]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
Convert dropdown menu to ES6 class
authorColin Marshall <colin.michael.marshall@gmail.com>
Thu, 4 Feb 2016 05:33:39 +0000 (22:33 -0700)
committerColin Marshall <colin.michael.marshall@gmail.com>
Thu, 4 Feb 2016 05:33:39 +0000 (22:33 -0700)
js/foundation.dropdownMenu.js

index c9043bb2d8d3173b6570deefeeff9066e63d691a..f9c7b2ba0cb8f5434b7ee8e916c5bd8953454827 100644 (file)
@@ -1,3 +1,5 @@
+'use strict';
+
 /**
  * DropdownMenu module.
  * @module foundation.dropdown-menu
@@ -5,9 +7,8 @@
  * @requires foundation.util.box
  * @requires foundation.util.nest
  */
-!function($, Foundation){
-  'use strict';
 
+export default class DropdownMenu {
   /**
    * Creates a new instance of DropdownMenu.
    * @class
@@ -15,7 +16,7 @@
    * @param {jQuery} element - jQuery object to make into a dropdown menu.
    * @param {Object} options - Overrides to the default plugin settings.
    */
-  function DropdownMenu(element, options){
+  constructor(element, options) {
     this.$element = element;
     this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options);
 
     });
   }
 
-  /**
-   * Default settings for plugin
-   */
-  DropdownMenu.defaults = {
-    /**
-     * Disallows hover events from opening submenus
-     * @option
-     * @example false
-     */
-    disableHover: false,
-    /**
-     * Allow a submenu to automatically close on a mouseleave event, if not clicked open.
-     * @option
-     * @example true
-     */
-    autoclose: true,
-    /**
-     * Amount of time to delay opening a submenu on hover event.
-     * @option
-     * @example 50
-     */
-    hoverDelay: 50,
-    /**
-     * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu.
-     * @option
-     * @example true
-     */
-    clickOpen: false,
-    /**
-     * Amount of time to delay closing a submenu on a mouseleave event.
-     * @option
-     * @example 500
-     */
-
-    closingTime: 500,
-    /**
-     * Position of the menu relative to what direction the submenus should open. Handled by JS.
-     * @option
-     * @example 'left'
-     */
-    alignment: 'left',
-    /**
-     * Allow clicks on the body to close any open submenus.
-     * @option
-     * @example true
-     */
-    closeOnClick: true,
-    /**
-     * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class.
-     * @option
-     * @example 'vertical'
-     */
-    verticalClass: 'vertical',
-    /**
-     * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class.
-     * @option
-     * @example 'align-right'
-     */
-    rightClass: 'align-right',
-    /**
-     * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile.
-     * @option
-     * @example false
-     */
-    forceFollow: true
-  };
   /**
    * Initializes the plugin, and calls _prepareMenu
    * @private
    * @function
    */
-  DropdownMenu.prototype._init = function(){
+  _init() {
     var subs = this.$element.find('li.is-dropdown-submenu-parent');
     this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub');
 
     this.isVert = this.$element.hasClass(this.options.verticalClass);
     this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass);
 
-    if(this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right' || Foundation.rtl()){
+    if (this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right' || Foundation.rtl()) {
       this.options.alignment = 'right';
       subs.addClass('is-left-arrow opens-left');
-    }else{
+    } else {
       subs.addClass('is-right-arrow opens-right');
     }
-    if(!this.isVert){
+    if (!this.isVert) {
       this.$tabs.filter('.is-dropdown-submenu-parent').removeClass('is-right-arrow is-left-arrow opens-right opens-left')
           .addClass('is-down-arrow');
     }
    * @private
    * @function
    */
-  DropdownMenu.prototype._events = function(){
+  _events() {
     var _this = this,
         hasTouch = 'ontouchstart' in window || (typeof window.ontouchstart !== 'undefined'),
         parClass = 'is-dropdown-submenu-parent';
 
-    if(this.options.clickOpen || hasTouch){
-      this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', function(e){
+    if (this.options.clickOpen || hasTouch) {
+      this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', function(e) {
         var $elem = $(e.target).parentsUntil('ul', `.${parClass}`),
             hasSub = $elem.hasClass(parClass),
             hasClicked = $elem.attr('data-is-click') === 'true',
             $sub = $elem.children('.is-dropdown-submenu');
 
-        if(hasSub){
-          if(hasClicked){
-            if(!_this.options.closeOnClick || (!_this.options.clickOpen && !hasTouch) || (_this.options.forceFollow && hasTouch)){ return; }
-            else{
+        if (hasSub) {
+          if (hasClicked) {
+            if (!_this.options.closeOnClick || (!_this.options.clickOpen && !hasTouch) || (_this.options.forceFollow && hasTouch)) { return; }
+            else {
               e.stopImmediatePropagation();
               e.preventDefault();
               _this._hide($elem);
             }
-          }else{
+          } else {
             e.preventDefault();
             e.stopImmediatePropagation();
             _this._show($elem.children('.is-dropdown-submenu'));
             $elem.add($elem.parentsUntil(_this.$element, `.${parClass}`)).attr('data-is-click', true);
           }
-        }else{ return; }
+        } else { return; }
       });
     }
 
-    if(!this.options.disableHover){
-      this.$menuItems.on('mouseenter.zf.dropdownmenu', function(e){
+    if (!this.options.disableHover) {
+      this.$menuItems.on('mouseenter.zf.dropdownmenu', function(e) {
         e.stopImmediatePropagation();
         var $elem = $(this),
             hasSub = $elem.hasClass(parClass);
 
-        if(hasSub){
+        if (hasSub) {
           clearTimeout(_this.delay);
-          _this.delay = setTimeout(function(){
+          _this.delay = setTimeout(function() {
             _this._show($elem.children('.is-dropdown-submenu'));
           }, _this.options.hoverDelay);
         }
-      }).on('mouseleave.zf.dropdownmenu', function(e){
+      }).on('mouseleave.zf.dropdownmenu', function(e) {
         var $elem = $(this),
             hasSub = $elem.hasClass(parClass);
-        if(hasSub && _this.options.autoclose){
-          if($elem.attr('data-is-click') === 'true' && _this.options.clickOpen){ return false; }
+        if (hasSub && _this.options.autoclose) {
+          if ($elem.attr('data-is-click') === 'true' && _this.options.clickOpen) { return false; }
 
           clearTimeout(_this.delay);
-          _this.delay = setTimeout(function(){
+          _this.delay = setTimeout(function() {
             _this._hide($elem);
           }, _this.options.closingTime);
         }
       });
     }
-    this.$menuItems.on('keydown.zf.dropdownmenu', function(e){
+    this.$menuItems.on('keydown.zf.dropdownmenu', function(e) {
       var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'),
           isTab = _this.$tabs.index($element) > -1,
           $elements = isTab ? _this.$tabs : $element.siblings('li').add($element),
         $prevElement.children('a:first').focus();
       }, openSub = function() {
         var $sub = $element.children('ul.is-dropdown-submenu');
-        if($sub.length){
+        if ($sub.length) {
           _this._show($sub);
           $element.find('li > a:first').focus();
-        }else{ return; }
+        } else { return; }
       }, closeSub = function() {
         //if ($element.is(':first-child')) {
         var close = $element.parent('ul').parent('li');
       Foundation.Keyboard.handleKey(e, 'DropdownMenu', functions);
 
     });
-  };
+  }
+
   /**
    * Adds an event handler to the body to close any dropdowns on a click.
    * @function
    * @private
    */
-  DropdownMenu.prototype._addBodyHandler = function(){
+  _addBodyHandler() {
     var $body = $(document.body),
         _this = this;
     $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu')
-         .on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function(e){
+         .on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function(e) {
            var $link = _this.$element.find(e.target);
-           if($link.length){ return; }
+           if ($link.length) { return; }
 
            _this._hide();
            $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu');
          });
-  };
+  }
+
   /**
    * Opens a dropdown pane, and checks for collisions first.
    * @param {jQuery} $sub - ul element that is a submenu to show
    * @private
    * @fires DropdownMenu#show
    */
-  DropdownMenu.prototype._show = function($sub){
-    var idx = this.$tabs.index(this.$tabs.filter(function(i, el){
+  _show($sub) {
+    var idx = this.$tabs.index(this.$tabs.filter(function(i, el) {
       return $(el).find($sub).length > 0;
     }));
     var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent');
         .parent('li.is-dropdown-submenu-parent').addClass('is-active')
         .attr({'aria-expanded': true});
     var clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
-    if(!clear){
+    if (!clear) {
       var oldClass = this.options.alignment === 'left' ? '-right' : '-left',
           $parentLi = $sub.parent('.is-dropdown-submenu-parent');
       $parentLi.removeClass(`opens${oldClass}`).addClass(`opens-${this.options.alignment}`);
       clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
-      if(!clear){
+      if (!clear) {
         $parentLi.removeClass(`opens-${this.options.alignment}`).addClass('opens-inner');
       }
       this.changed = true;
     }
     $sub.css('visibility', '');
-    if(this.options.closeOnClick){ this._addBodyHandler(); }
+    if (this.options.closeOnClick) { this._addBodyHandler(); }
     /**
      * Fires when the new dropdown pane is visible.
      * @event DropdownMenu#show
      */
     this.$element.trigger('show.zf.dropdownmenu', [$sub]);
-  };
+  }
+
   /**
    * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything.
    * @function
    * @param {Number} idx - index of the $tabs collection to hide
    * @private
    */
-  DropdownMenu.prototype._hide = function($elem, idx){
+  _hide($elem, idx) {
     var $toClose;
-    if($elem && $elem.length){
+    if ($elem && $elem.length) {
       $toClose = $elem;
-    }else if(idx !== undefined){
-      $toClose = this.$tabs.not(function(i, el){
+    } else if (idx !== undefined) {
+      $toClose = this.$tabs.not(function(i, el) {
         return i === idx;
       });
     }
-    else{
+    else {
       $toClose = this.$element;
     }
     var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0;
 
-    if(somethingToClose){
+    if (somethingToClose) {
       $toClose.find('li.is-active').add($toClose).attr({
         'aria-expanded': false,
         'data-is-click': false
         'aria-hidden': true
       }).removeClass('js-dropdown-active');
 
-      if(this.changed || $toClose.find('opens-inner').length){
+      if (this.changed || $toClose.find('opens-inner').length) {
         var oldClass = this.options.alignment === 'left' ? 'right' : 'left';
         $toClose.find('li.is-dropdown-submenu-parent').add($toClose)
                 .removeClass(`opens-inner opens-${this.options.alignment}`)
        */
       this.$element.trigger('hide.zf.dropdownmenu', [$toClose]);
     }
-  };
+  }
+
   /**
    * Destroys the plugin.
    * @function
    */
-  DropdownMenu.prototype.destroy = function(){
+  destroy() {
     this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click')
         .removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner');
     $(document.body).off('.zf.dropdownmenu');
     Foundation.Nest.Burn(this.$element, 'dropdown');
     Foundation.unregisterPlugin(this);
-  };
+  }
+}
+
+/**
+ * Default settings for plugin
+ */
+DropdownMenu.defaults = {
+  /**
+   * Disallows hover events from opening submenus
+   * @option
+   * @example false
+   */
+  disableHover: false,
+  /**
+   * Allow a submenu to automatically close on a mouseleave event, if not clicked open.
+   * @option
+   * @example true
+   */
+  autoclose: true,
+  /**
+   * Amount of time to delay opening a submenu on hover event.
+   * @option
+   * @example 50
+   */
+  hoverDelay: 50,
+  /**
+   * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu.
+   * @option
+   * @example true
+   */
+  clickOpen: false,
+  /**
+   * Amount of time to delay closing a submenu on a mouseleave event.
+   * @option
+   * @example 500
+   */
+
+  closingTime: 500,
+  /**
+   * Position of the menu relative to what direction the submenus should open. Handled by JS.
+   * @option
+   * @example 'left'
+   */
+  alignment: 'left',
+  /**
+   * Allow clicks on the body to close any open submenus.
+   * @option
+   * @example true
+   */
+  closeOnClick: true,
+  /**
+   * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class.
+   * @option
+   * @example 'vertical'
+   */
+  verticalClass: 'vertical',
+  /**
+   * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class.
+   * @option
+   * @example 'align-right'
+   */
+  rightClass: 'align-right',
+  /**
+   * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile.
+   * @option
+   * @example false
+   */
+  forceFollow: true
+};
 
-  Foundation.plugin(DropdownMenu, 'DropdownMenu');
-}(jQuery, window.Foundation);
+// Window exports
+if (window.Foundation) {
+  window.Foundation.plugin(DropdownMenu, 'DropdownMenu');
+}