diff --git a/core/misc/dialog/dialog.ajax.js b/core/misc/dialog/dialog.ajax.js index 7e439974df6..dca291e08e4 100644 --- a/core/misc/dialog/dialog.ajax.js +++ b/core/misc/dialog/dialog.ajax.js @@ -94,6 +94,7 @@ buttons.push({ text: $originalButton.html() || $originalButton.attr('value'), class: $originalButton.attr('class'), + 'data-once': $originalButton.data('once'), click(e) { // If the original button is an anchor tag, triggering the "click" // event will not simulate a click. Use the click method instead. @@ -104,8 +105,8 @@ .trigger('mousedown') .trigger('mouseup') .trigger('click'); - e.preventDefault(); } + e.preventDefault(); }, }); }); diff --git a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php index ec241187703..0a3aee61735 100644 --- a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php +++ b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php @@ -2,6 +2,8 @@ namespace Drupal\ajax_test\Form; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\MessageCommand; use Drupal\Core\Url; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; @@ -39,26 +41,44 @@ class AjaxTestForm extends FormBase { '#value' => $this->t('Do it'), ]; $form['actions']['preview'] = [ + '#title' => 'Preview', + '#type' => 'link', + '#url' => Url::fromRoute('ajax_test.dialog_form'), + '#attributes' => [ + 'class' => ['use-ajax', 'button'], + 'data-dialog-type' => 'modal', + ], + ]; + $form['actions']['hello_world'] = [ '#type' => 'submit', - '#value' => $this->t('Preview'), + '#value' => $this->t('Hello world'), // No regular submit-handler. This form only works via JavaScript. '#submit' => [], '#ajax' => [ - // This means the ::preview() method on this class would be invoked in - // case of a click event. However, since Drupal core's test runner only - // is able to execute PHP, not JS, there is no point in actually - // implementing this method, because we can never let it be called from - // JS; we'd have to manually call it from PHP, at which point we would - // not actually be testing it. - // Therefore we consciously choose to not implement this method, because - // we cannot meaningfully test it anyway. - 'callback' => '::preview', + 'callback' => '::helloWorld', 'event' => 'click', ], ]; return $form; } + /** + * An AJAX callback that prints "Hello World!" as a message. + * + * @param array $form + * The form array to remove elements from. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return \Drupal\Core\Ajax\AjaxResponse + * An AJAX response. + */ + public function helloWorld(array &$form, FormStateInterface $form_state) { + $response = new AjaxResponse(); + $response->addCommand(new MessageCommand('Hello world!')); + return $response; + } + /** * {@inheritdoc} */ diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php index 1a537175db5..42701e8fcd4 100644 --- a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php +++ b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/DialogTest.php @@ -145,26 +145,32 @@ class DialogTest extends WebDriverTestBase { $preview = $form_dialog->findButton('Preview'); $this->assertNotNull($preview, 'The dialog contains a "Preview" button.'); - // When a form with submit inputs is in a dialog, the form's submit inputs - // are copied to the dialog buttonpane as buttons. The originals should have - // their styles set to display: none. - $hidden_buttons = $this->getSession()->getPage()->findAll('css', '.ajax-test-form [type="submit"]'); - $this->assertCount(2, $hidden_buttons); + // Form submit inputs, link buttons, and buttons in dialog are copied to the + // dialog buttonpane as buttons. The originals should have their styles set + // to display: none. + $hidden_buttons = $this->getSession()->getPage()->findAll('css', '.ajax-test-form .button'); + $this->assertCount(3, $hidden_buttons); $hidden_button_text = []; foreach ($hidden_buttons as $button) { $styles = $button->getAttribute('style'); $this->assertStringContainsStringIgnoringCase('display: none;', $styles); - $hidden_button_text[] = $button->getAttribute('value'); + $hidden_button_text[] = $button->hasAttribute('value') ? $button->getAttribute('value') : $button->getHtml(); } // The copied buttons should have the same text as the submit inputs they // were copied from. $moved_to_buttonpane_buttons = $this->getSession()->getPage()->findAll('css', '.ui-dialog-buttonpane button'); - $this->assertCount(2, $moved_to_buttonpane_buttons); + $this->assertCount(3, $moved_to_buttonpane_buttons); foreach ($moved_to_buttonpane_buttons as $key => $button) { $this->assertEquals($hidden_button_text[$key], $button->getText()); } + // Press buttons in the dialog to ensure there are no AJAX errors. + $this->assertSession()->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Hello world'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->assertSession()->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Preview'); + $this->assertSession()->assertWaitOnAjaxRequest(); + // Reset: close the form. $form_dialog->findButton('Close')->press();