toolbar.menu.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /**
  2. * @file
  3. * Builds a nested accordion widget.
  4. *
  5. * Invoke on an HTML list element with the jQuery plugin pattern.
  6. *
  7. * @example
  8. * $('.toolbar-menu').drupalToolbarMenu();
  9. */
  10. (function ($, Drupal, drupalSettings) {
  11. 'use strict';
  12. /**
  13. * Store the open menu tray.
  14. */
  15. var activeItem = Drupal.url(drupalSettings.path.currentPath);
  16. $.fn.drupalToolbarMenu = function () {
  17. var ui = {
  18. handleOpen: Drupal.t('Extend'),
  19. handleClose: Drupal.t('Collapse')
  20. };
  21. /**
  22. * Handle clicks from the disclosure button on an item with sub-items.
  23. *
  24. * @param {Object} event
  25. * A jQuery Event object.
  26. */
  27. function toggleClickHandler(event) {
  28. var $toggle = $(event.target);
  29. var $item = $toggle.closest('li');
  30. // Toggle the list item.
  31. toggleList($item);
  32. // Close open sibling menus.
  33. var $openItems = $item.siblings().filter('.open');
  34. toggleList($openItems, false);
  35. }
  36. /**
  37. * Handle clicks from a menu item link.
  38. *
  39. * @param {Object} event
  40. * A jQuery Event object.
  41. */
  42. function linkClickHandler(event) {
  43. // If the toolbar is positioned fixed (and therefore hiding content
  44. // underneath), then users expect clicks in the administration menu tray
  45. // to take them to that destination but for the menu tray to be closed
  46. // after clicking: otherwise the toolbar itself is obstructing the view
  47. // of the destination they chose.
  48. if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
  49. Drupal.toolbar.models.toolbarModel.set('activeTab', null);
  50. }
  51. // Stopping propagation to make sure that once a toolbar-box is clicked
  52. // (the whitespace part), the page is not redirected anymore.
  53. event.stopPropagation();
  54. }
  55. /**
  56. * Toggle the open/close state of a list is a menu.
  57. *
  58. * @param {jQuery} $item
  59. * The li item to be toggled.
  60. *
  61. * @param {Boolean} switcher
  62. * A flag that forces toggleClass to add or a remove a class, rather than
  63. * simply toggling its presence.
  64. */
  65. function toggleList($item, switcher) {
  66. var $toggle = $item.children('.toolbar-box').children('.toolbar-handle');
  67. switcher = (typeof switcher !== 'undefined') ? switcher : !$item.hasClass('open');
  68. // Toggle the item open state.
  69. $item.toggleClass('open', switcher);
  70. // Twist the toggle.
  71. $toggle.toggleClass('open', switcher);
  72. // Adjust the toggle text.
  73. $toggle
  74. .find('.action')
  75. // Expand Structure, Collapse Structure.
  76. .text((switcher) ? ui.handleClose : ui.handleOpen);
  77. }
  78. /**
  79. * Add markup to the menu elements.
  80. *
  81. * Items with sub-elements have a list toggle attached to them. Menu item
  82. * links and the corresponding list toggle are wrapped with in a div
  83. * classed with .toolbar-box. The .toolbar-box div provides a positioning
  84. * context for the item list toggle.
  85. *
  86. * @param {jQuery} $menu
  87. * The root of the menu to be initialized.
  88. */
  89. function initItems($menu) {
  90. var options = {
  91. class: 'toolbar-icon toolbar-handle',
  92. action: ui.handleOpen,
  93. text: ''
  94. };
  95. // Initialize items and their links.
  96. $menu.find('li > a').wrap('<div class="toolbar-box">');
  97. // Add a handle to each list item if it has a menu.
  98. $menu.find('li').each(function (index, element) {
  99. var $item = $(element);
  100. if ($item.children('ul.toolbar-menu').length) {
  101. var $box = $item.children('.toolbar-box');
  102. options.text = Drupal.t('@label', {'@label': $box.find('a').text()});
  103. $item.children('.toolbar-box')
  104. .append(Drupal.theme('toolbarMenuItemToggle', options));
  105. }
  106. });
  107. }
  108. /**
  109. * Adds a level class to each list based on its depth in the menu.
  110. *
  111. * This function is called recursively on each sub level of lists elements
  112. * until the depth of the menu is exhausted.
  113. *
  114. * @param {jQuery} $lists
  115. * A jQuery object of ul elements.
  116. *
  117. * @param {number} level
  118. * The current level number to be assigned to the list elements.
  119. */
  120. function markListLevels($lists, level) {
  121. level = (!level) ? 1 : level;
  122. var $lis = $lists.children('li').addClass('level-' + level);
  123. $lists = $lis.children('ul');
  124. if ($lists.length) {
  125. markListLevels($lists, level + 1);
  126. }
  127. }
  128. /**
  129. * On page load, open the active menu item.
  130. *
  131. * Marks the trail of the active link in the menu back to the root of the
  132. * menu with .menu-item--active-trail.
  133. *
  134. * @param {jQuery} $menu
  135. * The root of the menu.
  136. */
  137. function openActiveItem($menu) {
  138. var pathItem = $menu.find('a[href="' + location.pathname + '"]');
  139. if (pathItem.length && !activeItem) {
  140. activeItem = location.pathname;
  141. }
  142. if (activeItem) {
  143. var $activeItem = $menu.find('a[href="' + activeItem + '"]').addClass('menu-item--active');
  144. var $activeTrail = $activeItem.parentsUntil('.root', 'li').addClass('menu-item--active-trail');
  145. toggleList($activeTrail, true);
  146. }
  147. }
  148. // Return the jQuery object.
  149. return this.each(function (selector) {
  150. var $menu = $(this).once('toolbar-menu');
  151. if ($menu.length) {
  152. // Bind event handlers.
  153. $menu
  154. .on('click.toolbar', '.toolbar-box', toggleClickHandler)
  155. .on('click.toolbar', '.toolbar-box a', linkClickHandler);
  156. $menu.addClass('root');
  157. initItems($menu);
  158. markListLevels($menu);
  159. // Restore previous and active states.
  160. openActiveItem($menu);
  161. }
  162. });
  163. };
  164. /**
  165. * A toggle is an interactive element often bound to a click handler.
  166. *
  167. * @param {object} options
  168. * Options for the button.
  169. * @param {string} options.class
  170. * Class to set on the button.
  171. * @param {string} options.action
  172. * Action for the button.
  173. * @param {string} options.text
  174. * Used as label for the button.
  175. *
  176. * @return {string}
  177. * A string representing a DOM fragment.
  178. */
  179. Drupal.theme.toolbarMenuItemToggle = function (options) {
  180. return '<button class="' + options['class'] + '"><span class="action">' + options.action + '</span><span class="label">' + options.text + '</span></button>';
  181. };
  182. }(jQuery, Drupal, drupalSettings));