foundation.responsiveMenu.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. 'use strict';
  2. import $ from 'jquery';
  3. import { MediaQuery } from './foundation.util.mediaQuery';
  4. import { GetYoDigits } from './foundation.core.utils';
  5. import { Plugin } from './foundation.core.plugin';
  6. import { DropdownMenu } from './foundation.dropdownMenu';
  7. import { Drilldown } from './foundation.drilldown';
  8. import { AccordionMenu } from './foundation.accordionMenu';
  9. let MenuPlugins = {
  10. dropdown: {
  11. cssClass: 'dropdown',
  12. plugin: DropdownMenu
  13. },
  14. drilldown: {
  15. cssClass: 'drilldown',
  16. plugin: Drilldown
  17. },
  18. accordion: {
  19. cssClass: 'accordion-menu',
  20. plugin: AccordionMenu
  21. }
  22. };
  23. // import "foundation.util.triggers.js";
  24. /**
  25. * ResponsiveMenu module.
  26. * @module foundation.responsiveMenu
  27. * @requires foundation.util.triggers
  28. * @requires foundation.util.mediaQuery
  29. */
  30. class ResponsiveMenu extends Plugin {
  31. /**
  32. * Creates a new instance of a responsive menu.
  33. * @class
  34. * @name ResponsiveMenu
  35. * @fires ResponsiveMenu#init
  36. * @param {jQuery} element - jQuery object to make into a dropdown menu.
  37. * @param {Object} options - Overrides to the default plugin settings.
  38. */
  39. _setup(element, options) {
  40. this.$element = $(element);
  41. this.rules = this.$element.data('responsive-menu');
  42. this.currentMq = null;
  43. this.currentPlugin = null;
  44. this.className = 'ResponsiveMenu'; // ie9 back compat
  45. this._init();
  46. this._events();
  47. }
  48. /**
  49. * Initializes the Menu by parsing the classes from the 'data-ResponsiveMenu' attribute on the element.
  50. * @function
  51. * @private
  52. */
  53. _init() {
  54. MediaQuery._init();
  55. // The first time an Interchange plugin is initialized, this.rules is converted from a string of "classes" to an object of rules
  56. if (typeof this.rules === 'string') {
  57. let rulesTree = {};
  58. // Parse rules from "classes" pulled from data attribute
  59. let rules = this.rules.split(' ');
  60. // Iterate through every rule found
  61. for (let i = 0; i < rules.length; i++) {
  62. let rule = rules[i].split('-');
  63. let ruleSize = rule.length > 1 ? rule[0] : 'small';
  64. let rulePlugin = rule.length > 1 ? rule[1] : rule[0];
  65. if (MenuPlugins[rulePlugin] !== null) {
  66. rulesTree[ruleSize] = MenuPlugins[rulePlugin];
  67. }
  68. }
  69. this.rules = rulesTree;
  70. }
  71. if (!$.isEmptyObject(this.rules)) {
  72. this._checkMediaQueries();
  73. }
  74. // Add data-mutate since children may need it.
  75. this.$element.attr('data-mutate', (this.$element.attr('data-mutate') || GetYoDigits(6, 'responsive-menu')));
  76. }
  77. /**
  78. * Initializes events for the Menu.
  79. * @function
  80. * @private
  81. */
  82. _events() {
  83. var _this = this;
  84. $(window).on('changed.zf.mediaquery', function() {
  85. _this._checkMediaQueries();
  86. });
  87. // $(window).on('resize.zf.ResponsiveMenu', function() {
  88. // _this._checkMediaQueries();
  89. // });
  90. }
  91. /**
  92. * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out.
  93. * @function
  94. * @private
  95. */
  96. _checkMediaQueries() {
  97. var matchedMq, _this = this;
  98. // Iterate through each rule and find the last matching rule
  99. $.each(this.rules, function(key) {
  100. if (MediaQuery.atLeast(key)) {
  101. matchedMq = key;
  102. }
  103. });
  104. // No match? No dice
  105. if (!matchedMq) return;
  106. // Plugin already initialized? We good
  107. if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;
  108. // Remove existing plugin-specific CSS classes
  109. $.each(MenuPlugins, function(key, value) {
  110. _this.$element.removeClass(value.cssClass);
  111. });
  112. // Add the CSS class for the new plugin
  113. this.$element.addClass(this.rules[matchedMq].cssClass);
  114. // Create an instance of the new plugin
  115. if (this.currentPlugin) this.currentPlugin.destroy();
  116. this.currentPlugin = new this.rules[matchedMq].plugin(this.$element, {});
  117. }
  118. /**
  119. * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out.
  120. * @function
  121. */
  122. _destroy() {
  123. this.currentPlugin.destroy();
  124. $(window).off('.zf.ResponsiveMenu');
  125. }
  126. }
  127. ResponsiveMenu.defaults = {};
  128. export {ResponsiveMenu};