;(function ($, window, document, undefined) { 'use strict'; Foundation.libs.dropdown = { name : 'dropdown', version : '5.5.3master', settings : { active_class : 'open', disabled_class : 'disabled', mega_class : 'mega', align : 'bottom', is_hover : false, hover_timeout : 150, no_pip : false, 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, s) { 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; var windowWidth = window.innerWidth; if (document.getElementsByClassName('row')[0]) { actualBodyWidth = document.getElementsByClassName('row')[0].clientWidth; } else { actualBodyWidth = windowWidth; } var actualMarginWidth = (windowWidth - actualBodyWidth) / 2; var actualBoundary = actualBodyWidth; if (!this.hasClass('mega') && !s.ignore_repositioning) { var outerWidth = this.outerWidth(); var o_left = t.offset().left; //miss top if (t.offset().top <= this.outerHeight()) { p.missTop = true; actualBoundary = windowWidth - actualMarginWidth; p.leftRightFlag = true; } //miss right if (o_left + outerWidth > o_left + actualMarginWidth && o_left - actualMarginWidth > outerWidth - o_left) { p.missRight = true; } //miss left if (o_left - outerWidth <= 0) { p.missLeft = true; } } return p; }, top : function (t, s) { var self = Foundation.libs.dropdown, p = self.dirs._base.call(this, t, s), tOuterHeight = t.outerHeight(), tOuterWidth = t.outerWidth(), thisOuterHeight = this.outerHeight(), thisOuterWidth = this.outerWidth(); this.addClass('drop-top'); if (p.missTop == true) { p.top = p.top + tOuterHeight + thisOuterHeight; this.removeClass('drop-top'); } if (p.missRight == true) { p.left = p.left - thisOuterWidth + tOuterWidth; } if (!s.no_pip && tOuterWidth < thisOuterWidth || self.small() || this.hasClass(s.mega_menu)) { self.adjust_pip(this, t, s, p); } if (Foundation.rtl) { return {left : p.left - thisOuterWidth + tOuterWidth, top : p.top - thisOuterHeight}; } return {left : p.left, top : p.top - thisOuterHeight}; }, bottom : function (t, s) { var self = Foundation.libs.dropdown, p = self.dirs._base.call(this, t, s), tOuterHeight = t.outerHeight(), tOuterWidth = t.outerWidth(), thisOuterHeight = this.outerHeight(), thisOuterWidth = this.outerWidth();; if (p.missRight == true) { p.left = p.left - thisOuterWidth + tOuterWidth; } if (!s.no_pip && tOuterWidth < thisOuterWidth || self.small() || this.hasClass(s.mega_menu)) { self.adjust_pip(this, t, s, p); } if (self.rtl) { return {left : p.left - thisOuterWidth + tOuterWidth, top : p.top + tOuterHeight}; } return {left : p.left, top : p.top + tOuterHeight}; }, left : function (t, s) { var p = Foundation.libs.dropdown.dirs._base.call(this, t, s); var self = Foundation.libs.dropdown, tOuterHeight = t.outerHeight(), tOuterWidth = t.outerWidth(), thisOuterHeight = this.outerHeight(), thisOuterWidth = this.outerWidth(); this.addClass('drop-left'); if (p.missLeft === true) { p.left = p.left + thisOuterWidth; p.top = p.top + tOuterHeight; this.removeClass('drop-left'); } if (p.missRight === true && p.missLeft === true && p.leftRightFlag == false) { p.left = p.left - tOuterWidth; this.removeClass('drop-left'); self.adjust_pip(this,t,s,p); } return {left : p.left - thisOuterWidth, top : p.top}; }, right : function (t, s) { var p = Foundation.libs.dropdown.dirs._base.call(this, t, s); var self = Foundation.libs.dropdown, tOuterHeight = t.outerHeight(), tOuterWidth = t.outerWidth(), thisOuterHeight = this.outerHeight(), thisOuterWidth = this.outerWidth(); this.addClass('drop-right'); if (p.missRight === true && p.missLeft == false) { p.left = p.left - thisOuterWidth; p.top = p.top + tOuterHeight; this.removeClass('drop-right'); } else { p.triggeredRight = true; } if (p.missLeft === true && p.missRight === true && p.leftRightFlag === false) { p.left = p.left - thisOuterWidth; p.top = p.top + tOuterHeight; this.removeClass('drop-right'); p.triggeredRight = false; } if (tOuterWidth < thisOuterWidth || self.small() || this.hasClass(s.mega_menu)) { self.adjust_pip(this,t,s,p); } return {left : p.left + tOuterWidth, top : p.top}; } }, // Insert rule to style psuedo elements adjust_pip : function (dropdown, target, settings, position) { if (settings.no_pip === true) return; 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));