464 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			464 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| ;(function ($, window, document, undefined) {
 | |
|   'use strict';
 | |
| 
 | |
|   Foundation.libs.dropdown = {
 | |
|     name : 'dropdown',
 | |
| 
 | |
|     version : '5.5.2',
 | |
| 
 | |
|     settings : {
 | |
|       active_class : 'open',
 | |
|       disabled_class : 'disabled',
 | |
|       mega_class : 'mega',
 | |
|       align : 'bottom',
 | |
|       is_hover : false,
 | |
|       hover_timeout : 150,
 | |
|       opened : function () {},
 | |
|       closed : function () {}
 | |
|     },
 | |
| 
 | |
|     init : function (scope, method, options) {
 | |
|       Foundation.inherit(this, 'throttle');
 | |
| 
 | |
|       $.extend(true, this.settings, method, options);
 | |
|       this.bindings(method, options);
 | |
|     },
 | |
| 
 | |
|     events : function (scope) {
 | |
|       var self = this,
 | |
|           S = self.S;
 | |
| 
 | |
|       S(this.scope)
 | |
|         .off('.dropdown')
 | |
|         .on('click.fndtn.dropdown', '[' + this.attr_name() + ']', function (e) {
 | |
|           var settings = S(this).data(self.attr_name(true) + '-init') || self.settings;
 | |
|           if (!settings.is_hover || Modernizr.touch) {
 | |
|             e.preventDefault();
 | |
|             if (S(this).parent('[data-reveal-id]').length) {
 | |
|               e.stopPropagation();
 | |
|             }
 | |
|             self.toggle($(this));
 | |
|           }
 | |
|         })
 | |
|         .on('mouseenter.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) {
 | |
|           var $this = S(this),
 | |
|               dropdown,
 | |
|               target;
 | |
| 
 | |
|           clearTimeout(self.timeout);
 | |
| 
 | |
|           if ($this.data(self.data_attr())) {
 | |
|             dropdown = S('#' + $this.data(self.data_attr()));
 | |
|             target = $this;
 | |
|           } else {
 | |
|             dropdown = $this;
 | |
|             target = S('[' + self.attr_name() + '="' + dropdown.attr('id') + '"]');
 | |
|           }
 | |
| 
 | |
|           var settings = target.data(self.attr_name(true) + '-init') || self.settings;
 | |
| 
 | |
|           if (S(e.currentTarget).data(self.data_attr()) && settings.is_hover) {
 | |
|             self.closeall.call(self);
 | |
|           }
 | |
| 
 | |
|           if (settings.is_hover) {
 | |
|             self.open.apply(self, [dropdown, target]);
 | |
|           }
 | |
|         })
 | |
|         .on('mouseleave.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) {
 | |
|           var $this = S(this);
 | |
|           var settings;
 | |
| 
 | |
|           if ($this.data(self.data_attr())) {
 | |
|               settings = $this.data(self.data_attr(true) + '-init') || self.settings;
 | |
|           } else {
 | |
|               var target   = S('[' + self.attr_name() + '="' + S(this).attr('id') + '"]'),
 | |
|                   settings = target.data(self.attr_name(true) + '-init') || self.settings;
 | |
|           }
 | |
| 
 | |
|           self.timeout = setTimeout(function () {
 | |
|             if ($this.data(self.data_attr())) {
 | |
|               if (settings.is_hover) {
 | |
|                 self.close.call(self, S('#' + $this.data(self.data_attr())));
 | |
|               }
 | |
|             } else {
 | |
|               if (settings.is_hover) {
 | |
|                 self.close.call(self, $this);
 | |
|               }
 | |
|             }
 | |
|           }.bind(this), settings.hover_timeout);
 | |
|         })
 | |
|         .on('click.fndtn.dropdown', function (e) {
 | |
|           var parent = S(e.target).closest('[' + self.attr_name() + '-content]');
 | |
|           var links  = parent.find('a');
 | |
| 
 | |
|           if (links.length > 0 && parent.attr('aria-autoclose') !== 'false') {
 | |
|               self.close.call(self, S('[' + self.attr_name() + '-content]'));
 | |
|           }
 | |
| 
 | |
|           if (e.target !== document && !$.contains(document.documentElement, e.target)) {
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           if (S(e.target).closest('[' + self.attr_name() + ']').length > 0) {
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           if (!(S(e.target).data('revealId')) &&
 | |
|             (parent.length > 0 && (S(e.target).is('[' + self.attr_name() + '-content]') ||
 | |
|               $.contains(parent.first()[0], e.target)))) {
 | |
|             e.stopPropagation();
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           self.close.call(self, S('[' + self.attr_name() + '-content]'));
 | |
|         })
 | |
|         .on('opened.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () {
 | |
|           self.settings.opened.call(this);
 | |
|         })
 | |
|         .on('closed.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () {
 | |
|           self.settings.closed.call(this);
 | |
|         });
 | |
| 
 | |
|       S(window)
 | |
|         .off('.dropdown')
 | |
|         .on('resize.fndtn.dropdown', self.throttle(function () {
 | |
|           self.resize.call(self);
 | |
|         }, 50));
 | |
| 
 | |
|       this.resize();
 | |
|     },
 | |
| 
 | |
|     close : function (dropdown) {
 | |
|       var self = this;
 | |
|       dropdown.each(function (idx) {
 | |
|         var original_target = $('[' + self.attr_name() + '=' + dropdown[idx].id + ']') || $('aria-controls=' + dropdown[idx].id + ']');
 | |
|         original_target.attr('aria-expanded', 'false');
 | |
|         if (self.S(this).hasClass(self.settings.active_class)) {
 | |
|           self.S(this)
 | |
|             .css(Foundation.rtl ? 'right' : 'left', '-99999px')
 | |
|             .attr('aria-hidden', 'true')
 | |
|             .removeClass(self.settings.active_class)
 | |
|             .prev('[' + self.attr_name() + ']')
 | |
|             .removeClass(self.settings.active_class)
 | |
|             .removeData('target');
 | |
| 
 | |
|           self.S(this).trigger('closed.fndtn.dropdown', [dropdown]);
 | |
|         }
 | |
|       });
 | |
|       dropdown.removeClass('f-open-' + this.attr_name(true));
 | |
|     },
 | |
| 
 | |
|     closeall : function () {
 | |
|       var self = this;
 | |
|       $.each(self.S('.f-open-' + this.attr_name(true)), function () {
 | |
|         self.close.call(self, self.S(this));
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     open : function (dropdown, target) {
 | |
|       this
 | |
|         .css(dropdown
 | |
|         .addClass(this.settings.active_class), target);
 | |
|       dropdown.prev('[' + this.attr_name() + ']').addClass(this.settings.active_class);
 | |
|       dropdown.data('target', target.get(0)).trigger('opened.fndtn.dropdown', [dropdown, target]);
 | |
|       dropdown.attr('aria-hidden', 'false');
 | |
|       target.attr('aria-expanded', 'true');
 | |
|       dropdown.focus();
 | |
|       dropdown.addClass('f-open-' + this.attr_name(true));
 | |
|     },
 | |
| 
 | |
|     data_attr : function () {
 | |
|       if (this.namespace.length > 0) {
 | |
|         return this.namespace + '-' + this.name;
 | |
|       }
 | |
| 
 | |
|       return this.name;
 | |
|     },
 | |
| 
 | |
|     toggle : function (target) {
 | |
|       if (target.hasClass(this.settings.disabled_class)) {
 | |
|         return;
 | |
|       }
 | |
|       var dropdown = this.S('#' + target.data(this.data_attr()));
 | |
|       if (dropdown.length === 0) {
 | |
|         // No dropdown found, not continuing
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       this.close.call(this, this.S('[' + this.attr_name() + '-content]').not(dropdown));
 | |
| 
 | |
|       if (dropdown.hasClass(this.settings.active_class)) {
 | |
|         this.close.call(this, dropdown);
 | |
|         if (dropdown.data('target') !== target.get(0)) {
 | |
|           this.open.call(this, dropdown, target);
 | |
|         }
 | |
|       } else {
 | |
|         this.open.call(this, dropdown, target);
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     resize : function () {
 | |
|       var dropdown = this.S('[' + this.attr_name() + '-content].open');
 | |
|       var target = $(dropdown.data("target"));
 | |
| 
 | |
|       if (dropdown.length && target.length) {
 | |
|         this.css(dropdown, target);
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     css : function (dropdown, target) {
 | |
|       var left_offset = Math.max((target.width() - dropdown.width()) / 2, 8),
 | |
|           settings = target.data(this.attr_name(true) + '-init') || this.settings,
 | |
|           parentOverflow = dropdown.parent().css('overflow-y') || dropdown.parent().css('overflow');
 | |
| 
 | |
|       this.clear_idx();
 | |
| 
 | |
| 
 | |
| 
 | |
|       if (this.small()) {
 | |
|         var p = this.dirs.bottom.call(dropdown, target, settings);
 | |
| 
 | |
|         dropdown.attr('style', '').removeClass('drop-left drop-right drop-top').css({
 | |
|           position : 'absolute',
 | |
|           width : '95%',
 | |
|           'max-width' : 'none',
 | |
|           top : p.top
 | |
|         });
 | |
| 
 | |
|         dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset);
 | |
|       }
 | |
|       // detect if dropdown is in an overflow container
 | |
|       else if (parentOverflow !== 'visible') {
 | |
|         var offset = target[0].offsetTop + target[0].offsetHeight;
 | |
| 
 | |
|         dropdown.attr('style', '').css({
 | |
|           position : 'absolute',
 | |
|           top : offset
 | |
|         });
 | |
| 
 | |
|         dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset);
 | |
|       }
 | |
|       else {
 | |
| 
 | |
|         this.style(dropdown, target, settings);
 | |
|       }
 | |
| 
 | |
|       return dropdown;
 | |
|     },
 | |
| 
 | |
|     style : function (dropdown, target, settings) {
 | |
|       var css = $.extend({position : 'absolute'},
 | |
|         this.dirs[settings.align].call(dropdown, target, settings));
 | |
| 
 | |
|       dropdown.attr('style', '').css(css);
 | |
|     },
 | |
| 
 | |
|     // return CSS property object
 | |
|     // `this` is the dropdown
 | |
|     dirs : {
 | |
|       // Calculate target offset
 | |
|       _base : function (t) {
 | |
|         var o_p = this.offsetParent(),
 | |
|             o = o_p.offset(),
 | |
|             p = t.offset();
 | |
| 
 | |
|         p.top -= o.top;
 | |
|         p.left -= o.left;
 | |
| 
 | |
|         //set some flags on the p object to pass along
 | |
|         p.missRight = false;
 | |
|         p.missTop = false;
 | |
|         p.missLeft = false;
 | |
|         p.leftRightFlag = false;
 | |
| 
 | |
|         //lets see if the panel will be off the screen
 | |
|         //get the actual width of the page and store it
 | |
|         var actualBodyWidth;
 | |
|         if (document.getElementsByClassName('row')[0]) {
 | |
|           actualBodyWidth = document.getElementsByClassName('row')[0].clientWidth;
 | |
|         } else {
 | |
|           actualBodyWidth = window.innerWidth;
 | |
|         }
 | |
| 
 | |
|         var actualMarginWidth = (window.innerWidth - actualBodyWidth) / 2;
 | |
|         var actualBoundary = actualBodyWidth;
 | |
| 
 | |
|         if (!this.hasClass('mega')) {
 | |
|           //miss top
 | |
|           if (t.offset().top <= this.outerHeight()) {
 | |
|             p.missTop = true;
 | |
|             actualBoundary = window.innerWidth - actualMarginWidth;
 | |
|             p.leftRightFlag = true;
 | |
|           }
 | |
| 
 | |
|           //miss right
 | |
|           if (t.offset().left + this.outerWidth() > t.offset().left + actualMarginWidth && t.offset().left - actualMarginWidth > this.outerWidth()) {
 | |
|             p.missRight = true;
 | |
|             p.missLeft = false;
 | |
|           }
 | |
| 
 | |
|           //miss left
 | |
|           if (t.offset().left - this.outerWidth() <= 0) {
 | |
|             p.missLeft = true;
 | |
|             p.missRight = false;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         return p;
 | |
|       },
 | |
| 
 | |
|       top : function (t, s) {
 | |
|         var self = Foundation.libs.dropdown,
 | |
|             p = self.dirs._base.call(this, t);
 | |
| 
 | |
|         this.addClass('drop-top');
 | |
| 
 | |
|         if (p.missTop == true) {
 | |
|           p.top = p.top + t.outerHeight() + this.outerHeight();
 | |
|           this.removeClass('drop-top');
 | |
|         }
 | |
| 
 | |
|         if (p.missRight == true) {
 | |
|           p.left = p.left - this.outerWidth() + t.outerWidth();
 | |
|         }
 | |
| 
 | |
|         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
 | |
|           self.adjust_pip(this, t, s, p);
 | |
|         }
 | |
| 
 | |
|         if (Foundation.rtl) {
 | |
|           return {left : p.left - this.outerWidth() + t.outerWidth(),
 | |
|             top : p.top - this.outerHeight()};
 | |
|         }
 | |
| 
 | |
|         return {left : p.left, top : p.top - this.outerHeight()};
 | |
|       },
 | |
| 
 | |
|       bottom : function (t, s) {
 | |
|         var self = Foundation.libs.dropdown,
 | |
|             p = self.dirs._base.call(this, t);
 | |
| 
 | |
|         if (p.missRight == true) {
 | |
|           p.left = p.left - this.outerWidth() + t.outerWidth();
 | |
|         }
 | |
| 
 | |
|         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
 | |
|           self.adjust_pip(this, t, s, p);
 | |
|         }
 | |
| 
 | |
|         if (self.rtl) {
 | |
|           return {left : p.left - this.outerWidth() + t.outerWidth(), top : p.top + t.outerHeight()};
 | |
|         }
 | |
| 
 | |
|         return {left : p.left, top : p.top + t.outerHeight()};
 | |
|       },
 | |
| 
 | |
|       left : function (t, s) {
 | |
|         var p = Foundation.libs.dropdown.dirs._base.call(this, t);
 | |
| 
 | |
|         this.addClass('drop-left');
 | |
| 
 | |
|         if (p.missLeft == true) {
 | |
|           p.left =  p.left + this.outerWidth();
 | |
|           p.top = p.top + t.outerHeight();
 | |
|           this.removeClass('drop-left');
 | |
|         }
 | |
| 
 | |
|         return {left : p.left - this.outerWidth(), top : p.top};
 | |
|       },
 | |
| 
 | |
|       right : function (t, s) {
 | |
|         var p = Foundation.libs.dropdown.dirs._base.call(this, t);
 | |
| 
 | |
|         this.addClass('drop-right');
 | |
| 
 | |
|         if (p.missRight == true) {
 | |
|           p.left = p.left - this.outerWidth();
 | |
|           p.top = p.top + t.outerHeight();
 | |
|           this.removeClass('drop-right');
 | |
|         } else {
 | |
|           p.triggeredRight = true;
 | |
|         }
 | |
| 
 | |
|         var self = Foundation.libs.dropdown;
 | |
| 
 | |
|         if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) {
 | |
|           self.adjust_pip(this, t, s, p);
 | |
|         }
 | |
| 
 | |
|         return {left : p.left + t.outerWidth(), top : p.top};
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // Insert rule to style psuedo elements
 | |
|     adjust_pip : function (dropdown, target, settings, position) {
 | |
|       var sheet = Foundation.stylesheet,
 | |
|           pip_offset_base = 8;
 | |
| 
 | |
|       if (dropdown.hasClass(settings.mega_class)) {
 | |
|         pip_offset_base = position.left + (target.outerWidth() / 2) - 8;
 | |
|       } else if (this.small()) {
 | |
|         pip_offset_base += position.left - 8;
 | |
|       }
 | |
| 
 | |
|       this.rule_idx = sheet.cssRules.length;
 | |
| 
 | |
|       //default
 | |
|       var sel_before = '.f-dropdown.open:before',
 | |
|           sel_after  = '.f-dropdown.open:after',
 | |
|           css_before = 'left: ' + pip_offset_base + 'px;',
 | |
|           css_after  = 'left: ' + (pip_offset_base - 1) + 'px;';
 | |
| 
 | |
|       if (position.missRight == true) {
 | |
|         pip_offset_base = dropdown.outerWidth() - 23;
 | |
|         sel_before = '.f-dropdown.open:before',
 | |
|         sel_after  = '.f-dropdown.open:after',
 | |
|         css_before = 'left: ' + pip_offset_base + 'px;',
 | |
|         css_after  = 'left: ' + (pip_offset_base - 1) + 'px;';
 | |
|       }
 | |
| 
 | |
|       //just a case where right is fired, but its not missing right
 | |
|       if (position.triggeredRight == true) {
 | |
|         sel_before = '.f-dropdown.open:before',
 | |
|         sel_after  = '.f-dropdown.open:after',
 | |
|         css_before = 'left:-12px;',
 | |
|         css_after  = 'left:-14px;';
 | |
|       }
 | |
| 
 | |
|       if (sheet.insertRule) {
 | |
|         sheet.insertRule([sel_before, '{', css_before, '}'].join(' '), this.rule_idx);
 | |
|         sheet.insertRule([sel_after, '{', css_after, '}'].join(' '), this.rule_idx + 1);
 | |
|       } else {
 | |
|         sheet.addRule(sel_before, css_before, this.rule_idx);
 | |
|         sheet.addRule(sel_after, css_after, this.rule_idx + 1);
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // Remove old dropdown rule index
 | |
|     clear_idx : function () {
 | |
|       var sheet = Foundation.stylesheet;
 | |
| 
 | |
|       if (typeof this.rule_idx !== 'undefined') {
 | |
|         sheet.deleteRule(this.rule_idx);
 | |
|         sheet.deleteRule(this.rule_idx);
 | |
|         delete this.rule_idx;
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     small : function () {
 | |
|       return matchMedia(Foundation.media_queries.small).matches &&
 | |
|         !matchMedia(Foundation.media_queries.medium).matches;
 | |
|     },
 | |
| 
 | |
|     off : function () {
 | |
|       this.S(this.scope).off('.fndtn.dropdown');
 | |
|       this.S('html, body').off('.fndtn.dropdown');
 | |
|       this.S(window).off('.fndtn.dropdown');
 | |
|       this.S('[data-dropdown-content]').off('.fndtn.dropdown');
 | |
|     },
 | |
| 
 | |
|     reflow : function () {}
 | |
|   };
 | |
| }(jQuery, window, window.document));
 |