diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc index 31c099e..82470d1 100644 --- a/core/includes/ajax.inc +++ b/core/includes/ajax.inc @@ -519,6 +519,7 @@ function ajax_process_form($element, &$form_state) { * - #ajax['wrapper'] * - #ajax['parameters'] * - #ajax['effect'] + * - #ajax['accepts'] * * @return * The processed element with the necessary JavaScript attached to it. @@ -605,6 +606,7 @@ function ajax_pre_render_element($element) { $settings += array( 'path' => isset($settings['callback']) ? 'system/ajax' : NULL, 'options' => array(), + 'accepts' => 'application/vnd.drupal-ajax' ); // @todo Legacy support. Remove in Drupal 8. diff --git a/core/lib/Drupal/Core/Ajax/AjaxSubscriber.php b/core/lib/Drupal/Core/Ajax/AjaxSubscriber.php index 5ef67c0..414511f 100644 --- a/core/lib/Drupal/Core/Ajax/AjaxSubscriber.php +++ b/core/lib/Drupal/Core/Ajax/AjaxSubscriber.php @@ -27,6 +27,8 @@ public function onKernelRequest(GetResponseEvent $event) { // @todo Refactor 'drupal_ajax' to just 'ajax' once all Ajax is converted to // Drupal 8's API. $request->setFormat('drupal_ajax', 'application/vnd.drupal-ajax'); + $request->setFormat('drupal_dialog', 'application/vnd.drupal-dialog'); + $request->setFormat('drupal_modal', 'application/vnd.drupal-modal'); } /** @@ -40,4 +42,4 @@ static function getSubscribedEvents(){ return $events; } -} \ No newline at end of file +} diff --git a/core/lib/Drupal/Core/Ajax/DialogController.php b/core/lib/Drupal/Core/Ajax/DialogController.php new file mode 100644 index 0000000..bf41001 --- /dev/null +++ b/core/lib/Drupal/Core/Ajax/DialogController.php @@ -0,0 +1,107 @@ +attributes; + // 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->remove('_legacy'); + + // Remove the accept header so the subrequest does not end up back in this + // controller. + $request->headers->remove('accept'); + + return $this->container->get('http_kernel')->forward($content, $attributes->all(), $request->query->all()); + } + + /** + * Wrapper to display content in a modal dialog. + * + * @param Request $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); + } + + /** + * Wrapper to display content in a dialog. + * + * @param Request $request + * The request object. + * @param callable $_content + * The body content callable that contains the body region of this page. + * @parm 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); + if ($subrequest->isOk()) { + $output = $subrequest->getContent(); + // A page callback could return a render array or a string. + if (is_array($output)) { + // Subrequest has set dialog title in the output. + if (isset($output['title'])) { + $title = $output['title']['#value']; + unset($output['title']); + } + $content = drupal_render($output); + } + else { + // Legacy fallback. + $title = drupal_get_title(); + $content = $output; + } + $response = new AjaxResponse(); + $options = array('width' => '700'); + if ($modal) { + $options['modal'] = TRUE; + } + $response->addCommand(new OpenDialogCommand('#drupal-modal', $title, $content, $options)); + return $response; + } + // An error occurred in the subrequest, return that. + return $subrequest; + } +} diff --git a/core/lib/Drupal/Core/ContentNegotiation.php b/core/lib/Drupal/Core/ContentNegotiation.php index a2c17b5..d2ffa45 100644 --- a/core/lib/Drupal/Core/ContentNegotiation.php +++ b/core/lib/Drupal/Core/ContentNegotiation.php @@ -26,7 +26,7 @@ class ContentNegotiation { * @param Symfony\Component\HttpFoundation\Request $request * The request object from which to extract the content type. * - * @return + * @return string * The normalized type of a given request. */ public function getContentType(Request $request) { @@ -36,11 +36,12 @@ public function getContentType(Request $request) { return 'iframeupload'; } - // Check all formats, it HTML is found return it. + // Check all formats, if priority format is found return it. $first_found_format = FALSE; foreach ($request->getAcceptableContentTypes() as $mime_type) { $format = $request->getFormat($mime_type); - if ($format === 'html' || $format === 'drupal_ajax') { + $priority = array('html', 'drupal_ajax', 'drupal_modal', 'drupal_dialog'); + if (in_array($format, $priority, TRUE)) { return $format; } if (!is_null($format) && !$first_found_format) { diff --git a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php index 7b1e34a..07e1a18 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php @@ -43,6 +43,24 @@ public function onRequestSetController(GetResponseEvent $event) { $request->attributes->set('_content', $request->attributes->get('_controller')); $request->attributes->set('_controller', '\Drupal\Core\AjaxController::content'); } + // @todo Move this to a RouteEnhancer when http://drupal.org/node/1938980 + // lands. + elseif ($this->negotiation->getContentType($request) == 'drupal_dialog') { + if (!$request->attributes->has('_content') && $request->attributes->has('_controller')) { + // Pass the controller on as content. + $request->attributes->set('_content', $request->attributes->get('_controller')); + } + $request->attributes->set('_controller', '\Drupal\Core\Ajax\DialogController::dialog'); + } + // @todo Move this to a RouteEnhancer when http://drupal.org/node/1938980 + // lands. + elseif ($this->negotiation->getContentType($request) == 'drupal_modal') { + if (!$request->attributes->has('_content') && $request->attributes->has('_controller')) { + // Pass the controller on as content. + $request->attributes->set('_content', $request->attributes->get('_controller')); + } + $request->attributes->set('_controller', '\Drupal\Core\Ajax\DialogController::modal'); + } elseif (!$request->attributes->has('_controller') && $this->negotiation->getContentType($request) === 'html') { if ($request->attributes->has('_form')) { $request->attributes->set('_controller', '\Drupal\Core\HtmlFormController::content'); diff --git a/core/misc/ajax.js b/core/misc/ajax.js index 1b5d0ca..deb1de5 100644 --- a/core/misc/ajax.js +++ b/core/misc/ajax.js @@ -52,6 +52,9 @@ Drupal.behaviors.AJAX = { element_settings.url = $(this).attr('href'); element_settings.event = 'click'; } + if ($(this).data('accepts')) { + element_settings.accepts = $(this).data('accepts'); + } var base = $(this).attr('id'); Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); }); @@ -200,7 +203,7 @@ Drupal.ajax = function (base, element, element_settings) { }, dataType: 'json', accepts: { - json: 'application/vnd.drupal-ajax' + json: element_settings.accepts || 'application/vnd.drupal-ajax' }, type: 'POST' }; diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc index e81c582..2c34832 100644 --- a/core/modules/config/config.admin.inc +++ b/core/modules/config/config.admin.inc @@ -77,6 +77,7 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa 'href' => 'admin/config/development/sync/diff/' . $config_file, 'attributes' => array( 'class' => array('use-ajax'), + 'data-accepts' => 'application/vnd.drupal-modal' ), ); $form[$config_change_type]['list']['#rows'][] = array( @@ -139,68 +140,3 @@ function config_admin_import_form_submit($form, &$form_state) { } } -/** - * Page callback: Shows diff of specificed configuration file. - * - * @param string $config_file - * The name of the configuration file. - * - * @return string - * Table showing a two-way diff between the active and staged configuration. - */ -function config_admin_diff_page($config_file) { - // Retrieve a list of differences between last known state and active store. - $source_storage = drupal_container()->get('config.storage.staging'); - $target_storage = drupal_container()->get('config.storage'); - - // Add the CSS for the inline diff. - $output['#attached']['css'][] = drupal_get_path('module', 'system') . '/system.diff.css'; - - $diff = config_diff($target_storage, $source_storage, $config_file); - $formatter = new DrupalDiffFormatter(); - $formatter->show_header = FALSE; - - $variables = array( - 'header' => array( - array('data' => t('Old'), 'colspan' => '2'), - array('data' => t('New'), 'colspan' => '2'), - ), - 'rows' => $formatter->format($diff), - ); - - $output['diff'] = array( - '#markup' => theme('table', $variables), - ); - - $output['back'] = array( - '#type' => 'link', - '#title' => "Back to 'Synchronize configuration' page.", - '#href' => 'admin/config/development/sync', - ); - - $title = t('View changes of @config_file', array('@config_file' => $config_file)); - - // Return AJAX requests as a dialog. - // @todo: Set up separate content callbacks for the non-JS and dialog versions - // of this page using the router system. See http://drupal.org/node/1944472. - if (Drupal::service('request')->isXmlHttpRequest()) { - // Add class to the close link. - $output['back']['#attributes']['class'][] = 'dialog-cancel'; - - $dialog_content = drupal_render($output); - $response = new AjaxResponse(); - $response->addCommand(new OpenModalDialogCommand($title, $dialog_content, array('width' => '700'))); - return $response; - } - // Otherwise show the page title as an element. - else { - $output['title'] = array( - '#theme' => 'html_tag', - '#tag' => 'h3', - '#value' => $title, - '#weight' => -10, - ); - } - - return $output; -} diff --git a/core/modules/config/config.module b/core/modules/config/config.module index e3b6027..651e387 100644 --- a/core/modules/config/config.module +++ b/core/modules/config/config.module @@ -48,18 +48,9 @@ function config_menu() { 'access arguments' => array('synchronize configuration'), 'file' => 'config.admin.inc', ); - $items['admin/config/development/sync/diff/%'] = array( - 'title' => 'Configuration file diff', - 'description' => 'Diff between active and staged configuraiton.', - 'page callback' => 'config_admin_diff_page', - 'page arguments' => array(5), - 'access arguments' => array('synchronize configuration'), - 'file' => 'config.admin.inc', - ); $items['admin/config/development/sync/import'] = array( 'title' => 'Import', 'type' => MENU_DEFAULT_LOCAL_TASK, ); return $items; } - diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml new file mode 100644 index 0000000..505539d --- /dev/null +++ b/core/modules/config/config.routing.yml @@ -0,0 +1,6 @@ +config_diff: + pattern: '/admin/config/development/sync/diff/{config_file}' + defaults: + _content: '\Drupal\config\Controller\ConfigController::diff' + requirements: + _permission: 'synchronize configuration' diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php new file mode 100644 index 0000000..42bbdb6 --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php @@ -0,0 +1,97 @@ +get('config.storage'), $container->get('config.storage.staging')); + } + + /** + * Constructor. + * + * @param \Drupal\Core\Config\StorageInterface $target_storage + * The target storage. + * @param \Drupal\Core\Config\StorageInterface $source_storage + * The source storage + */ + public function __construct(StorageInterface $target_storage, StorageInterface $source_storage) { + $this->targetStorage = $target_storage; + $this->sourceStorage = $source_storage; + } + + /** + * Shows diff of specificed configuration file. + * + * @param string $config_file + * The name of the configuration file. + * + * @return string + * Table showing a two-way diff between the active and staged configuration. + */ + public function diff($config_file) { + // Add the CSS for the inline diff. + $output['#attached']['css'][] = drupal_get_path('module', 'system') . '/system.diff.css'; + + $diff = config_diff($this->targetStorage, $this->sourceStorage, $config_file); + $formatter = new \DrupalDiffFormatter(); + $formatter->show_header = FALSE; + + $variables = array( + 'header' => array( + array('data' => t('Old'), 'colspan' => '2'), + array('data' => t('New'), 'colspan' => '2'), + ), + 'rows' => $formatter->format($diff), + ); + + $output['diff'] = array( + '#markup' => theme('table', $variables), + ); + + $output['back'] = array( + '#type' => 'link', + '#title' => "Back to 'Synchronize configuration' page.", + '#href' => 'admin/config/development/sync', + ); + + $title = t('View changes of @config_file', array('@config_file' => $config_file)); + $output['title'] = array( + '#theme' => 'html_tag', + '#tag' => 'h3', + '#value' => $title, + '#weight' => -10, + ); + + return $output; + } +}