PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/files/foundation/6.1.2/js/foundation.accordionMenu.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 259 lines | 173 code | 23 blank | 63 comment | 20 complexity | 83e80e3c7257b79318ee783ea25761a1 MD5 | raw file
  1. /**
  2. * AccordionMenu module.
  3. * @module foundation.accordionMenu
  4. * @requires foundation.util.keyboard
  5. * @requires foundation.util.motion
  6. * @requires foundation.util.nest
  7. */
  8. !function($) {
  9. 'use strict';
  10. /**
  11. * Creates a new instance of an accordion menu.
  12. * @class
  13. * @fires AccordionMenu#init
  14. * @param {jQuery} element - jQuery object to make into an accordion menu.
  15. * @param {Object} options - Overrides to the default plugin settings.
  16. */
  17. function AccordionMenu(element, options) {
  18. this.$element = element;
  19. this.options = $.extend({}, AccordionMenu.defaults, this.$element.data(), options);
  20. Foundation.Nest.Feather(this.$element, 'accordion');
  21. this._init();
  22. Foundation.registerPlugin(this, 'AccordionMenu');
  23. Foundation.Keyboard.register('AccordionMenu', {
  24. 'ENTER': 'toggle',
  25. 'SPACE': 'toggle',
  26. 'ARROW_RIGHT': 'open',
  27. 'ARROW_UP': 'up',
  28. 'ARROW_DOWN': 'down',
  29. 'ARROW_LEFT': 'close',
  30. 'ESCAPE': 'closeAll',
  31. 'TAB': 'down',
  32. 'SHIFT_TAB': 'up'
  33. });
  34. }
  35. AccordionMenu.defaults = {
  36. /**
  37. * Amount of time to animate the opening of a submenu in ms.
  38. * @option
  39. * @example 250
  40. */
  41. slideSpeed: 250,
  42. /**
  43. * Allow the menu to have multiple open panes.
  44. * @option
  45. * @example true
  46. */
  47. multiOpen: true
  48. };
  49. /**
  50. * Initializes the accordion menu by hiding all nested menus.
  51. * @private
  52. */
  53. AccordionMenu.prototype._init = function() {
  54. this.$element.find('[data-submenu]').not('.is-active').slideUp(0);//.find('a').css('padding-left', '1rem');
  55. this.$element.attr({
  56. 'role': 'tablist',
  57. 'aria-multiselectable': this.options.multiOpen
  58. });
  59. this.$menuLinks = this.$element.find('.is-accordion-submenu-parent');
  60. this.$menuLinks.each(function(){
  61. var linkId = this.id || Foundation.GetYoDigits(6, 'acc-menu-link'),
  62. $elem = $(this),
  63. $sub = $elem.children('[data-submenu]'),
  64. subId = $sub[0].id || Foundation.GetYoDigits(6, 'acc-menu'),
  65. isActive = $sub.hasClass('is-active');
  66. $elem.attr({
  67. 'aria-controls': subId,
  68. 'aria-expanded': isActive,
  69. 'role': 'tab',
  70. 'id': linkId
  71. });
  72. $sub.attr({
  73. 'aria-labelledby': linkId,
  74. 'aria-hidden': !isActive,
  75. 'role': 'tabpanel',
  76. 'id': subId
  77. });
  78. });
  79. var initPanes = this.$element.find('.is-active');
  80. if(initPanes.length){
  81. var _this = this;
  82. initPanes.each(function(){
  83. _this.down($(this));
  84. });
  85. }
  86. this._events();
  87. };
  88. /**
  89. * Adds event handlers for items within the menu.
  90. * @private
  91. */
  92. AccordionMenu.prototype._events = function() {
  93. var _this = this;
  94. this.$element.find('li').each(function() {
  95. var $submenu = $(this).children('[data-submenu]');
  96. if ($submenu.length) {
  97. $(this).children('a').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function(e) {
  98. e.preventDefault();
  99. _this.toggle($submenu);
  100. });
  101. }
  102. }).on('keydown.zf.accordionmenu', function(e){
  103. var $element = $(this),
  104. $elements = $element.parent('ul').children('li'),
  105. $prevElement,
  106. $nextElement,
  107. $target = $element.children('[data-submenu]');
  108. $elements.each(function(i) {
  109. if ($(this).is($element)) {
  110. $prevElement = $elements.eq(Math.max(0, i-1));
  111. $nextElement = $elements.eq(Math.min(i+1, $elements.length-1));
  112. if ($(this).children('[data-submenu]:visible').length) { // has open sub menu
  113. $nextElement = $element.find('li:first-child');
  114. }
  115. if ($(this).is(':first-child')) { // is first element of sub menu
  116. $prevElement = $element.parents('li').first();
  117. } else if ($prevElement.children('[data-submenu]:visible').length) { // if previous element has open sub menu
  118. $prevElement = $prevElement.find('li:last-child');
  119. }
  120. if ($(this).is(':last-child')) { // is last element of sub menu
  121. $nextElement = $element.parents('li').first().next('li');
  122. }
  123. return;
  124. }
  125. });
  126. Foundation.Keyboard.handleKey(e, 'AccordionMenu', {
  127. open: function() {
  128. if ($target.is(':hidden')) {
  129. _this.down($target);
  130. $target.find('li').first().focus();
  131. }
  132. },
  133. close: function() {
  134. if ($target.length && !$target.is(':hidden')) { // close active sub of this item
  135. _this.up($target);
  136. } else if ($element.parent('[data-submenu]').length) { // close currently open sub
  137. _this.up($element.parent('[data-submenu]'));
  138. $element.parents('li').first().focus();
  139. }
  140. },
  141. up: function() {
  142. $prevElement.focus();
  143. },
  144. down: function() {
  145. $nextElement.focus();
  146. },
  147. toggle: function() {
  148. if ($element.children('[data-submenu]').length) {
  149. _this.toggle($element.children('[data-submenu]'));
  150. }
  151. },
  152. closeAll: function() {
  153. _this.hideAll();
  154. },
  155. handled: function() {
  156. e.preventDefault();
  157. e.stopImmediatePropagation();
  158. }
  159. });
  160. });//.attr('tabindex', 0);
  161. };
  162. /**
  163. * Closes all panes of the menu.
  164. * @function
  165. */
  166. AccordionMenu.prototype.hideAll = function(){
  167. this.$element.find('[data-submenu]').slideUp(this.options.slideSpeed);
  168. };
  169. /**
  170. * Toggles the open/close state of a submenu.
  171. * @function
  172. * @param {jQuery} $target - the submenu to toggle
  173. */
  174. AccordionMenu.prototype.toggle = function($target){
  175. if(!$target.is(':animated')) {
  176. if (!$target.is(':hidden')) {
  177. this.up($target);
  178. }
  179. else {
  180. this.down($target);
  181. }
  182. }
  183. };
  184. /**
  185. * Opens the sub-menu defined by `$target`.
  186. * @param {jQuery} $target - Sub-menu to open.
  187. * @fires AccordionMenu#down
  188. */
  189. AccordionMenu.prototype.down = function($target) {
  190. var _this = this;
  191. if(!this.options.multiOpen){
  192. this.up(this.$element.find('.is-active').not($target.parentsUntil(this.$element).add($target)));
  193. }
  194. $target.addClass('is-active').attr({'aria-hidden': false})
  195. .parent('.is-accordion-submenu-parent').attr({'aria-expanded': true});
  196. Foundation.Move(this.options.slideSpeed, $target, function(){
  197. $target.slideDown(_this.options.slideSpeed, function () {
  198. /**
  199. * Fires when the menu is done opening.
  200. * @event AccordionMenu#down
  201. */
  202. _this.$element.trigger('down.zf.accordionMenu', [$target]);
  203. });
  204. });
  205. };
  206. /**
  207. * Closes the sub-menu defined by `$target`. All sub-menus inside the target will be closed as well.
  208. * @param {jQuery} $target - Sub-menu to close.
  209. * @fires AccordionMenu#up
  210. */
  211. AccordionMenu.prototype.up = function($target) {
  212. var _this = this;
  213. Foundation.Move(this.options.slideSpeed, $target, function(){
  214. $target.slideUp(_this.options.slideSpeed, function () {
  215. /**
  216. * Fires when the menu is done collapsing up.
  217. * @event AccordionMenu#up
  218. */
  219. _this.$element.trigger('up.zf.accordionMenu', [$target]);
  220. });
  221. });
  222. var $menus = $target.find('[data-submenu]').slideUp(0).addBack().attr('aria-hidden', true);
  223. $menus.parent('.is-accordion-submenu-parent').attr('aria-expanded', false);
  224. };
  225. /**
  226. * Destroys an instance of accordion menu.
  227. * @fires AccordionMenu#destroyed
  228. */
  229. AccordionMenu.prototype.destroy = function(){
  230. this.$element.find('[data-submenu]').slideDown(0).css('display', '');
  231. this.$element.find('a').off('click.zf.accordionMenu');
  232. Foundation.Nest.Burn(this.$element, 'accordion');
  233. Foundation.unregisterPlugin(this);
  234. };
  235. Foundation.plugin(AccordionMenu, 'AccordionMenu');
  236. }(jQuery, window.Foundation);