Issue #1998698 by larowlan, jibran, quicksketch: Allow Dialog Controller to work with form/entity form routes.
parent
aaa4e9dff3
commit
f7f7f37305
|
@ -77,5 +77,3 @@ class AjaxController extends ContainerAware {
|
|||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\Core\Controller;
|
|||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\OpenDialogCommand;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
|
@ -25,9 +26,10 @@ class DialogController {
|
|||
protected $httpKernel;
|
||||
|
||||
/**
|
||||
* Constructs a new HtmlPageController.
|
||||
* Constructs a new DialogController.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
|
||||
* The kernel.
|
||||
*/
|
||||
public function __construct(HttpKernelInterface $kernel) {
|
||||
$this->httpKernel = $kernel;
|
||||
|
@ -38,13 +40,11 @@ class DialogController {
|
|||
*
|
||||
* @param \Symfony\Component\HttpFoundation\RequestRequest $request
|
||||
* The request object.
|
||||
* @param callable $content
|
||||
* The body content callable that contains the body region of this page.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A response object.
|
||||
*/
|
||||
protected function forward(Request $request, $content) {
|
||||
protected function forward(Request $request) {
|
||||
// @todo When we have a Generator, we can replace the forward() call with
|
||||
// a render() call, which would handle ESI and hInclude as well. That will
|
||||
// require an _internal route. For examples, see:
|
||||
|
@ -54,12 +54,16 @@ class DialogController {
|
|||
// We need to clean up the derived information and such so that the
|
||||
// subrequest can be processed properly without leaking data through.
|
||||
$attributes->remove('system_path');
|
||||
$attributes->set('dialog', TRUE);
|
||||
|
||||
// Remove the accept header so the subrequest does not end up back in this
|
||||
// controller.
|
||||
$request->headers->remove('accept');
|
||||
// Remove the X-Requested-With header so the subrequest is not mistaken for
|
||||
// an ajax request.
|
||||
$request->headers->remove('x-requested-with');
|
||||
|
||||
return $this->httpKernel->forward($content, $attributes->all(), $request->query->all());
|
||||
return $this->httpKernel->forward(NULL, $attributes->all(), $request->query->all());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,14 +71,12 @@ class DialogController {
|
|||
*
|
||||
* @param \Symfony\Component\HttpFoundation\RequestRequest $request
|
||||
* The request object.
|
||||
* @param callable $_content
|
||||
* The body content callable that contains the body region of this page.
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
* AjaxResponse to return the content wrapper in a modal dialog.
|
||||
*/
|
||||
public function modal(Request $request, $_content) {
|
||||
return $this->dialog($request, $_content, TRUE);
|
||||
public function modal(Request $request) {
|
||||
return $this->dialog($request, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,16 +84,14 @@ class DialogController {
|
|||
*
|
||||
* @param \Symfony\Component\HttpFoundation\RequestRequest $request
|
||||
* The request object.
|
||||
* @param callable $_content
|
||||
* The body content callable that contains the body region of this page.
|
||||
* @param bool $modal
|
||||
* (optional) TRUE to render a modal dialog. Defaults to FALSE.
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
* AjaxResponse to return the content wrapper in a dialog.
|
||||
*/
|
||||
public function dialog(Request $request, $_content, $modal = FALSE) {
|
||||
$subrequest = $this->forward($request, $_content);
|
||||
public function dialog(Request $request, $modal = FALSE) {
|
||||
$subrequest = $this->forward($request);
|
||||
if ($subrequest->isOk()) {
|
||||
$content = $subrequest->getContent();
|
||||
// @todo Remove use of drupal_get_title() when
|
||||
|
@ -120,8 +120,9 @@ class DialogController {
|
|||
unset($options['target']);
|
||||
}
|
||||
else {
|
||||
// Generate a target based on the controller.
|
||||
$target = '#drupal-dialog-' . drupal_html_id(drupal_clean_css_identifier(drupal_strtolower($_content)));
|
||||
// Generate a target based on the route id.
|
||||
$route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
|
||||
$target = '#' . drupal_html_id("drupal-dialog-$route_name");
|
||||
}
|
||||
}
|
||||
$response->addCommand(new OpenDialogCommand($target, $title, $content, $options));
|
||||
|
|
|
@ -48,12 +48,21 @@ class ContentControllerEnhancer implements RouteEnhancerInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function enhance(array $defaults, Request $request) {
|
||||
if (empty($defaults['_controller']) && !empty($defaults['_content'])) {
|
||||
$type = $this->negotiation->getContentType($request);
|
||||
// If no controller is set and either _content is set or the request is
|
||||
// for a dialog or modal, then enhance.
|
||||
if (empty($defaults['_controller']) &&
|
||||
($type = $this->negotiation->getContentType($request)) &&
|
||||
(!empty($defaults['_content']) ||
|
||||
in_array($type, array('drupal_dialog', 'drupal_modal')))) {
|
||||
if (isset($this->types[$type])) {
|
||||
$defaults['_controller'] = $this->types[$type];
|
||||
}
|
||||
}
|
||||
// When the dialog attribute is TRUE this is a DialogController sub-request.
|
||||
// Route the sub-request to the _content callable.
|
||||
if ($request->attributes->get('dialog') && !empty($defaults['_content'])) {
|
||||
$defaults['_controller'] = $defaults['_content'];
|
||||
}
|
||||
return $defaults;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,20 @@
|
|||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\ajax_test\AjaxTestForm;
|
||||
|
||||
/**
|
||||
* Tests use of dialogs as wrappers for Ajax responses.
|
||||
*/
|
||||
class DialogTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('ajax_test', 'ajax_forms_test', 'contact');
|
||||
|
||||
/**
|
||||
* Declares test info.
|
||||
*/
|
||||
|
@ -27,6 +36,7 @@ class DialogTest extends AjaxTestBase {
|
|||
* Test sending non-JS and AJAX requests to open and manipulate modals.
|
||||
*/
|
||||
public function testDialog() {
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer contact forms')));
|
||||
// Ensure the elements render without notices or exceptions.
|
||||
$this->drupalGet('ajax-test/dialog');
|
||||
|
||||
|
@ -43,6 +53,24 @@ class DialogTest extends AjaxTestBase {
|
|||
'title' => 'AJAX Dialog contents',
|
||||
),
|
||||
);
|
||||
$form_expected_response = array(
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-modal',
|
||||
'settings' => NULL,
|
||||
'dialogOptions' => array(
|
||||
'modal' => TRUE,
|
||||
'title' => 'Ajax Form contents',
|
||||
),
|
||||
);
|
||||
$entity_form_expected_response = array(
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-modal',
|
||||
'settings' => NULL,
|
||||
'dialogOptions' => array(
|
||||
'modal' => TRUE,
|
||||
'title' => 'Home',
|
||||
),
|
||||
);
|
||||
$normal_expected_response = array(
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#ajax-test-dialog-wrapper-1',
|
||||
|
@ -53,6 +81,16 @@ class DialogTest extends AjaxTestBase {
|
|||
'title' => 'AJAX Dialog contents',
|
||||
),
|
||||
);
|
||||
$no_target_expected_response = array(
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-dialog-ajax-test-dialog-contents',
|
||||
'settings' => NULL,
|
||||
'data' => $dialog_contents,
|
||||
'dialogOptions' => array(
|
||||
'modal' => FALSE,
|
||||
'title' => 'AJAX Dialog contents',
|
||||
),
|
||||
);
|
||||
$close_expected_response = array(
|
||||
'command' => 'closeDialog',
|
||||
'selector' => '#ajax-test-dialog-wrapper-1',
|
||||
|
@ -83,6 +121,18 @@ class DialogTest extends AjaxTestBase {
|
|||
));
|
||||
$this->assertEqual($normal_expected_response, $ajax_result[3], 'Normal dialog JSON response matches.');
|
||||
|
||||
// Emulate going to the JS version of the page and check the JSON response.
|
||||
// This needs to use WebTestBase::drupalPostAJAX() so that the correct
|
||||
// dialog options are sent.
|
||||
$ajax_result = $this->drupalPostAJAX('ajax-test/dialog', array(
|
||||
// We have to mock a form element to make drupalPost submit from a link.
|
||||
'textfield' => 'test',
|
||||
), array(), 'ajax-test/dialog-contents', array(), array('Accept: application/vnd.drupal-dialog'), NULL, array(
|
||||
// Don't send a target.
|
||||
'submit' => array()
|
||||
));
|
||||
$this->assertEqual($no_target_expected_response, $ajax_result[3], 'Normal dialog with no target JSON response matches.');
|
||||
|
||||
// Emulate closing the dialog via an AJAX request. There is no non-JS
|
||||
// version of this test.
|
||||
$ajax_result = $this->drupalGetAJAX('ajax-test/dialog-close');
|
||||
|
@ -107,6 +157,38 @@ class DialogTest extends AjaxTestBase {
|
|||
// Abbreviated test for "normal" dialogs, testing only the difference.
|
||||
$ajax_result = $this->drupalPostAJAX('ajax-test/dialog', array(), 'button2');
|
||||
$this->assertEqual($normal_expected_response, $ajax_result[3], 'POST request normal dialog JSON response matches.');
|
||||
|
||||
// Check that requesting a form dialog without JS goes to a page.
|
||||
$this->drupalGet('ajax-test/dialog-form');
|
||||
// Check we get a chunk of the code, we can't test the whole form as form
|
||||
// build id and token with be different.
|
||||
$form = $this->xpath("//form[@id='ajax-test-form']");
|
||||
$this->assertTrue(!empty($form), 'Non-JS form page present.');
|
||||
|
||||
// Emulate going to the JS version of the form and check the JSON response.
|
||||
$ajax_result = $this->drupalGetAJAX('ajax-test/dialog-form', array(), array('Accept: application/vnd.drupal-modal'));
|
||||
$this->drupalSetContent($ajax_result[1]['data']);
|
||||
// Remove the data, the form build id and token will never match.
|
||||
unset($ajax_result[1]['data']);
|
||||
$form = $this->xpath("//form[@id='ajax-test-form']");
|
||||
$this->assertTrue(!empty($form), 'Modal dialog JSON contains form.');
|
||||
$this->assertEqual($form_expected_response, $ajax_result[1]);
|
||||
|
||||
// Check that requesting an entity form dialog without JS goes to a page.
|
||||
$this->drupalGet('admin/structure/contact/add');
|
||||
// Check we get a chunk of the code, we can't test the whole form as form
|
||||
// build id and token with be different.
|
||||
$form = $this->xpath("//form[@id='contact-category-add-form']");
|
||||
$this->assertTrue(!empty($form), 'Non-JS entity form page present.');
|
||||
|
||||
// Emulate going to the JS version of the form and check the JSON response.
|
||||
$ajax_result = $this->drupalGetAJAX('admin/structure/contact/add', array(), array('Accept: application/vnd.drupal-modal'));
|
||||
$this->drupalSetContent($ajax_result[1]['data']);
|
||||
// Remove the data, the form build id and token will never match.
|
||||
unset($ajax_result[1]['data']);
|
||||
$form = $this->xpath("//form[@id='contact-category-add-form']");
|
||||
$this->assertTrue(!empty($form), 'Modal dialog JSON contains entity form.');
|
||||
$this->assertEqual($entity_form_expected_response, $ajax_result[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,4 +4,6 @@ description: 'Support module for AJAX framework tests.'
|
|||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- contact
|
||||
hidden: true
|
||||
|
|
|
@ -160,6 +160,37 @@ function ajax_test_dialog() {
|
|||
'class' => array('use-ajax'),
|
||||
),
|
||||
),
|
||||
'link5' => array(
|
||||
'title' => 'Link 5 (form)',
|
||||
'href' => 'ajax-test/dialog-form',
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-accepts' => 'application/vnd.drupal-modal',
|
||||
),
|
||||
),
|
||||
'link6' => array(
|
||||
'title' => 'Link 6 (entity form)',
|
||||
'href' => 'admin/structure/contact/add',
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-accepts' => 'application/vnd.drupal-modal',
|
||||
'data-dialog-options' => json_encode(array(
|
||||
'width' => 800,
|
||||
'height' => 500,
|
||||
))
|
||||
),
|
||||
),
|
||||
'link7' => array(
|
||||
'title' => 'Link 7 (non-modal, no target)',
|
||||
'href' => 'ajax-test/dialog-contents',
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-accepts' => 'application/vnd.drupal-dialog',
|
||||
'data-dialog-options' => json_encode(array(
|
||||
'width' => 800,
|
||||
))
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return $build;
|
||||
|
|
|
@ -4,3 +4,9 @@ ajax_test_dialog_contents:
|
|||
_content: '\Drupal\ajax_test\AjaxTestController::dialogContents'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
ajax_test_dialog_form:
|
||||
pattern: ajax-test/dialog-form
|
||||
defaults:
|
||||
_form: '\Drupal\ajax_test\AjaxTestForm'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\ajax_test\AjaxTestForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\ajax_test;
|
||||
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
|
||||
/**
|
||||
* Dummy form for testing DialogController with _form routes.
|
||||
*/
|
||||
class AjaxTestForm implements FormInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormID() {
|
||||
return 'ajax_test_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, array &$form_state) {
|
||||
|
||||
drupal_set_title(t('Ajax Form contents'));
|
||||
|
||||
$form['#action'] = url('ajax-test/dialog');
|
||||
$form['#cache'] = TRUE;
|
||||
|
||||
$form['description'] = array(
|
||||
'#markup' => '<p>' . t("Ajax Form contents description.") . '</p>',
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Do it'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, array &$form_state) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, array &$form_state) {}
|
||||
|
||||
}
|
Loading…
Reference in New Issue