1
0
mirror of https://github.com/Hutchy68/pivot.git synced 2024-11-23 19:09:03 +01:00
pivot/assets/scripts/foundation/foundation.dropdown.js

500 lines
16 KiB
JavaScript

;(function ($, window, document, undefined) {
'use strict';
Foundation.libs.dropdown = {
name : 'dropdown',
version : '{{VERSION}}',
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));