Mercurial > web-octave
diff js/foundation/foundation.dropdown.js @ 0:7abe02bf29ec
initial commit
author | Alex Krolick <whokilledtheelectricmonk@gmail.com> |
---|---|
date | Sat, 07 Nov 2015 18:04:42 -0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/foundation/foundation.dropdown.js Sat Nov 07 18:04:42 2015 -0800 @@ -0,0 +1,468 @@ +;(function ($, window, document, undefined) { + 'use strict'; + + Foundation.libs.dropdown = { + name : 'dropdown', + + version : '5.5.3', + + 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, 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) { + p.missRight = true; + p.missLeft = false; + } + + //miss left + if (o_left - 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, s); + + 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, s); + + 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, s); + + 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, s); + + 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));