From 0c810aa1a094238a3d09cf099d4a4e37405fd703 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Wed, 29 Jul 2015 09:12:30 +0100 Subject: [PATCH] Issue #2535118 by longwave, Wim Leers, borisson_, effulgentsia: Toolbar subtrees not working on admin pages due to lack of theme negotiation on Toolbar's custom JSONP route --- core/modules/toolbar/js/toolbar.js | 14 +++++- .../toolbar/js/views/ToolbarVisualView.js | 18 ++++---- .../toolbar/src/Ajax/SetSubtreesCommand.php | 44 +++++++++++++++++++ .../src/Controller/ToolbarController.php | 13 +++--- .../src/Tests/ToolbarAdminMenuTest.php | 11 ++--- core/modules/toolbar/toolbar.libraries.yml | 1 + core/modules/toolbar/toolbar.routing.yml | 5 ++- 7 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 core/modules/toolbar/src/Ajax/SetSubtreesCommand.php diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index cd44b7f2024d..ed4068c101ff 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -79,7 +79,8 @@ // asynchronously. Drupal.toolbar.setSubtrees.done(function (subtrees) { menuModel.set('subtrees', subtrees); - localStorage.setItem('Drupal.toolbar.subtrees', JSON.stringify(subtrees)); + var theme = drupalSettings.ajaxPageState.theme; + localStorage.setItem('Drupal.toolbar.subtrees.' + theme, JSON.stringify(subtrees)); // Indicate on the toolbarModel that subtrees are now loaded. model.set('areSubtreesLoaded', true); }); @@ -233,4 +234,15 @@ ''; }; + /** + * Ajax command to set the toolbar subtrees. + * + * @param {Drupal.Ajax} ajax + * @param {object} response + * @param {number} [status] + */ + Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (ajax, response, status) { + Drupal.toolbar.setSubtrees.resolve(response.subtrees); + }; + }(jQuery, Drupal, drupalSettings)); diff --git a/core/modules/toolbar/js/views/ToolbarVisualView.js b/core/modules/toolbar/js/views/ToolbarVisualView.js index 872aa98575db..456e602787bf 100644 --- a/core/modules/toolbar/js/views/ToolbarVisualView.js +++ b/core/modules/toolbar/js/views/ToolbarVisualView.js @@ -249,7 +249,8 @@ }, /** - * Calls the endpoint URI that will return rendered subtrees with JSONP. + * Calls the endpoint URI that builds an AJAX command with the rendered + * subtrees. * * The rendered admin menu subtrees HTML is cached on the client in * localStorage until the cache of the admin menu subtrees on the server- @@ -267,9 +268,10 @@ // (3) The orientation of the tray is vertical. if (!this.model.get('areSubtreesLoaded') && typeof $activeTab.data('drupal-subtrees') !== 'undefined' && orientation === 'vertical') { var subtreesHash = drupalSettings.toolbar.subtreesHash; + var theme = drupalSettings.ajaxPageState.theme; var endpoint = Drupal.url('toolbar/subtrees/' + subtreesHash); - var cachedSubtreesHash = localStorage.getItem('Drupal.toolbar.subtreesHash'); - var cachedSubtrees = JSON.parse(localStorage.getItem('Drupal.toolbar.subtrees')); + var cachedSubtreesHash = localStorage.getItem('Drupal.toolbar.subtreesHash.' + theme); + var cachedSubtrees = JSON.parse(localStorage.getItem('Drupal.toolbar.subtrees.' + theme)); var isVertical = this.model.get('orientation') === 'vertical'; // If we have the subtrees in localStorage and the subtree hash has not // changed, then use the cached data. @@ -280,13 +282,13 @@ // toolbar is vertical. else if (isVertical) { // Remove the cached menu information. - localStorage.removeItem('Drupal.toolbar.subtreesHash'); - localStorage.removeItem('Drupal.toolbar.subtrees'); - // The response from the server will call the resolve method of the + localStorage.removeItem('Drupal.toolbar.subtreesHash.' + theme); + localStorage.removeItem('Drupal.toolbar.subtrees.' + theme); + // The AJAX response's command will trigger the resolve method of the // Drupal.toolbar.setSubtrees Promise. - $.ajax(endpoint); + Drupal.ajax({url: endpoint}).execute(); // Cache the hash for the subtrees locally. - localStorage.setItem('Drupal.toolbar.subtreesHash', subtreesHash); + localStorage.setItem('Drupal.toolbar.subtreesHash.' + theme, subtreesHash); } } } diff --git a/core/modules/toolbar/src/Ajax/SetSubtreesCommand.php b/core/modules/toolbar/src/Ajax/SetSubtreesCommand.php new file mode 100644 index 000000000000..d9015d81cf07 --- /dev/null +++ b/core/modules/toolbar/src/Ajax/SetSubtreesCommand.php @@ -0,0 +1,44 @@ +subtrees = $subtrees; + } + + /** + * {@inheritdoc} + */ + public function render() { + return [ + 'command' => 'setToolbarSubtrees', + 'subtrees' => array_map('strval', $this->subtrees), + ]; + } + +} diff --git a/core/modules/toolbar/src/Controller/ToolbarController.php b/core/modules/toolbar/src/Controller/ToolbarController.php index ecccc1eb5f96..a158deeb2679 100644 --- a/core/modules/toolbar/src/Controller/ToolbarController.php +++ b/core/modules/toolbar/src/Controller/ToolbarController.php @@ -8,8 +8,9 @@ namespace Drupal\toolbar\Controller; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Controller\ControllerBase; -use Symfony\Component\HttpFoundation\JsonResponse; +use Drupal\toolbar\Ajax\SetSubtreesCommand; /** * Defines a controller for the toolbar module. @@ -17,14 +18,14 @@ use Symfony\Component\HttpFoundation\JsonResponse; class ToolbarController extends ControllerBase { /** - * Returns the rendered subtree of each top-level toolbar link. + * Returns an AJAX response to render the toolbar subtrees. * - * @return \Symfony\Component\HttpFoundation\JsonResponse + * @return \Drupal\Core\Ajax\AjaxResponse */ - public function subtreesJsonp() { + public function subtreesAjax() { list($subtrees, $cacheability) = toolbar_get_rendered_subtrees(); - $response = new JsonResponse($subtrees); - $response->setCallback('Drupal.toolbar.setSubtrees.resolve'); + $response = new AjaxResponse(); + $response->addCommand(new SetSubtreesCommand($subtrees)); // The Expires HTTP header is the heart of the client-side HTTP caching. The // additional server-side page cache only takes effect when the client diff --git a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php index cd6cb9f904f4..3139b5da769f 100644 --- a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php +++ b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php @@ -7,7 +7,6 @@ namespace Drupal\toolbar\Tests; -use Drupal\Component\Serialization\Json; use Drupal\Core\Cache\Cache; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; @@ -341,14 +340,10 @@ class ToolbarAdminMenuTest extends WebTestBase { // Request a new page to refresh the drupalSettings object. $subtrees_hash = $this->getSubtreesHash(); - $this->drupalGetJSON('toolbar/subtrees/' . $subtrees_hash); + $ajax_result = $this->drupalGetAjax('toolbar/subtrees/' . $subtrees_hash); $this->assertResponse('200'); - $json_callback_start = substr($this->getRawContent(), 0, 39); - $json_callback_end = substr($this->getRawContent(), -2, 2); - $json = substr($this->getRawContent(), 39, strlen($this->getRawContent()) - 41); - $this->assertTrue($json_callback_start === '/**/Drupal.toolbar.setSubtrees.resolve(' && $json_callback_end === ');', 'Subtrees response is wrapped in callback.'); - $subtrees = Json::decode($json); - $this->assertEqual(array_keys($subtrees), ['system-admin_content', 'system-admin_structure', 'system-themes_page', 'system-modules_list', 'system-admin_config', 'entity-user-collection', 'front'], 'Correct subtrees JSON returned.'); + $this->assertEqual($ajax_result[0]['command'], 'setToolbarSubtrees', 'Subtrees response uses the correct command.'); + $this->assertEqual(array_keys($ajax_result[0]['subtrees']), ['system-admin_content', 'system-admin_structure', 'system-themes_page', 'system-modules_list', 'system-admin_config', 'entity-user-collection', 'front'], 'Correct subtrees returned.'); } /** diff --git a/core/modules/toolbar/toolbar.libraries.yml b/core/modules/toolbar/toolbar.libraries.yml index df3f66046ba3..dcef0841bb62 100644 --- a/core/modules/toolbar/toolbar.libraries.yml +++ b/core/modules/toolbar/toolbar.libraries.yml @@ -22,6 +22,7 @@ toolbar: - core/jquery - core/drupal - core/drupalSettings + - core/drupal.ajax - core/drupal.announce - core/backbone - core/matchmedia diff --git a/core/modules/toolbar/toolbar.routing.yml b/core/modules/toolbar/toolbar.routing.yml index c1b8581d9639..0f9dcf8acc50 100644 --- a/core/modules/toolbar/toolbar.routing.yml +++ b/core/modules/toolbar/toolbar.routing.yml @@ -1,7 +1,8 @@ toolbar.subtrees: path: '/toolbar/subtrees/{hash}' defaults: - _controller: '\Drupal\toolbar\Controller\ToolbarController::subtreesJsonp' - langcode: null + _controller: '\Drupal\toolbar\Controller\ToolbarController::subtreesAjax' + options: + _theme: ajax_base_page requirements: _custom_access: '\Drupal\toolbar\Controller\ToolbarController::checkSubTreeAccess'