Initial Drupal 11 with DDEV setup
This commit is contained in:
		
							
								
								
									
										45
									
								
								web/core/modules/toolbar/js/escapeAdmin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								web/core/modules/toolbar/js/escapeAdmin.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Replaces the home link in toolbar with a back to site link.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function ($, Drupal, drupalSettings) {
 | 
			
		||||
  const pathInfo = drupalSettings.path;
 | 
			
		||||
  const escapeAdminPath = sessionStorage.getItem('escapeAdminPath');
 | 
			
		||||
  const windowLocation = window.location;
 | 
			
		||||
 | 
			
		||||
  // Saves the last non-administrative page in the browser to be able to link
 | 
			
		||||
  // back to it when browsing administrative pages. If there is a destination
 | 
			
		||||
  // parameter there is not need to save the current path because the page is
 | 
			
		||||
  // loaded within an existing "workflow".
 | 
			
		||||
  if (
 | 
			
		||||
    !pathInfo.currentPathIsAdmin &&
 | 
			
		||||
    !/destination=/.test(windowLocation.search)
 | 
			
		||||
  ) {
 | 
			
		||||
    sessionStorage.setItem('escapeAdminPath', windowLocation);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Replaces "Back to site" link url when appropriate.
 | 
			
		||||
   *
 | 
			
		||||
   * Back to site link points to the last non-administrative page the user
 | 
			
		||||
   * visited within the same browser tab.
 | 
			
		||||
   *
 | 
			
		||||
   * @type {Drupal~behavior}
 | 
			
		||||
   *
 | 
			
		||||
   * @prop {Drupal~behaviorAttach} attach
 | 
			
		||||
   *   Attaches the replacement functionality to the toolbar-escape-admin element.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.behaviors.escapeAdmin = {
 | 
			
		||||
    attach() {
 | 
			
		||||
      const toolbarEscape = once('escapeAdmin', '[data-toolbar-escape-admin]');
 | 
			
		||||
      if (
 | 
			
		||||
        toolbarEscape.length &&
 | 
			
		||||
        pathInfo.currentPathIsAdmin &&
 | 
			
		||||
        escapeAdminPath !== null
 | 
			
		||||
      ) {
 | 
			
		||||
        $(toolbarEscape).attr('href', escapeAdminPath);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
})(jQuery, Drupal, drupalSettings);
 | 
			
		||||
							
								
								
									
										29
									
								
								web/core/modules/toolbar/js/models/MenuModel.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								web/core/modules/toolbar/js/models/MenuModel.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * A Backbone Model for collapsible menus.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function (Backbone, Drupal) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Backbone Model for collapsible menus.
 | 
			
		||||
   *
 | 
			
		||||
   * @constructor
 | 
			
		||||
   *
 | 
			
		||||
   * @augments Backbone.Model
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.toolbar.MenuModel = Backbone.Model.extend(
 | 
			
		||||
    /** @lends Drupal.toolbar.MenuModel# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * @type {object}
 | 
			
		||||
       *
 | 
			
		||||
       * @prop {object|null} subtrees
 | 
			
		||||
       */
 | 
			
		||||
      defaults: /** @lends Drupal.toolbar.MenuModel# */ {
 | 
			
		||||
        /**
 | 
			
		||||
         * @type {object|null}
 | 
			
		||||
         */
 | 
			
		||||
        subtrees: null,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
})(Backbone, Drupal);
 | 
			
		||||
							
								
								
									
										159
									
								
								web/core/modules/toolbar/js/models/ToolbarModel.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								web/core/modules/toolbar/js/models/ToolbarModel.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,159 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * A Backbone Model for the toolbar.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function (Backbone, Drupal) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Backbone model for the toolbar.
 | 
			
		||||
   *
 | 
			
		||||
   * @constructor
 | 
			
		||||
   *
 | 
			
		||||
   * @augments Backbone.Model
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.toolbar.ToolbarModel = Backbone.Model.extend(
 | 
			
		||||
    /** @lends Drupal.toolbar.ToolbarModel# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * @type {object}
 | 
			
		||||
       *
 | 
			
		||||
       * @prop activeTab
 | 
			
		||||
       * @prop activeTray
 | 
			
		||||
       * @prop isOriented
 | 
			
		||||
       * @prop isFixed
 | 
			
		||||
       * @prop areSubtreesLoaded
 | 
			
		||||
       * @prop isViewportOverflowConstrained
 | 
			
		||||
       * @prop orientation
 | 
			
		||||
       * @prop locked
 | 
			
		||||
       * @prop isTrayToggleVisible
 | 
			
		||||
       * @prop height
 | 
			
		||||
       * @prop offsets
 | 
			
		||||
       */
 | 
			
		||||
      defaults: /** @lends Drupal.toolbar.ToolbarModel# */ {
 | 
			
		||||
        /**
 | 
			
		||||
         * The active toolbar tab. All other tabs should be inactive under
 | 
			
		||||
         * normal circumstances. It will remain active across page loads. The
 | 
			
		||||
         * active item is stored as an ID selector e.g. '#toolbar-item--1'.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {string}
 | 
			
		||||
         */
 | 
			
		||||
        activeTab: null,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Represents whether a tray is open or not. Stored as an ID selector e.g.
 | 
			
		||||
         * '#toolbar-item--1-tray'.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {string}
 | 
			
		||||
         */
 | 
			
		||||
        activeTray: null,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Indicates whether the toolbar is displayed in an oriented fashion,
 | 
			
		||||
         * either horizontal or vertical.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        isOriented: false,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Indicates whether the toolbar is positioned absolute (false) or fixed
 | 
			
		||||
         * (true).
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        isFixed: false,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Menu subtrees are loaded through an AJAX request only when the Toolbar
 | 
			
		||||
         * is set to a vertical orientation.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        areSubtreesLoaded: false,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * If the viewport overflow becomes constrained, isFixed must be true so
 | 
			
		||||
         * that elements in the trays aren't lost off-screen and impossible to
 | 
			
		||||
         * get to.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        isViewportOverflowConstrained: false,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The orientation of the active tray.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {string}
 | 
			
		||||
         */
 | 
			
		||||
        orientation: 'horizontal',
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A tray is locked if a user toggled it to vertical. Otherwise a tray
 | 
			
		||||
         * will switch between vertical and horizontal orientation based on the
 | 
			
		||||
         * configured breakpoints. The locked state will be maintained across page
 | 
			
		||||
         * loads.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        locked: false,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Indicates whether the tray orientation toggle is visible.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {boolean}
 | 
			
		||||
         */
 | 
			
		||||
        isTrayToggleVisible: true,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The height of the toolbar.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {number}
 | 
			
		||||
         */
 | 
			
		||||
        height: null,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The current viewport offsets determined by {@link Drupal.displace}. The
 | 
			
		||||
         * offsets suggest how a module might position is components relative to
 | 
			
		||||
         * the viewport.
 | 
			
		||||
         *
 | 
			
		||||
         * @type {object}
 | 
			
		||||
         *
 | 
			
		||||
         * @prop {number} top
 | 
			
		||||
         * @prop {number} right
 | 
			
		||||
         * @prop {number} bottom
 | 
			
		||||
         * @prop {number} left
 | 
			
		||||
         */
 | 
			
		||||
        offsets: {
 | 
			
		||||
          top: 0,
 | 
			
		||||
          right: 0,
 | 
			
		||||
          bottom: 0,
 | 
			
		||||
          left: 0,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * {@inheritdoc}
 | 
			
		||||
       *
 | 
			
		||||
       * @param {object} attributes
 | 
			
		||||
       *   Attributes for the toolbar.
 | 
			
		||||
       * @param {object} options
 | 
			
		||||
       *   Options for the toolbar.
 | 
			
		||||
       *
 | 
			
		||||
       * @return {string|undefined}
 | 
			
		||||
       *   Returns an error message if validation failed.
 | 
			
		||||
       */
 | 
			
		||||
      validate(attributes, options) {
 | 
			
		||||
        // Prevent the orientation being set to horizontal if it is locked, unless
 | 
			
		||||
        // override has not been passed as an option.
 | 
			
		||||
        if (
 | 
			
		||||
          attributes.orientation === 'horizontal' &&
 | 
			
		||||
          this.get('locked') &&
 | 
			
		||||
          !options.override
 | 
			
		||||
        ) {
 | 
			
		||||
          return Drupal.t(
 | 
			
		||||
            'The toolbar cannot be set to a horizontal orientation when it is locked.',
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
})(Backbone, Drupal);
 | 
			
		||||
							
								
								
									
										72
									
								
								web/core/modules/toolbar/js/toolbar.anti-flicker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								web/core/modules/toolbar/js/toolbar.anti-flicker.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Prevents flicker of the toolbar on page load.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(() => {
 | 
			
		||||
  const toolbarState = sessionStorage.getItem('Drupal.toolbar.toolbarState')
 | 
			
		||||
    ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState'))
 | 
			
		||||
    : false;
 | 
			
		||||
  // These are classes that toolbar typically adds to <body>, but this code
 | 
			
		||||
  // executes before the first paint, when <body> is not yet present. The
 | 
			
		||||
  // classes are added to <html> so styling immediately reflects the current
 | 
			
		||||
  // toolbar state. The classes are removed after the toolbar completes
 | 
			
		||||
  // initialization.
 | 
			
		||||
  const classesToAdd = ['toolbar-loading', 'toolbar-anti-flicker'];
 | 
			
		||||
  if (toolbarState) {
 | 
			
		||||
    const {
 | 
			
		||||
      orientation,
 | 
			
		||||
      hasActiveTab,
 | 
			
		||||
      isFixed,
 | 
			
		||||
      activeTray,
 | 
			
		||||
      activeTabId,
 | 
			
		||||
      isOriented,
 | 
			
		||||
      userButtonMinWidth,
 | 
			
		||||
    } = toolbarState;
 | 
			
		||||
 | 
			
		||||
    classesToAdd.push(
 | 
			
		||||
      orientation ? `toolbar-${orientation}` : 'toolbar-horizontal',
 | 
			
		||||
    );
 | 
			
		||||
    if (hasActiveTab !== false) {
 | 
			
		||||
      classesToAdd.push('toolbar-tray-open');
 | 
			
		||||
    }
 | 
			
		||||
    if (isFixed) {
 | 
			
		||||
      classesToAdd.push('toolbar-fixed');
 | 
			
		||||
    }
 | 
			
		||||
    if (isOriented) {
 | 
			
		||||
      classesToAdd.push('toolbar-oriented');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (activeTray) {
 | 
			
		||||
      // These styles are added so the active tab/tray styles are present
 | 
			
		||||
      // immediately instead of "flickering" on as the toolbar initializes. In
 | 
			
		||||
      // instances where a tray is lazy loaded, these styles facilitate the
 | 
			
		||||
      // lazy loaded tray appearing gracefully and without reflow.
 | 
			
		||||
      const styleContent = `
 | 
			
		||||
      .toolbar-loading #${activeTabId} {
 | 
			
		||||
        background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%);
 | 
			
		||||
      }
 | 
			
		||||
      .toolbar-loading #${activeTabId}-tray {
 | 
			
		||||
        display: block; box-shadow: -1px 0 5px 2px rgb(0 0 0 / 33%);
 | 
			
		||||
        border-right: 1px solid #aaa; background-color: #f5f5f5;
 | 
			
		||||
        z-index: 0;
 | 
			
		||||
      }
 | 
			
		||||
      .toolbar-loading.toolbar-vertical.toolbar-tray-open #${activeTabId}-tray {
 | 
			
		||||
        width: 15rem; height: 100vh;
 | 
			
		||||
      }
 | 
			
		||||
     .toolbar-loading.toolbar-horizontal :not(#${activeTray}) > .toolbar-lining {opacity: 0}`;
 | 
			
		||||
 | 
			
		||||
      const style = document.createElement('style');
 | 
			
		||||
      style.textContent = styleContent;
 | 
			
		||||
      style.setAttribute('data-toolbar-anti-flicker-loading', true);
 | 
			
		||||
      document.querySelector('head').appendChild(style);
 | 
			
		||||
      if (userButtonMinWidth) {
 | 
			
		||||
        const userButtonStyle = document.createElement('style');
 | 
			
		||||
        userButtonStyle.textContent = `
 | 
			
		||||
        #toolbar-item-user {min-width: ${userButtonMinWidth}px;}`;
 | 
			
		||||
        document.querySelector('head').appendChild(userButtonStyle);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  document.querySelector('html').classList.add(...classesToAdd);
 | 
			
		||||
})();
 | 
			
		||||
							
								
								
									
										401
									
								
								web/core/modules/toolbar/js/toolbar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								web/core/modules/toolbar/js/toolbar.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,401 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Defines the behavior of the Drupal administration toolbar.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function ($, Drupal, drupalSettings) {
 | 
			
		||||
  // Set UI-impacting toolbar classes before Drupal behaviors initialize to
 | 
			
		||||
  // minimize flickering on load. This is encapsulated in a function to
 | 
			
		||||
  // emphasize this having a distinct purpose than the code that follows it.
 | 
			
		||||
  (() => {
 | 
			
		||||
    if (!sessionStorage.getItem('Drupal.toolbar.toolbarState')) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const toolbarState = JSON.parse(
 | 
			
		||||
      sessionStorage.getItem('Drupal.toolbar.toolbarState'),
 | 
			
		||||
    );
 | 
			
		||||
    const { activeTray, orientation, isOriented } = toolbarState;
 | 
			
		||||
    const activeTrayElement = document.querySelector(
 | 
			
		||||
      `.toolbar-tray[data-toolbar-tray="${activeTray}"]`,
 | 
			
		||||
    );
 | 
			
		||||
    const activeTrayToggle = document.querySelector(
 | 
			
		||||
      `.toolbar-item[data-toolbar-tray="${activeTray}"]`,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (activeTrayElement) {
 | 
			
		||||
      activeTrayElement.classList.add(
 | 
			
		||||
        `toolbar-tray-${orientation}`,
 | 
			
		||||
        'is-active',
 | 
			
		||||
      );
 | 
			
		||||
      activeTrayToggle.classList.add('is-active');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isOriented) {
 | 
			
		||||
      document
 | 
			
		||||
        .querySelector('#toolbar-administration')
 | 
			
		||||
        .classList.add('toolbar-oriented');
 | 
			
		||||
    }
 | 
			
		||||
  })();
 | 
			
		||||
 | 
			
		||||
  // Merge run-time settings with the defaults.
 | 
			
		||||
  const options = $.extend(
 | 
			
		||||
    {
 | 
			
		||||
      breakpoints: {
 | 
			
		||||
        'toolbar.narrow': '',
 | 
			
		||||
        'toolbar.standard': '',
 | 
			
		||||
        'toolbar.wide': '',
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    drupalSettings.toolbar,
 | 
			
		||||
    // Merge strings on top of drupalSettings so that they are not mutable.
 | 
			
		||||
    {
 | 
			
		||||
      strings: {
 | 
			
		||||
        horizontal: Drupal.t('Horizontal orientation'),
 | 
			
		||||
        vertical: Drupal.t('Vertical orientation'),
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Registers tabs with the toolbar.
 | 
			
		||||
   *
 | 
			
		||||
   * The Drupal toolbar allows modules to register top-level tabs. These may
 | 
			
		||||
   * point directly to a resource or toggle the visibility of a tray.
 | 
			
		||||
   *
 | 
			
		||||
   * Modules register tabs with hook_toolbar().
 | 
			
		||||
   *
 | 
			
		||||
   * @type {Drupal~behavior}
 | 
			
		||||
   *
 | 
			
		||||
   * @prop {Drupal~behaviorAttach} attach
 | 
			
		||||
   *   Attaches the toolbar rendering functionality to the toolbar element.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.behaviors.toolbar = {
 | 
			
		||||
    attach(context) {
 | 
			
		||||
      // Verify that the user agent understands media queries. Complex admin
 | 
			
		||||
      // toolbar layouts require media query support.
 | 
			
		||||
      if (!window.matchMedia('only screen').matches) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      // Process the administrative toolbar.
 | 
			
		||||
      once('toolbar', '#toolbar-administration', context).forEach((toolbar) => {
 | 
			
		||||
        // Establish the toolbar models and views.
 | 
			
		||||
        const model = new Drupal.toolbar.ToolbarModel({
 | 
			
		||||
          locked: JSON.parse(
 | 
			
		||||
            localStorage.getItem('Drupal.toolbar.trayVerticalLocked'),
 | 
			
		||||
          ),
 | 
			
		||||
          activeTab: document.getElementById(
 | 
			
		||||
            JSON.parse(localStorage.getItem('Drupal.toolbar.activeTabID')),
 | 
			
		||||
          ),
 | 
			
		||||
          height: $('#toolbar-administration').outerHeight(),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Drupal.toolbar.models.toolbarModel = model;
 | 
			
		||||
 | 
			
		||||
        // Attach a listener to the configured media query breakpoints.
 | 
			
		||||
        // Executes it before Drupal.toolbar.views to avoid extra rendering.
 | 
			
		||||
        Object.keys(options.breakpoints).forEach((label) => {
 | 
			
		||||
          const mq = options.breakpoints[label];
 | 
			
		||||
          const mql = window.matchMedia(mq);
 | 
			
		||||
          Drupal.toolbar.mql[label] = mql;
 | 
			
		||||
          // Curry the model and the label of the media query breakpoint to
 | 
			
		||||
          // the mediaQueryChangeHandler function.
 | 
			
		||||
          mql.addListener(
 | 
			
		||||
            Drupal.toolbar.mediaQueryChangeHandler.bind(null, model, label),
 | 
			
		||||
          );
 | 
			
		||||
          // Fire the mediaQueryChangeHandler for each configured breakpoint
 | 
			
		||||
          // so that they process once.
 | 
			
		||||
          Drupal.toolbar.mediaQueryChangeHandler.call(null, model, label, mql);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Drupal.toolbar.views.toolbarVisualView =
 | 
			
		||||
          new Drupal.toolbar.ToolbarVisualView({
 | 
			
		||||
            el: toolbar,
 | 
			
		||||
            model,
 | 
			
		||||
            strings: options.strings,
 | 
			
		||||
          });
 | 
			
		||||
        Drupal.toolbar.views.toolbarAuralView =
 | 
			
		||||
          new Drupal.toolbar.ToolbarAuralView({
 | 
			
		||||
            el: toolbar,
 | 
			
		||||
            model,
 | 
			
		||||
            strings: options.strings,
 | 
			
		||||
          });
 | 
			
		||||
        Drupal.toolbar.views.bodyVisualView = new Drupal.toolbar.BodyVisualView(
 | 
			
		||||
          {
 | 
			
		||||
            el: toolbar,
 | 
			
		||||
            model,
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Force layout render to fix mobile view. Only needed on load, not
 | 
			
		||||
        // for every media query match.
 | 
			
		||||
        model.trigger('change:isFixed', model, model.get('isFixed'));
 | 
			
		||||
        model.trigger('change:activeTray', model, model.get('activeTray'));
 | 
			
		||||
 | 
			
		||||
        // Render collapsible menus.
 | 
			
		||||
        const menuModel = new Drupal.toolbar.MenuModel();
 | 
			
		||||
        Drupal.toolbar.models.menuModel = menuModel;
 | 
			
		||||
        Drupal.toolbar.views.menuVisualView = new Drupal.toolbar.MenuVisualView(
 | 
			
		||||
          {
 | 
			
		||||
            el: $(toolbar).find('.toolbar-menu-administration').get(0),
 | 
			
		||||
            model: menuModel,
 | 
			
		||||
            strings: options.strings,
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Handle the resolution of Drupal.toolbar.setSubtrees.
 | 
			
		||||
        // This is handled with a deferred so that the function may be invoked
 | 
			
		||||
        // asynchronously.
 | 
			
		||||
        Drupal.toolbar.setSubtrees.done((subtrees) => {
 | 
			
		||||
          menuModel.set('subtrees', subtrees);
 | 
			
		||||
          const 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);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Trigger an initial attempt to load menu subitems. This first attempt
 | 
			
		||||
        // is made after the media query handlers have had an opportunity to
 | 
			
		||||
        // process. The toolbar starts in the vertical orientation by default,
 | 
			
		||||
        // unless the viewport is wide enough to accommodate a horizontal
 | 
			
		||||
        // orientation. Thus we give the Toolbar a chance to determine if it
 | 
			
		||||
        // should be set to horizontal orientation before attempting to load
 | 
			
		||||
        // menu subtrees.
 | 
			
		||||
        Drupal.toolbar.views.toolbarVisualView.loadSubtrees();
 | 
			
		||||
 | 
			
		||||
        $(document)
 | 
			
		||||
          // Update the model when the viewport offset changes.
 | 
			
		||||
          .on('drupalViewportOffsetChange.toolbar', (event, offsets) => {
 | 
			
		||||
            model.set('offsets', offsets);
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
        // Broadcast model changes to other modules.
 | 
			
		||||
        model
 | 
			
		||||
          .on('change:orientation', (model, orientation) => {
 | 
			
		||||
            $(document).trigger('drupalToolbarOrientationChange', orientation);
 | 
			
		||||
          })
 | 
			
		||||
          .on('change:activeTab', (model, tab) => {
 | 
			
		||||
            $(document).trigger('drupalToolbarTabChange', tab);
 | 
			
		||||
          })
 | 
			
		||||
          .on('change:activeTray', (model, tray) => {
 | 
			
		||||
            $(document).trigger('drupalToolbarTrayChange', tray);
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
        const toolbarState = sessionStorage.getItem(
 | 
			
		||||
          'Drupal.toolbar.toolbarState',
 | 
			
		||||
        )
 | 
			
		||||
          ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState'))
 | 
			
		||||
          : {};
 | 
			
		||||
        // If the toolbar's orientation is horizontal, no active tab is defined,
 | 
			
		||||
        // and the orientation state is not set (which means the user has not
 | 
			
		||||
        // yet interacted with the toolbar), then show the tray of the first
 | 
			
		||||
        // toolbar tab by default (but not the first 'Home' toolbar tab).
 | 
			
		||||
        if (
 | 
			
		||||
          Drupal.toolbar.models.toolbarModel.get('orientation') ===
 | 
			
		||||
            'horizontal' &&
 | 
			
		||||
          Drupal.toolbar.models.toolbarModel.get('activeTab') === null &&
 | 
			
		||||
          !toolbarState.orientation
 | 
			
		||||
        ) {
 | 
			
		||||
          Drupal.toolbar.models.toolbarModel.set({
 | 
			
		||||
            activeTab: $(
 | 
			
		||||
              '.toolbar-bar .toolbar-tab:not(.home-toolbar-tab) a',
 | 
			
		||||
            ).get(0),
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        window.addEventListener('dialog:aftercreate', (e) => {
 | 
			
		||||
          const $element = $(e.target);
 | 
			
		||||
          const { settings } = e;
 | 
			
		||||
          const toolbarBar = document.getElementById('toolbar-bar');
 | 
			
		||||
          if (toolbarBar) {
 | 
			
		||||
            toolbarBar.style.marginTop = '0';
 | 
			
		||||
 | 
			
		||||
            // When off-canvas is positioned in top, toolbar has to be moved down.
 | 
			
		||||
            if (settings.drupalOffCanvasPosition === 'top') {
 | 
			
		||||
              const height = Drupal.offCanvas
 | 
			
		||||
                .getContainer($element)
 | 
			
		||||
                .outerHeight();
 | 
			
		||||
              toolbarBar.style.marginTop = `${height}px`;
 | 
			
		||||
 | 
			
		||||
              $element.on('dialogContentResize.off-canvas', () => {
 | 
			
		||||
                const newHeight = Drupal.offCanvas
 | 
			
		||||
                  .getContainer($element)
 | 
			
		||||
                  .outerHeight();
 | 
			
		||||
                toolbarBar.style.marginTop = `${newHeight}px`;
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        window.addEventListener('dialog:beforeclose', () => {
 | 
			
		||||
          const toolbarBar = document.getElementById('toolbar-bar');
 | 
			
		||||
          if (toolbarBar) {
 | 
			
		||||
            toolbarBar.style.marginTop = '0';
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Add anti-flicker functionality.
 | 
			
		||||
      if (
 | 
			
		||||
        once('toolbarAntiFlicker', '#toolbar-administration', context).length
 | 
			
		||||
      ) {
 | 
			
		||||
        Drupal.toolbar.models.toolbarModel.on(
 | 
			
		||||
          'change:activeTab change:orientation change:isOriented change:isTrayToggleVisible change:offsets',
 | 
			
		||||
          function () {
 | 
			
		||||
            const userButton = document.querySelector('#toolbar-item-user');
 | 
			
		||||
            const hasActiveTab = !!$(this.get('activeTab')).length > 0;
 | 
			
		||||
            const previousToolbarState = sessionStorage.getItem(
 | 
			
		||||
              'Drupal.toolbar.toolbarState',
 | 
			
		||||
            )
 | 
			
		||||
              ? JSON.parse(
 | 
			
		||||
                  sessionStorage.getItem('Drupal.toolbar.toolbarState'),
 | 
			
		||||
                )
 | 
			
		||||
              : {};
 | 
			
		||||
            const toolbarState = {
 | 
			
		||||
              ...previousToolbarState,
 | 
			
		||||
              orientation:
 | 
			
		||||
                Drupal.toolbar.models.toolbarModel.get('orientation'),
 | 
			
		||||
              hasActiveTab,
 | 
			
		||||
              activeTabId: hasActiveTab ? this.get('activeTab').id : null,
 | 
			
		||||
              activeTray: $(this.get('activeTab')).attr('data-toolbar-tray'),
 | 
			
		||||
              isOriented: this.get('isOriented'),
 | 
			
		||||
              isFixed: this.get('isFixed'),
 | 
			
		||||
              userButtonMinWidth: userButton ? userButton.clientWidth : 0,
 | 
			
		||||
            };
 | 
			
		||||
            // Store toolbar UI state in session storage, so it can be accessed
 | 
			
		||||
            // by JavaScript that executes before the first paint.
 | 
			
		||||
            // @see core/modules/toolbar/js/toolbar.anti-flicker.js
 | 
			
		||||
            sessionStorage.setItem(
 | 
			
		||||
              'Drupal.toolbar.toolbarState',
 | 
			
		||||
              JSON.stringify(toolbarState),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Toolbar methods of Backbone objects.
 | 
			
		||||
   *
 | 
			
		||||
   * @namespace
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.toolbar = {
 | 
			
		||||
    /**
 | 
			
		||||
     * A hash of View instances.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {object.<string, Backbone.View>}
 | 
			
		||||
     */
 | 
			
		||||
    views: {},
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A hash of Model instances.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {object.<string, Backbone.Model>}
 | 
			
		||||
     */
 | 
			
		||||
    models: {},
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A hash of MediaQueryList objects tracked by the toolbar.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {object.<string, object>}
 | 
			
		||||
     */
 | 
			
		||||
    mql: {},
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a list of subtree menu elements.
 | 
			
		||||
     *
 | 
			
		||||
     * A deferred object that is resolved by an inlined JavaScript callback.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {jQuery.Deferred}
 | 
			
		||||
     *
 | 
			
		||||
     * @see toolbar_subtrees_jsonp().
 | 
			
		||||
     */
 | 
			
		||||
    setSubtrees: new $.Deferred(),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Respond to configured narrow media query changes.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Drupal.toolbar.ToolbarModel} model
 | 
			
		||||
     *   A toolbar model
 | 
			
		||||
     * @param {string} label
 | 
			
		||||
     *   Media query label.
 | 
			
		||||
     * @param {object} mql
 | 
			
		||||
     *   A MediaQueryList object.
 | 
			
		||||
     */
 | 
			
		||||
    mediaQueryChangeHandler(model, label, mql) {
 | 
			
		||||
      switch (label) {
 | 
			
		||||
        case 'toolbar.narrow':
 | 
			
		||||
          model.set({
 | 
			
		||||
            isOriented: mql.matches,
 | 
			
		||||
            isTrayToggleVisible: false,
 | 
			
		||||
          });
 | 
			
		||||
          // If the toolbar doesn't have an explicit orientation yet, or if the
 | 
			
		||||
          // narrow media query doesn't match then set the orientation to
 | 
			
		||||
          // vertical.
 | 
			
		||||
          if (!mql.matches || !model.get('orientation')) {
 | 
			
		||||
            model.set({ orientation: 'vertical' }, { validate: true });
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 'toolbar.standard':
 | 
			
		||||
          model.set({
 | 
			
		||||
            isFixed: mql.matches,
 | 
			
		||||
          });
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 'toolbar.wide':
 | 
			
		||||
          model.set(
 | 
			
		||||
            {
 | 
			
		||||
              orientation:
 | 
			
		||||
                mql.matches && !model.get('locked') ? 'horizontal' : 'vertical',
 | 
			
		||||
            },
 | 
			
		||||
            { validate: true },
 | 
			
		||||
          );
 | 
			
		||||
          // The tray orientation toggle visibility does not need to be
 | 
			
		||||
          // validated.
 | 
			
		||||
          model.set({
 | 
			
		||||
            isTrayToggleVisible: mql.matches,
 | 
			
		||||
          });
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A toggle is an interactive element often bound to a click handler.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   *   A string representing a DOM fragment.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.theme.toolbarOrientationToggle = function () {
 | 
			
		||||
    return (
 | 
			
		||||
      '<div class="toolbar-toggle-orientation"><div class="toolbar-lining">' +
 | 
			
		||||
      '<button class="toolbar-icon" type="button"></button>' +
 | 
			
		||||
      '</div></div>'
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Ajax command to set the toolbar subtrees.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Drupal.Ajax} ajax
 | 
			
		||||
   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
 | 
			
		||||
   * @param {object} response
 | 
			
		||||
   *   JSON response from the Ajax request.
 | 
			
		||||
   * @param {number} [status]
 | 
			
		||||
   *   XMLHttpRequest status.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.AjaxCommands.prototype.setToolbarSubtrees = function (
 | 
			
		||||
    ajax,
 | 
			
		||||
    response,
 | 
			
		||||
    status,
 | 
			
		||||
  ) {
 | 
			
		||||
    Drupal.toolbar.setSubtrees.resolve(response.subtrees);
 | 
			
		||||
  };
 | 
			
		||||
})(jQuery, Drupal, drupalSettings);
 | 
			
		||||
							
								
								
									
										256
									
								
								web/core/modules/toolbar/js/toolbar.menu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								web/core/modules/toolbar/js/toolbar.menu.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,256 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Builds a nested accordion widget.
 | 
			
		||||
 *
 | 
			
		||||
 * Invoke on an HTML list element with the jQuery plugin pattern.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * $('.toolbar-menu').drupalToolbarMenu();
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function ($, Drupal, drupalSettings) {
 | 
			
		||||
  /**
 | 
			
		||||
   * Store the open menu tray.
 | 
			
		||||
   */
 | 
			
		||||
  let activeItem = Drupal.url(drupalSettings.path.currentPath);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maintains active tab in horizontal orientation.
 | 
			
		||||
   */
 | 
			
		||||
  $.fn.drupalToolbarMenuHorizontal = function () {
 | 
			
		||||
    let currentPath = drupalSettings.path.currentPath;
 | 
			
		||||
    const menu = once('toolbar-menu-horizontal', this);
 | 
			
		||||
    if (menu.length) {
 | 
			
		||||
      const $menu = $(menu);
 | 
			
		||||
      if (activeItem) {
 | 
			
		||||
        const count = currentPath.split('/').length;
 | 
			
		||||
        // Find the deepest link with its parent info and start
 | 
			
		||||
        // marking active.
 | 
			
		||||
        for (let i = 0; i < count; i++) {
 | 
			
		||||
          const $menuItem = $menu.find(
 | 
			
		||||
            `a[data-drupal-link-system-path="${currentPath}"]`,
 | 
			
		||||
          );
 | 
			
		||||
          if ($menuItem.length !== 0) {
 | 
			
		||||
            $menuItem.closest('a').addClass('is-active');
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          const lastIndex = currentPath.lastIndexOf('/');
 | 
			
		||||
          currentPath = currentPath.slice(0, lastIndex);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  $.fn.drupalToolbarMenu = function () {
 | 
			
		||||
    const ui = {
 | 
			
		||||
      handleOpen: Drupal.t('Extend'),
 | 
			
		||||
      handleClose: Drupal.t('Collapse'),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggle the open/close state of a list is a menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {jQuery} $item
 | 
			
		||||
     *   The li item to be toggled.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} switcher
 | 
			
		||||
     *   A flag that forces toggleClass to add or a remove a class, rather than
 | 
			
		||||
     *   simply toggling its presence.
 | 
			
		||||
     */
 | 
			
		||||
    function toggleList($item, switcher) {
 | 
			
		||||
      const $toggle = $item
 | 
			
		||||
        .children('.toolbar-box')
 | 
			
		||||
        .children('.toolbar-handle');
 | 
			
		||||
      switcher =
 | 
			
		||||
        typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
 | 
			
		||||
      // Toggle the item open state.
 | 
			
		||||
      $item.toggleClass('open', switcher);
 | 
			
		||||
      // Twist the toggle.
 | 
			
		||||
      $toggle.toggleClass('open', switcher);
 | 
			
		||||
      // Adjust the toggle text.
 | 
			
		||||
      $toggle.find('.action').each((index, element) => {
 | 
			
		||||
        // Expand Structure, Collapse Structure.
 | 
			
		||||
        element.textContent = switcher ? ui.handleClose : ui.handleOpen;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle clicks from the disclosure button on an item with sub-items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} event
 | 
			
		||||
     *   A jQuery Event object.
 | 
			
		||||
     */
 | 
			
		||||
    function toggleClickHandler(event) {
 | 
			
		||||
      const $toggle = $(event.target);
 | 
			
		||||
      const $item = $toggle.closest('li');
 | 
			
		||||
      // Toggle the list item.
 | 
			
		||||
      toggleList($item);
 | 
			
		||||
      // Close open sibling menus.
 | 
			
		||||
      const $openItems = $item.siblings().filter('.open');
 | 
			
		||||
      toggleList($openItems, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle clicks from a menu item link.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} event
 | 
			
		||||
     *   A jQuery Event object.
 | 
			
		||||
     */
 | 
			
		||||
    function linkClickHandler(event) {
 | 
			
		||||
      // If the toolbar is positioned fixed (and therefore hiding content
 | 
			
		||||
      // underneath), then users expect clicks in the administration menu tray
 | 
			
		||||
      // to take them to that destination but for the menu tray to be closed
 | 
			
		||||
      // after clicking: otherwise the toolbar itself is obstructing the view
 | 
			
		||||
      // of the destination they chose.
 | 
			
		||||
      if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
 | 
			
		||||
        Drupal.toolbar.models.toolbarModel.set('activeTab', null);
 | 
			
		||||
      }
 | 
			
		||||
      // Stopping propagation to make sure that once a toolbar-box is clicked
 | 
			
		||||
      // (the whitespace part), the page is not redirected anymore.
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add markup to the menu elements.
 | 
			
		||||
     *
 | 
			
		||||
     * Items with sub-elements have a list toggle attached to them. Menu item
 | 
			
		||||
     * links and the corresponding list toggle are wrapped with in a div
 | 
			
		||||
     * classed with .toolbar-box. The .toolbar-box div provides a positioning
 | 
			
		||||
     * context for the item list toggle.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {jQuery} $menu
 | 
			
		||||
     *   The root of the menu to be initialized.
 | 
			
		||||
     */
 | 
			
		||||
    function initItems($menu) {
 | 
			
		||||
      const options = {
 | 
			
		||||
        class: 'toolbar-icon toolbar-handle',
 | 
			
		||||
        action: ui.handleOpen,
 | 
			
		||||
        text: '',
 | 
			
		||||
      };
 | 
			
		||||
      // Initialize items and their links.
 | 
			
		||||
      $menu.find('li > a').wrap('<div class="toolbar-box">');
 | 
			
		||||
      // Add a handle to each list item if it has a menu.
 | 
			
		||||
      $menu.find('li').each((index, element) => {
 | 
			
		||||
        const $item = $(element);
 | 
			
		||||
        if ($item.children('ul.toolbar-menu').length) {
 | 
			
		||||
          const $box = $item.children('.toolbar-box');
 | 
			
		||||
          const $link = $box.find('a');
 | 
			
		||||
          options.text = Drupal.t('@label', {
 | 
			
		||||
            '@label': $link.length ? $link[0].textContent : '',
 | 
			
		||||
          });
 | 
			
		||||
          $item
 | 
			
		||||
            .children('.toolbar-box')
 | 
			
		||||
            .append(
 | 
			
		||||
              $(Drupal.theme('toolbarMenuItemToggle', options))
 | 
			
		||||
                .hide()
 | 
			
		||||
                .fadeIn(150),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a level class to each list based on its depth in the menu.
 | 
			
		||||
     *
 | 
			
		||||
     * This function is called recursively on each sub level of lists elements
 | 
			
		||||
     * until the depth of the menu is exhausted.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {jQuery} $lists
 | 
			
		||||
     *   A jQuery object of ul elements.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} level
 | 
			
		||||
     *   The current level number to be assigned to the list elements.
 | 
			
		||||
     */
 | 
			
		||||
    function markListLevels($lists, level) {
 | 
			
		||||
      level = !level ? 1 : level;
 | 
			
		||||
      const $lis = $lists.children('li').addClass(`level-${level}`);
 | 
			
		||||
      $lists = $lis.children('ul');
 | 
			
		||||
      if ($lists.length) {
 | 
			
		||||
        markListLevels($lists, level + 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * On page load, open the active menu item.
 | 
			
		||||
     *
 | 
			
		||||
     * Marks the trail of the active link in the menu back to the root of the
 | 
			
		||||
     * menu with .menu-item--active-trail.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {jQuery} $menu
 | 
			
		||||
     *   The root of the menu.
 | 
			
		||||
     */
 | 
			
		||||
    function openActiveItem($menu) {
 | 
			
		||||
      let currentPath = drupalSettings.path.currentPath;
 | 
			
		||||
      const pathItem = $menu.find(`a[href="${window.location.pathname}"]`);
 | 
			
		||||
      if (pathItem.length && !activeItem) {
 | 
			
		||||
        activeItem = window.location.pathname;
 | 
			
		||||
      }
 | 
			
		||||
      if (activeItem) {
 | 
			
		||||
        const $activeItem = $menu
 | 
			
		||||
          .find(`a[href="${activeItem}"]`)
 | 
			
		||||
          .addClass('menu-item--active');
 | 
			
		||||
        if (pathItem.length === 0 && activeItem) {
 | 
			
		||||
          const count = currentPath.split('/').length;
 | 
			
		||||
          // Find the deepest link with its parent info and start
 | 
			
		||||
          // marking active.
 | 
			
		||||
          for (let i = 0; i < count; i++) {
 | 
			
		||||
            const $menuItem = $menu.find(
 | 
			
		||||
              `a[data-drupal-link-system-path="${currentPath}"]`,
 | 
			
		||||
            );
 | 
			
		||||
            if ($menuItem.length !== 0) {
 | 
			
		||||
              const $activeTrail = $menuItem
 | 
			
		||||
                .parentsUntil('.root', 'li')
 | 
			
		||||
                .addClass('menu-item--active-trail');
 | 
			
		||||
              toggleList($activeTrail, true);
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            const lastIndex = currentPath.lastIndexOf('/');
 | 
			
		||||
            currentPath = currentPath.slice(0, lastIndex);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          const $activeTrail = $activeItem
 | 
			
		||||
            .parentsUntil('.root', 'li')
 | 
			
		||||
            .addClass('menu-item--active-trail');
 | 
			
		||||
          toggleList($activeTrail, true);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return the jQuery object.
 | 
			
		||||
    return this.each(function (selector) {
 | 
			
		||||
      const menu = once('toolbar-menu-vertical', this);
 | 
			
		||||
      if (menu.length) {
 | 
			
		||||
        const $menu = $(menu);
 | 
			
		||||
        // Bind event handlers.
 | 
			
		||||
        $menu
 | 
			
		||||
          .on('click.toolbar', '.toolbar-box', toggleClickHandler)
 | 
			
		||||
          .on('click.toolbar', '.toolbar-box a', linkClickHandler);
 | 
			
		||||
 | 
			
		||||
        $menu.addClass('root');
 | 
			
		||||
        initItems($menu);
 | 
			
		||||
        markListLevels($menu);
 | 
			
		||||
        // Restore previous and active states.
 | 
			
		||||
        openActiveItem($menu);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A toggle is an interactive element often bound to a click handler.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {object} options
 | 
			
		||||
   *   Options for the button.
 | 
			
		||||
   * @param {string} options.class
 | 
			
		||||
   *   Class to set on the button.
 | 
			
		||||
   * @param {string} options.action
 | 
			
		||||
   *   Action for the button.
 | 
			
		||||
   * @param {string} options.text
 | 
			
		||||
   *   Used as label for the button.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   *   A string representing a DOM fragment.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.theme.toolbarMenuItemToggle = function (options) {
 | 
			
		||||
    return `<button class="${options.class}"><span class="action">${options.action}</span> <span class="label">${options.text}</span></button>`;
 | 
			
		||||
  };
 | 
			
		||||
})(jQuery, Drupal, drupalSettings);
 | 
			
		||||
							
								
								
									
										48
									
								
								web/core/modules/toolbar/js/views/BodyVisualView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								web/core/modules/toolbar/js/views/BodyVisualView.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * A Backbone view for the body element.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function ($, Drupal, Backbone) {
 | 
			
		||||
  Drupal.toolbar.BodyVisualView = Backbone.View.extend(
 | 
			
		||||
    /** @lends Drupal.toolbar.BodyVisualView# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * Adjusts the body element with the toolbar position and dimension changes.
 | 
			
		||||
       *
 | 
			
		||||
       * @constructs
 | 
			
		||||
       *
 | 
			
		||||
       * @augments Backbone.View
 | 
			
		||||
       */
 | 
			
		||||
      initialize() {
 | 
			
		||||
        this.listenTo(this.model, 'change:activeTray ', this.render);
 | 
			
		||||
        this.listenTo(
 | 
			
		||||
          this.model,
 | 
			
		||||
          'change:isFixed change:isViewportOverflowConstrained',
 | 
			
		||||
          this.isToolbarFixed,
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      isToolbarFixed() {
 | 
			
		||||
        // When the toolbar is fixed, it will not scroll with page scrolling.
 | 
			
		||||
        const isViewportOverflowConstrained = this.model.get(
 | 
			
		||||
          'isViewportOverflowConstrained',
 | 
			
		||||
        );
 | 
			
		||||
        $('body').toggleClass(
 | 
			
		||||
          'toolbar-fixed',
 | 
			
		||||
          isViewportOverflowConstrained || this.model.get('isFixed'),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * {@inheritdoc}
 | 
			
		||||
       */
 | 
			
		||||
      render() {
 | 
			
		||||
        $('body')
 | 
			
		||||
          // Toggle the toolbar-tray-open class on the body element. The class is
 | 
			
		||||
          // applied when a toolbar tray is active. Padding might be applied to
 | 
			
		||||
          // the body element to prevent the tray from overlapping content.
 | 
			
		||||
          .toggleClass('toolbar-tray-open', !!this.model.get('activeTray'));
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
})(jQuery, Drupal, Backbone);
 | 
			
		||||
							
								
								
									
										65
									
								
								web/core/modules/toolbar/js/views/MenuVisualView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								web/core/modules/toolbar/js/views/MenuVisualView.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * A Backbone view for the collapsible menus.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function ($, Backbone, Drupal) {
 | 
			
		||||
  Drupal.toolbar.MenuVisualView = Backbone.View.extend(
 | 
			
		||||
    /** @lends Drupal.toolbar.MenuVisualView# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * Backbone View for collapsible menus.
 | 
			
		||||
       *
 | 
			
		||||
       * @constructs
 | 
			
		||||
       *
 | 
			
		||||
       * @augments Backbone.View
 | 
			
		||||
       */
 | 
			
		||||
      initialize() {
 | 
			
		||||
        this.listenTo(this.model, 'change:subtrees', this.render);
 | 
			
		||||
 | 
			
		||||
        // Render the view immediately on initialization.
 | 
			
		||||
        this.render();
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * {@inheritdoc}
 | 
			
		||||
       */
 | 
			
		||||
      render() {
 | 
			
		||||
        this.renderVertical();
 | 
			
		||||
        this.renderHorizontal();
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Renders the toolbar menu in horizontal mode.
 | 
			
		||||
       */
 | 
			
		||||
      renderHorizontal() {
 | 
			
		||||
        // Render horizontal.
 | 
			
		||||
        if ('drupalToolbarMenu' in $.fn) {
 | 
			
		||||
          this.$el.children('.toolbar-menu').drupalToolbarMenuHorizontal();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Renders the toolbar menu in vertical mode.
 | 
			
		||||
       */
 | 
			
		||||
      renderVertical() {
 | 
			
		||||
        const subtrees = this.model.get('subtrees');
 | 
			
		||||
 | 
			
		||||
        // Rendering the vertical menu depends on the subtrees.
 | 
			
		||||
        if (!this.model.get('subtrees')) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Add subtrees.
 | 
			
		||||
        Object.keys(subtrees || {}).forEach((id) => {
 | 
			
		||||
          $(
 | 
			
		||||
            once('toolbar-subtrees', this.$el.find(`#toolbar-link-${id}`)),
 | 
			
		||||
          ).after(subtrees[id]);
 | 
			
		||||
        });
 | 
			
		||||
        // Render the main menu as a nested, collapsible accordion.
 | 
			
		||||
        if ('drupalToolbarMenu' in $.fn) {
 | 
			
		||||
          this.$el.children('.toolbar-menu').drupalToolbarMenu();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
})(jQuery, Backbone, Drupal);
 | 
			
		||||
							
								
								
									
										80
									
								
								web/core/modules/toolbar/js/views/ToolbarAuralView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								web/core/modules/toolbar/js/views/ToolbarAuralView.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * A Backbone view for the aural feedback of the toolbar.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function (Backbone, Drupal) {
 | 
			
		||||
  Drupal.toolbar.ToolbarAuralView = Backbone.View.extend(
 | 
			
		||||
    /** @lends Drupal.toolbar.ToolbarAuralView# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * Backbone view for the aural feedback of the toolbar.
 | 
			
		||||
       *
 | 
			
		||||
       * @constructs
 | 
			
		||||
       *
 | 
			
		||||
       * @augments Backbone.View
 | 
			
		||||
       *
 | 
			
		||||
       * @param {object} options
 | 
			
		||||
       *   Options for the view.
 | 
			
		||||
       * @param {object} options.strings
 | 
			
		||||
       *   Various strings to use in the view.
 | 
			
		||||
       */
 | 
			
		||||
      initialize(options) {
 | 
			
		||||
        this.strings = options.strings;
 | 
			
		||||
 | 
			
		||||
        this.listenTo(
 | 
			
		||||
          this.model,
 | 
			
		||||
          'change:orientation',
 | 
			
		||||
          this.onOrientationChange,
 | 
			
		||||
        );
 | 
			
		||||
        this.listenTo(this.model, 'change:activeTray', this.onActiveTrayChange);
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Announces an orientation change.
 | 
			
		||||
       *
 | 
			
		||||
       * @param {Drupal.toolbar.ToolbarModel} model
 | 
			
		||||
       *   The toolbar model in question.
 | 
			
		||||
       * @param {string} orientation
 | 
			
		||||
       *   The new value of the orientation attribute in the model.
 | 
			
		||||
       */
 | 
			
		||||
      onOrientationChange(model, orientation) {
 | 
			
		||||
        Drupal.announce(
 | 
			
		||||
          Drupal.t('Tray orientation changed to @orientation.', {
 | 
			
		||||
            '@orientation': orientation,
 | 
			
		||||
          }),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * Announces a changed active tray.
 | 
			
		||||
       *
 | 
			
		||||
       * @param {Drupal.toolbar.ToolbarModel} model
 | 
			
		||||
       *   The toolbar model in question.
 | 
			
		||||
       * @param {HTMLElement} tray
 | 
			
		||||
       *   The new value of the tray attribute in the model.
 | 
			
		||||
       */
 | 
			
		||||
      onActiveTrayChange(model, tray) {
 | 
			
		||||
        const relevantTray =
 | 
			
		||||
          tray === null ? model.previous('activeTray') : tray;
 | 
			
		||||
        // Current activeTray and previous activeTray are empty, no state change
 | 
			
		||||
        // to announce.
 | 
			
		||||
        if (!relevantTray) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        const action = tray === null ? Drupal.t('closed') : Drupal.t('opened');
 | 
			
		||||
        const trayNameElement =
 | 
			
		||||
          relevantTray.querySelector('.toolbar-tray-name');
 | 
			
		||||
        let text;
 | 
			
		||||
        if (trayNameElement !== null) {
 | 
			
		||||
          text = Drupal.t('Tray "@tray" @action.', {
 | 
			
		||||
            '@tray': trayNameElement.textContent,
 | 
			
		||||
            '@action': action,
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          text = Drupal.t('Tray @action.', { '@action': action });
 | 
			
		||||
        }
 | 
			
		||||
        Drupal.announce(text);
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
})(Backbone, Drupal);
 | 
			
		||||
							
								
								
									
										396
									
								
								web/core/modules/toolbar/js/views/ToolbarVisualView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										396
									
								
								web/core/modules/toolbar/js/views/ToolbarVisualView.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,396 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @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# */ {
 | 
			
		||||
      /**
 | 
			
		||||
       * 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,
 | 
			
		||||
        };
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * 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,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Add the tray orientation toggles, but only if there is a menu.
 | 
			
		||||
        this.$el
 | 
			
		||||
          .find('.toolbar-tray .toolbar-lining')
 | 
			
		||||
          .has('.toolbar-menu')
 | 
			
		||||
          .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');
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * 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')[0].style.paddingTop = `${this.model.get('height')}px`;
 | 
			
		||||
        $('html')[0].style.scrollPaddingTop = `${this.model.get('height')}px`;
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * {@inheritdoc}
 | 
			
		||||
       *
 | 
			
		||||
       * @return {Drupal.toolbar.ToolbarVisualView}
 | 
			
		||||
       *   The `ToolbarVisualView` instance.
 | 
			
		||||
       */
 | 
			
		||||
      render() {
 | 
			
		||||
        this.updateTabs();
 | 
			
		||||
        this.updateTrayOrientation();
 | 
			
		||||
        this.updateBarAttributes();
 | 
			
		||||
 | 
			
		||||
        $('[data-toolbar-anti-flicker-loading]').remove();
 | 
			
		||||
        $('html').removeClass([
 | 
			
		||||
          'toolbar-loading',
 | 
			
		||||
          'toolbar-horizontal',
 | 
			
		||||
          'toolbar-vertical',
 | 
			
		||||
          'toolbar-tray-open',
 | 
			
		||||
          'toolbar-fixed',
 | 
			
		||||
          'toolbar-oriented',
 | 
			
		||||
          'toolbar-anti-flicker',
 | 
			
		||||
        ]);
 | 
			
		||||
        $('body').removeClass('toolbar-loading');
 | 
			
		||||
 | 
			
		||||
        // 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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * 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.currentTarget.hasAttribute('data-toolbar-tray')) {
 | 
			
		||||
          const activeTab = this.model.get('activeTab');
 | 
			
		||||
          const clickedTab = event.currentTarget;
 | 
			
		||||
 | 
			
		||||
          // Set the event target as the active item if it is not already.
 | 
			
		||||
          this.model.set(
 | 
			
		||||
            'activeTab',
 | 
			
		||||
            !activeTab || clickedTab !== activeTab ? clickedTab : null,
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          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,
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        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')
 | 
			
		||||
          .attr('aria-pressed', false);
 | 
			
		||||
        // Deactivate the previous tray.
 | 
			
		||||
        $(this.model.previous('activeTray')).removeClass('is-active');
 | 
			
		||||
 | 
			
		||||
        // The stored active tab is removed as updateTabs() can be called when
 | 
			
		||||
        // a tray is explicitly closed, thus not replaced with a new active tab.
 | 
			
		||||
        localStorage.removeItem('Drupal.toolbar.activeTabID');
 | 
			
		||||
        // Activate the selected tab.
 | 
			
		||||
        if ($tab.length > 0) {
 | 
			
		||||
          $tab
 | 
			
		||||
            .addClass('is-active')
 | 
			
		||||
            // Mark the tab as pressed.
 | 
			
		||||
            .attr('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');
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /**
 | 
			
		||||
       * 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');
 | 
			
		||||
 | 
			
		||||
        // 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');
 | 
			
		||||
 | 
			
		||||
        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'));
 | 
			
		||||
        const $orientationToggleButton = $orientationToggle.find('button');
 | 
			
		||||
        $orientationToggleButton[0].value = antiOrientation;
 | 
			
		||||
        $orientationToggleButton
 | 
			
		||||
          .attr('title', this.strings[antiOrientation])
 | 
			
		||||
          .removeClass(iconClass)
 | 
			
		||||
          .addClass(iconAntiClass);
 | 
			
		||||
        $orientationToggleButton[0].textContent = this.strings[antiOrientation];
 | 
			
		||||
 | 
			
		||||
        // 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);
 | 
			
		||||
          }
 | 
			
		||||
          // 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);
 | 
			
		||||
		Reference in New Issue
	
	Block a user