156 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @file
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Sidebar component.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Only few common things. Like close all popovers when one is opened.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @type {Drupal~behavior}
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @prop {Drupal~behaviorAttach} attach
							 | 
						||
| 
								 | 
							
								 *   Attaches the behavior to the `.admin-toolbar` element.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								(
							 | 
						||
| 
								 | 
							
								  (Drupal, once) => {
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Drupal behaviors object.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @type {Drupal~behaviors}
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Drupal.behaviors.navigation = {
							 | 
						||
| 
								 | 
							
								      attach(context) {
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Sidebar element with the `.admin-toolbar` class.
							 | 
						||
| 
								 | 
							
								         *
							 | 
						||
| 
								 | 
							
								         * @type {HTMLElement}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        once('navigation', '.admin-toolbar', context).forEach((sidebar) => {
							 | 
						||
| 
								 | 
							
								          const backButton = sidebar.querySelector(
							 | 
						||
| 
								 | 
							
								            '[data-toolbar-back-control]',
							 | 
						||
| 
								 | 
							
								          );
							 | 
						||
| 
								 | 
							
								          if (!backButton) {
							 | 
						||
| 
								 | 
							
								            // We're in layout editing mode and the .admin-toolbar we have in
							 | 
						||
| 
								 | 
							
								            // scope here is the empty one that only exists to leave space for
							 | 
						||
| 
								 | 
							
								            // the one added by layout builder. We need to use an empty
							 | 
						||
| 
								 | 
							
								            // .admin-toolbar element because the css uses the adjacent
							 | 
						||
| 
								 | 
							
								            // sibling selector.
							 | 
						||
| 
								 | 
							
								            // @see \navigation_page_top();
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          /**
							 | 
						||
| 
								 | 
							
								           * All menu triggers.
							 | 
						||
| 
								 | 
							
								           *
							 | 
						||
| 
								 | 
							
								           * @type {NodeList}
							 | 
						||
| 
								 | 
							
								           */
							 | 
						||
| 
								 | 
							
								          const buttons = sidebar.querySelectorAll(
							 | 
						||
| 
								 | 
							
								            '[data-toolbar-menu-trigger]',
							 | 
						||
| 
								 | 
							
								          );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          /**
							 | 
						||
| 
								 | 
							
								           * All popovers and tooltip triggers.
							 | 
						||
| 
								 | 
							
								           *
							 | 
						||
| 
								 | 
							
								           * @type {NodeList}
							 | 
						||
| 
								 | 
							
								           */
							 | 
						||
| 
								 | 
							
								          // const popovers = sidebar.querySelectorAll('[data-toolbar-popover]');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          /**
							 | 
						||
| 
								 | 
							
								           * NodeList of all tooltip elements.
							 | 
						||
| 
								 | 
							
								           *
							 | 
						||
| 
								 | 
							
								           * @type {NodeList}
							 | 
						||
| 
								 | 
							
								           */
							 | 
						||
| 
								 | 
							
								          const tooltips = sidebar.querySelectorAll('[data-drupal-tooltip]');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          const closeButtons = () => {
							 | 
						||
| 
								 | 
							
								            buttons.forEach((button) => {
							 | 
						||
| 
								 | 
							
								              button.dispatchEvent(
							 | 
						||
| 
								 | 
							
								                new CustomEvent('toolbar-menu-set-toggle', {
							 | 
						||
| 
								 | 
							
								                  detail: {
							 | 
						||
| 
								 | 
							
								                    state: false,
							 | 
						||
| 
								 | 
							
								                  },
							 | 
						||
| 
								 | 
							
								                }),
							 | 
						||
| 
								 | 
							
								              );
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          const closePopovers = (current = false) => {
							 | 
						||
| 
								 | 
							
								            // TODO: Find way to use popovers variable.
							 | 
						||
| 
								 | 
							
								            // This change needed because BigPipe replaces user popover.
							 | 
						||
| 
								 | 
							
								            sidebar
							 | 
						||
| 
								 | 
							
								              .querySelectorAll('[data-toolbar-popover]')
							 | 
						||
| 
								 | 
							
								              .forEach((popover) => {
							 | 
						||
| 
								 | 
							
								                if (
							 | 
						||
| 
								 | 
							
								                  current &&
							 | 
						||
| 
								 | 
							
								                  current instanceof Element &&
							 | 
						||
| 
								 | 
							
								                  popover.isEqualNode(current)
							 | 
						||
| 
								 | 
							
								                ) {
							 | 
						||
| 
								 | 
							
								                  return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                popover.dispatchEvent(
							 | 
						||
| 
								 | 
							
								                  new CustomEvent('toolbar-popover-close', {}),
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // Add click event listeners to all buttons and then contains the callback
							 | 
						||
| 
								 | 
							
								          // to expand / collapse the button's menus.
							 | 
						||
| 
								 | 
							
								          sidebar.addEventListener('click', (e) => {
							 | 
						||
| 
								 | 
							
								            if (e.target.matches('button, button *')) {
							 | 
						||
| 
								 | 
							
								              e.target.closest('button').focus();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // We want to close all popovers when we close sidebar.
							 | 
						||
| 
								 | 
							
								          sidebar.addEventListener('toggle-admin-toolbar-content', (e) => {
							 | 
						||
| 
								 | 
							
								            if (!e.detail.state) {
							 | 
						||
| 
								 | 
							
								              closePopovers();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // When any popover opened we close all others.
							 | 
						||
| 
								 | 
							
								          sidebar.addEventListener('toolbar-popover-toggled', (e) => {
							 | 
						||
| 
								 | 
							
								            if (e.detail.state) {
							 | 
						||
| 
								 | 
							
								              closeButtons();
							 | 
						||
| 
								 | 
							
								              closePopovers(e.target);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // When any menu opened we close all others.
							 | 
						||
| 
								 | 
							
								          sidebar.addEventListener('toolbar-menu-toggled', (e) => {
							 | 
						||
| 
								 | 
							
								            if (e.detail.state) {
							 | 
						||
| 
								 | 
							
								              // We want to close buttons on when new opened only if they are on same level.
							 | 
						||
| 
								 | 
							
								              const targetLevel = e.detail.level;
							 | 
						||
| 
								 | 
							
								              buttons.forEach((button) => {
							 | 
						||
| 
								 | 
							
								                const buttonLevel = button.dataset.toolbarMenuTrigger;
							 | 
						||
| 
								 | 
							
								                if (
							 | 
						||
| 
								 | 
							
								                  !button.isEqualNode(e.target) &&
							 | 
						||
| 
								 | 
							
								                  +buttonLevel === +targetLevel
							 | 
						||
| 
								 | 
							
								                ) {
							 | 
						||
| 
								 | 
							
								                  button.dispatchEvent(
							 | 
						||
| 
								 | 
							
								                    new CustomEvent('toolbar-menu-set-toggle', {
							 | 
						||
| 
								 | 
							
								                      detail: {
							 | 
						||
| 
								 | 
							
								                        state: false,
							 | 
						||
| 
								 | 
							
								                      },
							 | 
						||
| 
								 | 
							
								                    }),
							 | 
						||
| 
								 | 
							
								                  );
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								          backButton.addEventListener('click', closePopovers);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // Tooltips triggered on hover and focus so add an extra event listener
							 | 
						||
| 
								 | 
							
								          // to close all popovers.
							 | 
						||
| 
								 | 
							
								          tooltips.forEach((tooltip) => {
							 | 
						||
| 
								 | 
							
								            ['mouseover', 'focus'].forEach((e) => {
							 | 
						||
| 
								 | 
							
								              tooltip.addEventListener(e, closePopovers);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								)(Drupal, once);
							 |