Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / toolbar / js / views / ToolbarVisualView.es6.js
index fd4fa6bfd2fd11ac2a9e9fefe49203f0743bca64..e263810daa58a58cb79dea87cf54b8e9aa000e48 100644 (file)
  * A Backbone view for the toolbar element. Listens to mouse & touch.
  */
 
-(function ($, Drupal, drupalSettings, Backbone) {
-  Drupal.toolbar.ToolbarVisualView = Backbone.View.extend(/** @lends Drupal.toolbar.ToolbarVisualView# */{
+(function($, Drupal, drupalSettings, Backbone) {
+  Drupal.toolbar.ToolbarVisualView = Backbone.View.extend(
+    /** @lends Drupal.toolbar.ToolbarVisualView# */ {
+      /**
+       * Event map for the `ToolbarVisualView`.
+       *
+       * @return {object}
+       *   A map of events.
+       */
+      events() {
+        // Prevents delay and simulated mouse events.
+        const touchEndToClick = function(event) {
+          event.preventDefault();
+          event.target.click();
+        };
 
-    /**
-     * Event map for the `ToolbarVisualView`.
-     *
-     * @return {object}
-     *   A map of events.
-     */
-    events() {
-      // Prevents delay and simulated mouse events.
-      const touchEndToClick = function (event) {
-        event.preventDefault();
-        event.target.click();
-      };
+        return {
+          'click .toolbar-bar .toolbar-tab .trigger': 'onTabClick',
+          'click .toolbar-toggle-orientation button':
+            'onOrientationToggleClick',
+          'touchend .toolbar-bar .toolbar-tab .trigger': touchEndToClick,
+          'touchend .toolbar-toggle-orientation button': touchEndToClick,
+        };
+      },
 
-      return {
-        'click .toolbar-bar .toolbar-tab .trigger': 'onTabClick',
-        'click .toolbar-toggle-orientation button': 'onOrientationToggleClick',
-        'touchend .toolbar-bar .toolbar-tab .trigger': touchEndToClick,
-        'touchend .toolbar-toggle-orientation button': touchEndToClick,
-      };
-    },
+      /**
+       * Backbone view for the toolbar element. Listens to mouse & touch.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options for the view object.
+       * @param {object} options.strings
+       *   Various strings to use in the view.
+       */
+      initialize(options) {
+        this.strings = options.strings;
 
-    /**
-     * Backbone view for the toolbar element. Listens to mouse & touch.
-     *
-     * @constructs
-     *
-     * @augments Backbone.View
-     *
-     * @param {object} options
-     *   Options for the view object.
-     * @param {object} options.strings
-     *   Various strings to use in the view.
-     */
-    initialize(options) {
-      this.strings = options.strings;
+        this.listenTo(
+          this.model,
+          'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible',
+          this.render,
+        );
+        this.listenTo(this.model, 'change:mqMatches', this.onMediaQueryChange);
+        this.listenTo(this.model, 'change:offsets', this.adjustPlacement);
+        this.listenTo(
+          this.model,
+          'change:activeTab change:orientation change:isOriented',
+          this.updateToolbarHeight,
+        );
 
-      this.listenTo(this.model, 'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible', this.render);
-      this.listenTo(this.model, 'change:mqMatches', this.onMediaQueryChange);
-      this.listenTo(this.model, 'change:offsets', this.adjustPlacement);
-      this.listenTo(this.model, 'change:activeTab change:orientation change:isOriented', this.updateToolbarHeight);
+        // Add the tray orientation toggles.
+        this.$el
+          .find('.toolbar-tray .toolbar-lining')
+          .append(Drupal.theme('toolbarOrientationToggle'));
 
-      // Add the tray orientation toggles.
-      this.$el
-        .find('.toolbar-tray .toolbar-lining')
-        .append(Drupal.theme('toolbarOrientationToggle'));
+        // Trigger an activeTab change so that listening scripts can respond on
+        // page load. This will call render.
+        this.model.trigger('change:activeTab');
+      },
 
-      // Trigger an activeTab change so that listening scripts can respond on
-      // page load. This will call render.
-      this.model.trigger('change:activeTab');
-    },
+      /**
+       * Update the toolbar element height.
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       */
+      updateToolbarHeight() {
+        const toolbarTabOuterHeight =
+          $('#toolbar-bar')
+            .find('.toolbar-tab')
+            .outerHeight() || 0;
+        const toolbarTrayHorizontalOuterHeight =
+          $('.is-active.toolbar-tray-horizontal').outerHeight() || 0;
+        this.model.set(
+          'height',
+          toolbarTabOuterHeight + toolbarTrayHorizontalOuterHeight,
+        );
 
-    /**
-     * Update the toolbar element height.
-     *
-     * @constructs
-     *
-     * @augments Backbone.View
-     */
-    updateToolbarHeight() {
-      const toolbarTabOuterHeight = $('#toolbar-bar').find('.toolbar-tab').outerHeight() || 0;
-      const toolbarTrayHorizontalOuterHeight = $('.is-active.toolbar-tray-horizontal').outerHeight() || 0;
-      this.model.set('height', toolbarTabOuterHeight + toolbarTrayHorizontalOuterHeight);
+        $('body').css({
+          'padding-top': this.model.get('height'),
+        });
 
-      $('body').css({
-        'padding-top': this.model.get('height'),
-      });
+        this.triggerDisplace();
+      },
 
-      this.triggerDisplace();
-    },
+      // Trigger a recalculation of viewport displacing elements. Use setTimeout
+      // to ensure this recalculation happens after changes to visual elements
+      // have processed.
+      triggerDisplace() {
+        _.defer(() => {
+          Drupal.displace(true);
+        });
+      },
 
-    // Trigger a recalculation of viewport displacing elements. Use setTimeout
-    // to ensure this recalculation happens after changes to visual elements
-    // have processed.
-    triggerDisplace() {
-      _.defer(() => {
-        Drupal.displace(true);
-      });
-    },
+      /**
+       * @inheritdoc
+       *
+       * @return {Drupal.toolbar.ToolbarVisualView}
+       *   The `ToolbarVisualView` instance.
+       */
+      render() {
+        this.updateTabs();
+        this.updateTrayOrientation();
+        this.updateBarAttributes();
+
+        $('body').removeClass('toolbar-loading');
 
-    /**
-     * @inheritdoc
-     *
-     * @return {Drupal.toolbar.ToolbarVisualView}
-     *   The `ToolbarVisualView` instance.
-     */
-    render() {
-      this.updateTabs();
-      this.updateTrayOrientation();
-      this.updateBarAttributes();
+        // Load the subtrees if the orientation of the toolbar is changed to
+        // vertical. This condition responds to the case that the toolbar switches
+        // from horizontal to vertical orientation. The toolbar starts in a
+        // vertical orientation by default and then switches to horizontal during
+        // initialization if the media query conditions are met. Simply checking
+        // that the orientation is vertical here would result in the subtrees
+        // always being loaded, even when the toolbar initialization ultimately
+        // results in a horizontal orientation.
+        //
+        // @see Drupal.behaviors.toolbar.attach() where admin menu subtrees
+        // loading is invoked during initialization after media query conditions
+        // have been processed.
+        if (
+          this.model.changed.orientation === 'vertical' ||
+          this.model.changed.activeTab
+        ) {
+          this.loadSubtrees();
+        }
 
-      $('body').removeClass('toolbar-loading');
+        return this;
+      },
 
-      // Load the subtrees if the orientation of the toolbar is changed to
-      // vertical. This condition responds to the case that the toolbar switches
-      // from horizontal to vertical orientation. The toolbar starts in a
-      // vertical orientation by default and then switches to horizontal during
-      // initialization if the media query conditions are met. Simply checking
-      // that the orientation is vertical here would result in the subtrees
-      // always being loaded, even when the toolbar initialization ultimately
-      // results in a horizontal orientation.
-      //
-      // @see Drupal.behaviors.toolbar.attach() where admin menu subtrees
-      // loading is invoked during initialization after media query conditions
-      // have been processed.
-      if (this.model.changed.orientation === 'vertical' || this.model.changed.activeTab) {
-        this.loadSubtrees();
-      }
+      /**
+       * Responds to a toolbar tab click.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      onTabClick(event) {
+        // If this tab has a tray associated with it, it is considered an
+        // activatable tab.
+        if (event.target.hasAttribute('data-toolbar-tray')) {
+          const activeTab = this.model.get('activeTab');
+          const clickedTab = event.target;
 
-      return this;
-    },
+          // Set the event target as the active item if it is not already.
+          this.model.set(
+            'activeTab',
+            !activeTab || clickedTab !== activeTab ? clickedTab : null,
+          );
 
-    /**
-     * Responds to a toolbar tab click.
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     */
-    onTabClick(event) {
-      // If this tab has a tray associated with it, it is considered an
-      // activatable tab.
-      if (event.target.hasAttribute('data-toolbar-tray')) {
-        const activeTab = this.model.get('activeTab');
-        const clickedTab = event.target;
+          event.preventDefault();
+          event.stopPropagation();
+        }
+      },
 
-        // Set the event target as the active item if it is not already.
-        this.model.set('activeTab', (!activeTab || clickedTab !== activeTab) ? clickedTab : null);
+      /**
+       * Toggles the orientation of a toolbar tray.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       */
+      onOrientationToggleClick(event) {
+        const orientation = this.model.get('orientation');
+        // Determine the toggle-to orientation.
+        const antiOrientation =
+          orientation === 'vertical' ? 'horizontal' : 'vertical';
+        const locked = antiOrientation === 'vertical';
+        // Remember the locked state.
+        if (locked) {
+          localStorage.setItem('Drupal.toolbar.trayVerticalLocked', 'true');
+        } else {
+          localStorage.removeItem('Drupal.toolbar.trayVerticalLocked');
+        }
+        // Update the model.
+        this.model.set(
+          {
+            locked,
+            orientation: antiOrientation,
+          },
+          {
+            validate: true,
+            override: true,
+          },
+        );
 
         event.preventDefault();
         event.stopPropagation();
-      }
-    },
+      },
 
-    /**
-     * Toggles the orientation of a toolbar tray.
-     *
-     * @param {jQuery.Event} event
-     *   The event triggered.
-     */
-    onOrientationToggleClick(event) {
-      const orientation = this.model.get('orientation');
-      // Determine the toggle-to orientation.
-      const antiOrientation = (orientation === 'vertical') ? 'horizontal' : 'vertical';
-      const locked = antiOrientation === 'vertical';
-      // Remember the locked state.
-      if (locked) {
-        localStorage.setItem('Drupal.toolbar.trayVerticalLocked', 'true');
-      }
-      else {
-        localStorage.removeItem('Drupal.toolbar.trayVerticalLocked');
-      }
-      // Update the model.
-      this.model.set({
-        locked,
-        orientation: antiOrientation,
-      }, {
-        validate: true,
-        override: true,
-      });
+      /**
+       * Updates the display of the tabs: toggles a tab and the associated tray.
+       */
+      updateTabs() {
+        const $tab = $(this.model.get('activeTab'));
+        // Deactivate the previous tab.
+        $(this.model.previous('activeTab'))
+          .removeClass('is-active')
+          .prop('aria-pressed', false);
+        // Deactivate the previous tray.
+        $(this.model.previous('activeTray')).removeClass('is-active');
 
-      event.preventDefault();
-      event.stopPropagation();
-    },
-
-    /**
-     * Updates the display of the tabs: toggles a tab and the associated tray.
-     */
-    updateTabs() {
-      const $tab = $(this.model.get('activeTab'));
-      // Deactivate the previous tab.
-      $(this.model.previous('activeTab'))
-        .removeClass('is-active')
-        .prop('aria-pressed', false);
-      // Deactivate the previous tray.
-      $(this.model.previous('activeTray'))
-        .removeClass('is-active');
-
-      // Activate the selected tab.
-      if ($tab.length > 0) {
-        $tab
-          .addClass('is-active')
-          // Mark the tab as pressed.
-          .prop('aria-pressed', true);
-        const name = $tab.attr('data-toolbar-tray');
-        // Store the active tab name or remove the setting.
-        const id = $tab.get(0).id;
-        if (id) {
-          localStorage.setItem('Drupal.toolbar.activeTabID', JSON.stringify(id));
-        }
-        // Activate the associated tray.
-        const $tray = this.$el.find(`[data-toolbar-tray="${name}"].toolbar-tray`);
-        if ($tray.length) {
-          $tray.addClass('is-active');
-          this.model.set('activeTray', $tray.get(0));
-        }
-        else {
+        // Activate the selected tab.
+        if ($tab.length > 0) {
+          $tab
+            .addClass('is-active')
+            // Mark the tab as pressed.
+            .prop('aria-pressed', true);
+          const name = $tab.attr('data-toolbar-tray');
+          // Store the active tab name or remove the setting.
+          const id = $tab.get(0).id;
+          if (id) {
+            localStorage.setItem(
+              'Drupal.toolbar.activeTabID',
+              JSON.stringify(id),
+            );
+          }
+          // Activate the associated tray.
+          const $tray = this.$el.find(
+            `[data-toolbar-tray="${name}"].toolbar-tray`,
+          );
+          if ($tray.length) {
+            $tray.addClass('is-active');
+            this.model.set('activeTray', $tray.get(0));
+          } else {
+            // There is no active tray.
+            this.model.set('activeTray', null);
+          }
+        } else {
           // There is no active tray.
           this.model.set('activeTray', null);
+          localStorage.removeItem('Drupal.toolbar.activeTabID');
         }
-      }
-      else {
-        // There is no active tray.
-        this.model.set('activeTray', null);
-        localStorage.removeItem('Drupal.toolbar.activeTabID');
-      }
-    },
+      },
 
-    /**
-     * Update the attributes of the toolbar bar element.
-     */
-    updateBarAttributes() {
-      const isOriented = this.model.get('isOriented');
-      if (isOriented) {
-        this.$el.find('.toolbar-bar').attr('data-offset-top', '');
-      }
-      else {
-        this.$el.find('.toolbar-bar').removeAttr('data-offset-top');
-      }
-      // Toggle between a basic vertical view and a more sophisticated
-      // horizontal and vertical display of the toolbar bar and trays.
-      this.$el.toggleClass('toolbar-oriented', isOriented);
-    },
+      /**
+       * Update the attributes of the toolbar bar element.
+       */
+      updateBarAttributes() {
+        const isOriented = this.model.get('isOriented');
+        if (isOriented) {
+          this.$el.find('.toolbar-bar').attr('data-offset-top', '');
+        } else {
+          this.$el.find('.toolbar-bar').removeAttr('data-offset-top');
+        }
+        // Toggle between a basic vertical view and a more sophisticated
+        // horizontal and vertical display of the toolbar bar and trays.
+        this.$el.toggleClass('toolbar-oriented', isOriented);
+      },
 
-    /**
-     * Updates the orientation of the active tray if necessary.
-     */
-    updateTrayOrientation() {
-      const orientation = this.model.get('orientation');
+      /**
+       * Updates the orientation of the active tray if necessary.
+       */
+      updateTrayOrientation() {
+        const orientation = this.model.get('orientation');
 
-      // The antiOrientation is used to render the view of action buttons like
-      // the tray orientation toggle.
-      const antiOrientation = (orientation === 'vertical') ? 'horizontal' : 'vertical';
+        // The antiOrientation is used to render the view of action buttons like
+        // the tray orientation toggle.
+        const antiOrientation =
+          orientation === 'vertical' ? 'horizontal' : 'vertical';
 
-      // Toggle toolbar's parent classes before other toolbar classes to avoid
-      // potential flicker and re-rendering.
-      $('body')
-        .toggleClass('toolbar-vertical', (orientation === 'vertical'))
-        .toggleClass('toolbar-horizontal', (orientation === 'horizontal'));
+        // Toggle toolbar's parent classes before other toolbar classes to avoid
+        // potential flicker and re-rendering.
+        $('body')
+          .toggleClass('toolbar-vertical', orientation === 'vertical')
+          .toggleClass('toolbar-horizontal', orientation === 'horizontal');
 
-      const removeClass = (antiOrientation === 'horizontal') ? 'toolbar-tray-horizontal' : 'toolbar-tray-vertical';
-      const $trays = this.$el.find('.toolbar-tray')
-        .removeClass(removeClass)
-        .addClass(`toolbar-tray-${orientation}`);
+        const removeClass =
+          antiOrientation === 'horizontal'
+            ? 'toolbar-tray-horizontal'
+            : 'toolbar-tray-vertical';
+        const $trays = this.$el
+          .find('.toolbar-tray')
+          .removeClass(removeClass)
+          .addClass(`toolbar-tray-${orientation}`);
 
-      // Update the tray orientation toggle button.
-      const iconClass = `toolbar-icon-toggle-${orientation}`;
-      const iconAntiClass = `toolbar-icon-toggle-${antiOrientation}`;
-      const $orientationToggle = this.$el.find('.toolbar-toggle-orientation')
-        .toggle(this.model.get('isTrayToggleVisible'));
-      $orientationToggle.find('button')
-        .val(antiOrientation)
-        .attr('title', this.strings[antiOrientation])
-        .text(this.strings[antiOrientation])
-        .removeClass(iconClass)
-        .addClass(iconAntiClass);
+        // Update the tray orientation toggle button.
+        const iconClass = `toolbar-icon-toggle-${orientation}`;
+        const iconAntiClass = `toolbar-icon-toggle-${antiOrientation}`;
+        const $orientationToggle = this.$el
+          .find('.toolbar-toggle-orientation')
+          .toggle(this.model.get('isTrayToggleVisible'));
+        $orientationToggle
+          .find('button')
+          .val(antiOrientation)
+          .attr('title', this.strings[antiOrientation])
+          .text(this.strings[antiOrientation])
+          .removeClass(iconClass)
+          .addClass(iconAntiClass);
 
-      // Update data offset attributes for the trays.
-      const dir = document.documentElement.dir;
-      const edge = (dir === 'rtl') ? 'right' : 'left';
-      // Remove data-offset attributes from the trays so they can be refreshed.
-      $trays.removeAttr('data-offset-left data-offset-right data-offset-top');
-      // If an active vertical tray exists, mark it as an offset element.
-      $trays.filter('.toolbar-tray-vertical.is-active').attr(`data-offset-${edge}`, '');
-      // If an active horizontal tray exists, mark it as an offset element.
-      $trays.filter('.toolbar-tray-horizontal.is-active').attr('data-offset-top', '');
-    },
+        // Update data offset attributes for the trays.
+        const dir = document.documentElement.dir;
+        const edge = dir === 'rtl' ? 'right' : 'left';
+        // Remove data-offset attributes from the trays so they can be refreshed.
+        $trays.removeAttr('data-offset-left data-offset-right data-offset-top');
+        // If an active vertical tray exists, mark it as an offset element.
+        $trays
+          .filter('.toolbar-tray-vertical.is-active')
+          .attr(`data-offset-${edge}`, '');
+        // If an active horizontal tray exists, mark it as an offset element.
+        $trays
+          .filter('.toolbar-tray-horizontal.is-active')
+          .attr('data-offset-top', '');
+      },
 
-    /**
-     * Sets the tops of the trays so that they align with the bottom of the bar.
-     */
-    adjustPlacement() {
-      const $trays = this.$el.find('.toolbar-tray');
-      if (!this.model.get('isOriented')) {
-        $trays.removeClass('toolbar-tray-horizontal').addClass('toolbar-tray-vertical');
-      }
-    },
-
-    /**
-     * 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-
-     * side is invalidated. The subtreesHash is stored in localStorage as well
-     * and compared to the subtreesHash in drupalSettings to determine when the
-     * admin menu subtrees cache has been invalidated.
-     */
-    loadSubtrees() {
-      const $activeTab = $(this.model.get('activeTab'));
-      const orientation = this.model.get('orientation');
-      // Only load and render the admin menu subtrees if:
-      //   (1) They have not been loaded yet.
-      //   (2) The active tab is the administration menu tab, indicated by the
-      //       presence of the data-drupal-subtrees attribute.
-      //   (3) The orientation of the tray is vertical.
-      if (!this.model.get('areSubtreesLoaded') && typeof $activeTab.data('drupal-subtrees') !== 'undefined' && orientation === 'vertical') {
-        const subtreesHash = drupalSettings.toolbar.subtreesHash;
-        const theme = drupalSettings.ajaxPageState.theme;
-        const endpoint = Drupal.url(`toolbar/subtrees/${subtreesHash}`);
-        const cachedSubtreesHash = localStorage.getItem(`Drupal.toolbar.subtreesHash.${theme}`);
-        const cachedSubtrees = JSON.parse(localStorage.getItem(`Drupal.toolbar.subtrees.${theme}`));
-        const 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.
-        if (isVertical && subtreesHash === cachedSubtreesHash && cachedSubtrees) {
-          Drupal.toolbar.setSubtrees.resolve(cachedSubtrees);
+      /**
+       * Sets the tops of the trays so that they align with the bottom of the bar.
+       */
+      adjustPlacement() {
+        const $trays = this.$el.find('.toolbar-tray');
+        if (!this.model.get('isOriented')) {
+          $trays
+            .removeClass('toolbar-tray-horizontal')
+            .addClass('toolbar-tray-vertical');
         }
-        // Only make the call to get the subtrees if the orientation of the
-        // toolbar is vertical.
-        else if (isVertical) {
-          // Remove the cached menu information.
-          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.
-          Drupal.ajax({ url: endpoint }).execute();
-          // Cache the hash for the subtrees locally.
-          localStorage.setItem(`Drupal.toolbar.subtreesHash.${theme}`, subtreesHash);
+      },
+
+      /**
+       * 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-
+       * side is invalidated. The subtreesHash is stored in localStorage as well
+       * and compared to the subtreesHash in drupalSettings to determine when the
+       * admin menu subtrees cache has been invalidated.
+       */
+      loadSubtrees() {
+        const $activeTab = $(this.model.get('activeTab'));
+        const orientation = this.model.get('orientation');
+        // Only load and render the admin menu subtrees if:
+        //   (1) They have not been loaded yet.
+        //   (2) The active tab is the administration menu tab, indicated by the
+        //       presence of the data-drupal-subtrees attribute.
+        //   (3) The orientation of the tray is vertical.
+        if (
+          !this.model.get('areSubtreesLoaded') &&
+          typeof $activeTab.data('drupal-subtrees') !== 'undefined' &&
+          orientation === 'vertical'
+        ) {
+          const subtreesHash = drupalSettings.toolbar.subtreesHash;
+          const theme = drupalSettings.ajaxPageState.theme;
+          const endpoint = Drupal.url(`toolbar/subtrees/${subtreesHash}`);
+          const cachedSubtreesHash = localStorage.getItem(
+            `Drupal.toolbar.subtreesHash.${theme}`,
+          );
+          const cachedSubtrees = JSON.parse(
+            localStorage.getItem(`Drupal.toolbar.subtrees.${theme}`),
+          );
+          const 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.
+          if (
+            isVertical &&
+            subtreesHash === cachedSubtreesHash &&
+            cachedSubtrees
+          ) {
+            Drupal.toolbar.setSubtrees.resolve(cachedSubtrees);
+          }
+          // Only make the call to get the subtrees if the orientation of the
+          // toolbar is vertical.
+          else if (isVertical) {
+            // Remove the cached menu information.
+            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.
+            Drupal.ajax({ url: endpoint }).execute();
+            // Cache the hash for the subtrees locally.
+            localStorage.setItem(
+              `Drupal.toolbar.subtreesHash.${theme}`,
+              subtreesHash,
+            );
+          }
         }
-      }
+      },
     },
-  });
-}(jQuery, Drupal, drupalSettings, Backbone));
+  );
+})(jQuery, Drupal, drupalSettings, Backbone);