PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/OAS.Web/dist/js/plugins/foundation.accordionMenu.js

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