summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcatch2014-12-11 23:17:22 (GMT)
committercatch2014-12-11 23:17:22 (GMT)
commit22ca1c9ca4145180073c5f7716143cdfb3c34f73 (patch)
tree5c20ed8426d8dc31d313a8c32aa5479808378d05
parentff20a6faf7e4e056257c42e38c2f180e9baaf669 (diff)
Issue #1985406 by jhedstrom, alexpott, Dave Reid, olli: #states not supported for elements in formatter settings being displayed on Views field handler form
-rw-r--r--core/lib/Drupal/Core/Form/FormHelper.php75
-rw-r--r--core/modules/field/src/Plugin/views/field/Field.php3
-rw-r--r--core/modules/views/src/Plugin/views/filter/FilterPluginBase.php52
-rw-r--r--core/tests/Drupal/Tests/Core/Form/FormHelperTest.php90
4 files changed, 190 insertions, 30 deletions
diff --git a/core/lib/Drupal/Core/Form/FormHelper.php b/core/lib/Drupal/Core/Form/FormHelper.php
new file mode 100644
index 0000000..2cb9974
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/FormHelper.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Form\FormHelper.
+ */
+
+namespace Drupal\Core\Form;
+
+use Drupal\Core\Render\Element;
+
+/**
+ * Provides helpers to operate on forms.
+ *
+ * @ingroup form_api
+ */
+class FormHelper {
+
+ /**
+ * Rewrite #states selectors.
+ *
+ * @param array $elements
+ * A renderable array element having a #states property.
+ * @param string $search
+ * A partial or entire jQuery selector string to replace in #states.
+ * @param string $replace
+ * The string to replace all instances of $search with.
+ *
+ * @see drupal_process_states()
+ */
+ public static function rewriteStatesSelector(array &$elements, $search, $replace) {
+ if (!empty($elements['#states'])) {
+ foreach ($elements['#states'] as $state => $ids) {
+ static::processStatesArray($elements['#states'][$state], $search, $replace);
+ }
+ }
+ foreach (Element::children($elements) as $key) {
+ static::rewriteStatesSelector($elements[$key], $search, $replace);
+ }
+ }
+
+ /**
+ * Helper function for self::rewriteStatesSelector().
+ *
+ * @param array $conditions
+ * States conditions array.
+ * @param string $search
+ * A partial or entire jQuery selector string to replace in #states.
+ * @param string $replace
+ * The string to replace all instances of $search with.
+ */
+ protected static function processStatesArray(array &$conditions, $search, $replace) {
+ // Retrieve the keys to make it easy to rename a key without changing the
+ // order of an array.
+ $keys = array_keys($conditions);
+ $update_keys = FALSE;
+ foreach ($conditions as $id => $values) {
+ if (strpos($id, $search) !== FALSE) {
+ $update_keys = TRUE;
+ $new_id = str_replace($search, $replace, $id);
+ // Replace the key and keep the array in the same order.
+ $index = array_search($id, $keys, TRUE);
+ $keys[$index] = $new_id;
+ }
+ elseif (is_array($values)) {
+ static::processStatesArray($conditions[$id], $search, $replace);
+ }
+ }
+ // Updates the states conditions keys if necessary.
+ if ($update_keys) {
+ $conditions = array_combine($keys, array_values($conditions));
+ }
+ }
+
+}
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index 95dd59e..6c7b9c5 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -15,6 +15,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FormatterPluginManager;
+use Drupal\Core\Form\FormHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
@@ -508,6 +509,8 @@ class Field extends FieldPluginBase implements CacheablePluginInterface {
$settings_form = array('#value' => array());
if ($formatter = $this->formatterPluginManager->getInstance($options)) {
$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;
}
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index 3366469..3af0e9c 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views\filter;
+use Drupal\Core\Form\FormHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\views\Plugin\CacheablePluginInterface;
@@ -979,39 +980,30 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
$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.
- $without_children = TRUE;
- foreach (Element::children($row['value']) as $children) {
- $has_state = FALSE;
- $states = array();
- foreach ($row['value'][$children]['#states']['visible'] as $key => $state) {
- if (isset($state[':input[name="options[operator]"]'])) {
- $has_state = TRUE;
- $states[$key] = $state[':input[name="options[operator]"]']['value'];
- }
- }
- if ($has_state) {
- foreach ($states as $key => $state) {
- $row['value'][$children]['#states']['visible'][] = array(
- ':input[name="options[group_info][group_items][' . $item_id . '][operator]"]' => array('value' => $state),
- );
- unset($row['value'][$children]['#states']['visible'][$key]);
- }
-
- $row['value'][$children]['#title'] = '';
-
- if (!empty($this->options['group_info']['group_items'][$item_id]['value'][$children])) {
- $row['value'][$children]['#default_value'] = $this->options['group_info']['group_items'][$item_id]['value'][$children];
+ // 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;
+ }
}
}
- $without_children = FALSE;
}
-
- if ($without_children) {
+ 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'];
}
diff --git a/core/tests/Drupal/Tests/Core/Form/FormHelperTest.php b/core/tests/Drupal/Tests/Core/Form/FormHelperTest.php
new file mode 100644
index 0000000..cf127cd
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Form/FormHelperTest.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Form\FormHelperTest.
+ */
+
+namespace Drupal\Tests\Core\Form;
+
+use Drupal\Core\Form\FormHelper;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Form\FormHelper
+ * @group Form
+ */
+class FormHelperTest extends UnitTestCase {
+
+ /**
+ * 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'),
+ ),
+ // Example from https://www.drupal.org/node/1464758
+ '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.');
+ }
+
+}