diff --git a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php index 412f572..946d752 100644 --- a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php +++ b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php @@ -496,14 +496,17 @@ public static function getSelected(FormStateInterface $form_state, $parents, $de } // If there is a user-submitted value for this element that matches one of - // the currently available options attached to it, use that. We need to check - // FormState::$input rather than $form_state->getValues() here because the - // triggering element often has the #limit_validation_errors property set to - // prevent unwanted errors elsewhere on the form. This means that the - // $form_state->getValues() array won't be complete. We could make it complete - // by adding each required part of the form to the #limit_validation_errors - // property individually as the form is being built, but this is difficult to - // do for a highly dynamic and extensible form. This method is much simpler. + // the currently available options attached to it, use that. However, only + // perform this check during the form rebuild. During the initial build + // after #ajax is triggered, we need to rebuild the form as it was + // initially. We need to check FormState::getUserInput() rather than + // $form_state->getValues() here because the triggering element often has + // the #limit_validation_errors property set to prevent unwanted errors + // elsewhere on the form. This means that the $form_state->getValues() array + // won't be complete. We could make it complete by adding each required part + // of the form to the #limit_validation_errors property individually as the + // form is being built, but this is difficult to do for a highly dynamic and + // extensible form. This method is much simpler. $user_input = $form_state->isRebuilding() ? $form_state->getUserInput() : []; if (!empty($user_input)) { $key_exists = NULL; diff --git a/core/modules/views/src/Tests/Wizard/TaggedWithTest.php b/core/modules/views/src/Tests/Wizard/TaggedWithTest.php index caf95be..b31e2b6 100644 --- a/core/modules/views/src/Tests/Wizard/TaggedWithTest.php +++ b/core/modules/views/src/Tests/Wizard/TaggedWithTest.php @@ -196,7 +196,7 @@ function testTaggedWithByNodeType() { $this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice')); $this->assertFieldByXpath($tags_xpath); $view['show[type]'] = $this->nodeTypeWithoutTags->id(); - $this->drupalPostForm(NULL, $view, t('Update "of type" choice')); + $this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)')); $this->assertNoFieldByXpath($tags_xpath); // If we add an instance of the tagging field to the second node type, the @@ -225,7 +225,7 @@ function testTaggedWithByNodeType() { $this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice')); $this->assertFieldByXpath($tags_xpath); $view['show[type]'] = $this->nodeTypeWithoutTags->id(); - $this->drupalPostForm(NULL, $view, t('Update "of type" choice')); + $this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)')); $this->assertFieldByXpath($tags_xpath); } diff --git a/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php b/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php new file mode 100644 index 0000000..1726531 --- /dev/null +++ b/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php @@ -0,0 +1,112 @@ +setUserInput($user_input); + + $actual = WizardPluginBase::getSelected($form_state, $parents, 'the_default_value', $element); + $this->assertSame($not_rebuilding_expected, $actual); + $this->assertSame($user_input, $form_state->getUserInput()); + + $form_state->setRebuild(); + $actual = WizardPluginBase::getSelected($form_state, $parents, 'the_default_value', $element); + $this->assertSame($expected, $actual); + $this->assertSame($user_input, $form_state->getUserInput()); + } + + /** + * Provides test data for testGetSelected(). + */ + public function providerTestGetSelected() { + $data = []; + // A form element with an invalid #type. + $data['invalid_type'] = [ + 'the_default_value', + [ + '#type' => 'checkbox', + ], + ]; + // A form element with no #options. + $data['no_options'] = [ + 'the_default_value', + [ + '#type' => 'select', + ], + ]; + // A valid form element with no user input. + $data['no_user_input'] = [ + 'the_default_value', + [ + '#type' => 'select', + '#options' => [ + 'option1' => 'Option 1', + ], + ], + ]; + // A valid form element with user input that doesn't correspond to it. + $data['mismatched_input'] = [ + 'the_default_value', + [ + '#type' => 'select', + '#options' => [ + 'option1' => 'Option 1', + ], + ], + ['foo', 'bar'], + ['foo' => ['foo' => 'value1']], + ]; + // A valid form element with a valid dynamic value that matches the default + // value. + $data['matching_default'] = [ + 'the_default_value', + [ + '#type' => 'select', + '#options' => [ + 'the_default_value' => 'Option 1', + ], + ], + ['foo', 'bar'], + ['foo' => ['bar' => 'the_default_value']], + ]; + // A valid form element with a valid dynamic value that does not match the + // default value. + $data['mismatched_value'] = [ + 'option1', + [ + '#type' => 'select', + '#options' => [ + 'option1' => 'Option 1', + ], + ], + ['foo', 'bar'], + ['foo' => ['bar' => 'option1']], + 'the_default_value', + ]; + return $data; + } + +} diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc index 30cc9c0..78be0fc 100644 --- a/core/modules/views_ui/admin.inc +++ b/core/modules/views_ui/admin.inc @@ -52,10 +52,6 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa $triggering_element = &$wrapping_element[$trigger_key]; $triggering_element['#ajax']['callback'] = 'views_ui_ajax_update_form'; - // Specify the #ajax URL in order to retain form caching. - // @todo Remove this in https://www.drupal.org/node/2500523. - //$triggering_element['#ajax']['url'] = Url::fromRoute('system.ajax'); - // We do not use \Drupal\Component\Utility\Html::getUniqueId() to get an ID // for the AJAX wrapper, because it remembers IDs across AJAX requests (and // won't reuse them), but in our case we need to use the same ID from request @@ -117,9 +113,6 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa 'wrapper' => $triggering_element['#ajax']['wrapper'], 'trigger_key' => $trigger_key, 'refresh_parents' => $refresh_parents, - // Keep track of duplicate wrappers so we don't add the same wrapper to the - // page more than once. - //'duplicate_wrapper' => !empty($seen_ids[$triggering_element['#ajax']['wrapper']]), ); $seen_ids[$triggering_element['#ajax']['wrapper']] = TRUE; $triggering_element['#views_ui_ajax_data'] = $ajax_data; @@ -166,9 +159,6 @@ function views_ui_add_limited_validation($element, FormStateInterface $form_stat * submit button form element. */ function views_ui_add_ajax_wrapper($element, FormStateInterface $form_state) { - // Don't add the wrapper
if the same one was already inserted on this - // form. - if (empty($element['#views_ui_ajax_data']['duplicate_wrapper'])) { // Find the region of the complete form that needs to be refreshed by AJAX. // This was earlier stored in a property on the element. $complete_form = &$form_state->getCompleteForm(); @@ -188,7 +178,6 @@ function views_ui_add_ajax_wrapper($element, FormStateInterface $form_state) { // Copy the element that needs to be refreshed back into the form, with our // modifications to it. NestedArray::setValue($complete_form, $refresh_parents, $refresh_element); - } return $element; }