/** * Tests rewriting the #states selectors. * * @covers ::rewriteStatesSelector */ function testRewriteStatesSelector() { // Simple selectors. $value = array('value' => 'medium'); $form['foo']['#states'] = array('visible' => array('select[name="fields[foo-id][settings_edit_form][settings][image_style]"]' => $value)); FormHelper::rewriteStatesSelector($form, 'fields[foo-id][settings_edit_form]', 'options'); $expected_selector = 'select[name="options[settings][image_style]"]'; $this->assertSame($form['foo']['#states']['visible'][$expected_selector], $value, 'The #states selector was not properly rewritten.'); // Complex selectors. $form = array(); $form['bar']['#states'] = array('visible' => array(array(':input[name="menu[type]"]' => array('value' => 'normal')), array(':input[name="menu[type]"]' => array('value' => 'tab')), ':input[name="menu[type]"]' => array('value' => 'default tab')), 'disabled' => array('[name="menu[options][dependee_1]"]' => array('value' => 'ON'), array(array('[name="menu[options][dependee_2]"]' => array('value' => 'ON')), array('[name="menu[options][dependee_3]"]' => array('value' => 'ON'))), array(array('[name="menu[options][dependee_4]"]' => array('value' => 'ON')), 'xor', array('[name="menu[options][dependee_5]"]' => array('value' => 'ON'))))); $expected['bar']['#states'] = array('visible' => array(array(':input[name="options[type]"]' => array('value' => 'normal')), array(':input[name="options[type]"]' => array('value' => 'tab')), ':input[name="options[type]"]' => array('value' => 'default tab')), 'disabled' => array('[name="options[options][dependee_1]"]' => array('value' => 'ON'), array(array('[name="options[options][dependee_2]"]' => array('value' => 'ON')), array('[name="options[options][dependee_3]"]' => array('value' => 'ON'))), array(array('[name="options[options][dependee_4]"]' => array('value' => 'ON')), 'xor', array('[name="options[options][dependee_5]"]' => array('value' => 'ON'))))); FormHelper::rewriteStatesSelector($form, 'menu', 'options'); $this->assertSame($expected, $form, 'The #states selectors were properly rewritten.'); }
/** * Build the form to let users create the group of exposed filters. * This form is displayed when users click on button 'Build group' */ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form_state) { if (empty($this->options['exposed']) || empty($this->options['is_grouped'])) { return; } $form['#theme'] = 'views_ui_build_group_filter_form'; // #flatten will move everything from $form['group_info'][$key] to $form[$key] // prior to rendering. That's why the preRender for it needs to run first, // so that when the next preRender (the one for fieldsets) runs, it gets // the flattened data. array_unshift($form['#pre_render'], array(get_class($this), 'preRenderFlattenData')); $form['group_info']['#flatten'] = TRUE; if (!empty($this->options['group_info']['identifier'])) { $identifier = $this->options['group_info']['identifier']; } else { $identifier = 'group_' . $this->options['expose']['identifier']; } $form['group_info']['identifier'] = array('#type' => 'textfield', '#default_value' => $identifier, '#title' => $this->t('Filter identifier'), '#size' => 40, '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank.')); $form['group_info']['label'] = array('#type' => 'textfield', '#default_value' => $this->options['group_info']['label'], '#title' => $this->t('Label'), '#size' => 40); $form['group_info']['description'] = array('#type' => 'textfield', '#default_value' => $this->options['group_info']['description'], '#title' => $this->t('Description'), '#size' => 60); $form['group_info']['optional'] = array('#type' => 'checkbox', '#title' => $this->t('Optional'), '#description' => $this->t('This exposed filter is optional and will have added options to allow it not to be set.'), '#default_value' => $this->options['group_info']['optional']); $form['group_info']['multiple'] = array('#type' => 'checkbox', '#title' => $this->t('Allow multiple selections'), '#description' => $this->t('Enable to allow users to select multiple items.'), '#default_value' => $this->options['group_info']['multiple']); $form['group_info']['widget'] = array('#type' => 'radios', '#default_value' => $this->options['group_info']['widget'], '#title' => $this->t('Widget type'), '#options' => array('radios' => $this->t('Radios'), 'select' => $this->t('Select')), '#description' => $this->t('Select which kind of widget will be used to render the group of filters')); $form['group_info']['remember'] = array('#type' => 'checkbox', '#title' => $this->t('Remember'), '#description' => $this->t('Remember the last setting the user gave this filter.'), '#default_value' => $this->options['group_info']['remember']); if (!empty($this->options['group_info']['identifier'])) { $identifier = $this->options['group_info']['identifier']; } else { $identifier = 'group_' . $this->options['expose']['identifier']; } $form['group_info']['identifier'] = array('#type' => 'textfield', '#default_value' => $identifier, '#title' => $this->t('Filter identifier'), '#size' => 40, '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank.')); $form['group_info']['label'] = array('#type' => 'textfield', '#default_value' => $this->options['group_info']['label'], '#title' => $this->t('Label'), '#size' => 40); $form['group_info']['optional'] = array('#type' => 'checkbox', '#title' => $this->t('Optional'), '#description' => $this->t('This exposed filter is optional and will have added options to allow it not to be set.'), '#default_value' => $this->options['group_info']['optional']); $form['group_info']['widget'] = array('#type' => 'radios', '#default_value' => $this->options['group_info']['widget'], '#title' => $this->t('Widget type'), '#options' => array('radios' => $this->t('Radios'), 'select' => $this->t('Select')), '#description' => $this->t('Select which kind of widget will be used to render the group of filters')); $form['group_info']['remember'] = array('#type' => 'checkbox', '#title' => $this->t('Remember'), '#description' => $this->t('Remember the last setting the user gave this filter.'), '#default_value' => $this->options['group_info']['remember']); $groups = array('All' => $this->t('- Any -')); // The string '- Any -' will not be rendered see @theme_views_ui_build_group_filter_form // Provide 3 options to start when we are in a new group. if (count($this->options['group_info']['group_items']) == 0) { $this->options['group_info']['group_items'] = array_fill(1, 3, array()); } // After the general settings, comes a table with all the existent groups. $default_weight = 0; foreach ($this->options['group_info']['group_items'] as $item_id => $item) { if (!$form_state->isValueEmpty(array('options', 'group_info', 'group_items', $item_id, 'remove'))) { continue; } // Each rows contains three widgets: // a) The title, where users define how they identify a pair of operator | value // b) The operator // c) The value (or values) to use in the filter with the selected operator // In each row, we have to display the operator form and the value from // $row acts as a fake form to render each widget in a row. $row = array(); $groups[$item_id] = $this->t('Grouping @id', array('@id' => $item_id)); $this->operatorForm($row, $form_state); // Force the operator form to be a select box. Some handlers uses // radios and they occupy a lot of space in a table row. $row['operator']['#type'] = 'select'; $row['operator']['#title'] = ''; $this->valueForm($row, $form_state); // Fix the dependencies to update value forms when operators changes. This // is needed because forms are inside a new form and their IDs changes. // Dependencies are used when operator changes from to 'Between', // 'Not Between', etc, and two or more widgets are displayed. FormHelper::rewriteStatesSelector($row['value'], ':input[name="options[operator]"]', ':input[name="options[group_info][group_items][' . $item_id . '][operator]"]'); // Set default values. $children = Element::children($row['value']); if (!empty($children)) { foreach ($children as $child) { foreach ($row['value'][$child]['#states']['visible'] as $state) { if (isset($state[':input[name="options[group_info][group_items][' . $item_id . '][operator]"]'])) { $row['value'][$child]['#title'] = ''; if (!empty($this->options['group_info']['group_items'][$item_id]['value'][$child])) { $row['value'][$child]['#default_value'] = $this->options['group_info']['group_items'][$item_id]['value'][$child]; } // Exit this loop and process the next child element. break; } } } } else { if (isset($this->options['group_info']['group_items'][$item_id]['value']) && $this->options['group_info']['group_items'][$item_id]['value'] != '') { $row['value']['#default_value'] = $this->options['group_info']['group_items'][$item_id]['value']; } } if (!empty($this->options['group_info']['group_items'][$item_id]['operator'])) { $row['operator']['#default_value'] = $this->options['group_info']['group_items'][$item_id]['operator']; } $default_title = ''; if (!empty($this->options['group_info']['group_items'][$item_id]['title'])) { $default_title = $this->options['group_info']['group_items'][$item_id]['title']; } // Per item group, we have a title that identifies it. $form['group_info']['group_items'][$item_id] = array('title' => array('#title' => $this->t('Label'), '#title_display' => 'invisible', '#type' => 'textfield', '#size' => 20, '#default_value' => $default_title), 'operator' => $row['operator'], 'value' => $row['value'], 'remove' => array('#type' => 'checkbox', '#id' => 'views-removed-' . $item_id, '#attributes' => array('class' => array('views-remove-checkbox')), '#default_value' => 0), 'weight' => array('#title' => $this->t('Weight'), '#title_display' => 'invisible', '#type' => 'weight', '#delta' => 10, '#default_value' => $default_weight++, '#attributes' => array('class' => array('weight')))); } // From all groups, let chose which is the default. $form['group_info']['default_group'] = array('#type' => 'radios', '#options' => $groups, '#default_value' => $this->options['group_info']['default_group'], '#required' => TRUE, '#attributes' => array('class' => array('default-radios'))); // From all groups, let chose which is the default. $form['group_info']['default_group_multiple'] = array('#type' => 'checkboxes', '#options' => $groups, '#default_value' => $this->options['group_info']['default_group_multiple'], '#attributes' => array('class' => array('default-checkboxes'))); $form['group_info']['add_group'] = array('#prefix' => '<div class="views-build-group clear-block">', '#suffix' => '</div>', '#type' => 'submit', '#value' => $this->t('Add another item'), '#submit' => array(array($this, 'addGroupForm')), '#attributes' => array('class' => array('use-ajax-submit'))); $js = array(); $js['tableDrag']['views-filter-groups']['weight'][0] = array('target' => 'weight', 'source' => NULL, 'relationship' => 'sibling', 'action' => 'order', 'hidden' => TRUE, 'limit' => 0); $js_settings = $form_state->get('js_settings'); if ($js_settings && is_array($js)) { $js_settings = array_merge($js_settings, $js); } else { $js_settings = $js; } $form_state->set('js_settings', $js_settings); }
/** * {@inheritdoc} */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { parent::buildOptionsForm($form, $form_state); $field = $this->getFieldDefinition(); $formatters = $this->formatterPluginManager->getOptions($field->getType()); $column_names = array_keys($field->getColumns()); // If this is a multiple value field, add its options. if ($this->multiple) { $this->multiple_options_form($form, $form_state); } // No need to ask the user anything if the field has only one column. if (count($field->getColumns()) == 1) { $form['click_sort_column'] = array('#type' => 'value', '#value' => isset($column_names[0]) ? $column_names[0] : ''); } else { $form['click_sort_column'] = array('#type' => 'select', '#title' => $this->t('Column used for click sorting'), '#options' => array_combine($column_names, $column_names), '#default_value' => $this->options['click_sort_column'], '#description' => $this->t('Used by Style: Table to determine the actual column to click sort the field on. The default is usually fine.')); } $form['type'] = array('#type' => 'select', '#title' => $this->t('Formatter'), '#options' => $formatters, '#default_value' => $this->options['type'], '#ajax' => array('url' => views_ui_build_form_url($form_state)), '#submit' => array(array($this, 'submitTemporaryForm')), '#executes_submit_callback' => TRUE); $form['field_api_classes'] = array('#title' => $this->t('Use field template'), '#type' => 'checkbox', '#default_value' => $this->options['field_api_classes'], '#description' => $this->t('If checked, field api classes will be added by field templates. This is not recommended unless your CSS depends upon these classes. If not checked, template will not be used.'), '#fieldset' => 'style_settings', '#weight' => 20); if ($this->multiple) { $form['field_api_classes']['#description'] .= ' ' . $this->t('Checking this option will cause the group Display Type and Separator values to be ignored.'); } // Get the settings form. $settings_form = array('#value' => array()); $format = isset($form_state->getUserInput()['options']['type']) ? $form_state->getUserInput()['options']['type'] : $this->options['type']; if ($formatter = $this->getFormatterInstance($format)) { $settings_form = $formatter->settingsForm($form, $form_state); // Convert field UI selector states to work in the Views field form. FormHelper::rewriteStatesSelector($settings_form, "fields[{$field->getName()}][settings_edit_form]", 'options'); } $form['settings'] = $settings_form; }
/** * {@inheritdoc} */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $form['field_rendering'] = array('#type' => 'checkbox', '#title' => $this->t('Use entity field rendering'), '#description' => $this->t("If checked, Drupal's built-in field rendering mechanism will be used for rendering this field's values, which requires the entity to be loaded. If unchecked, a type-specific, entity-independent rendering mechanism will be used."), '#default_value' => $this->options['field_rendering']); // Wrap the (immediate) parent options in their own field set, to clean up // the UI when (un)checking the above checkbox. $form['parent_options'] = array('#type' => 'fieldset', '#title' => $this->t('Render settings'), '#states' => array('visible' => array(':input[name="options[field_rendering]"]' => array('checked' => TRUE)))); // Include the parent options form and move all fields that were added by // our direct parent (\Drupal\views\Plugin\views\field\Field) to the // "parent_options" fieldset. parent::buildOptionsForm($form, $form_state); $parent_keys = array('multiple_field_settings', 'click_sort_column', 'type', 'field_api_classes', 'settings'); foreach ($parent_keys as $key) { if (!empty($form[$key])) { $form[$key]['#fieldset'] = 'parent_options'; } } // The Core boolean formatter hard-codes the field name to "field_boolean". // This breaks the parent class's call of rewriteStatesSelector() for fixing // "#states". We therefore apply that behavior again here. if (!empty($form['settings'])) { FormHelper::rewriteStatesSelector($form['settings'], "fields[field_boolean][settings_edit_form]", 'options'); } // Get the options form for the fallback handler. $fallback_form = array(); $this->fallbackHandler->buildOptionsForm($fallback_form, $form_state); // Remove all fields from FieldPluginBase from the fallback form, but leave // those in that were only added by our immediate parent, // \Drupal\views\Plugin\views\field\Field. (E.g., the "type" option is // especially prone to conflicts here.) The others come from the plugin base // classes and will be identical, so it would be confusing to include them // twice. $parent_keys[] = '#pre_render'; $remove_from_fallback = array_diff_key($form, array_flip($parent_keys)); $fallback_form = array_diff_key($fallback_form, $remove_from_fallback); // Fix the "#states" selectors in the fallback form, and put an additional // "#states" directive on it to only be visible for the corresponding // "field_rendering" setting. if ($fallback_form) { FormHelper::rewriteStatesSelector($fallback_form, '"options[', '"options[fallback_options]['); $form['fallback_options'] = $fallback_form; $form['fallback_options']['#type'] = 'fieldset'; $form['fallback_options']['#title'] = $this->t('Render settings'); $form['fallback_options']['#states']['visible'][':input[name="options[field_rendering]"]'] = array('checked' => FALSE); } }