261 lines
8.6 KiB
JavaScript
261 lines
8.6 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
import $ from 'jquery';
|
||
|
import { onLoad } from './foundation.core.utils';
|
||
|
import { Motion } from './foundation.util.motion';
|
||
|
|
||
|
const MutationObserver = (function () {
|
||
|
var prefixes = ['WebKit', 'Moz', 'O', 'Ms', ''];
|
||
|
for (var i=0; i < prefixes.length; i++) {
|
||
|
if (`${prefixes[i]}MutationObserver` in window) {
|
||
|
return window[`${prefixes[i]}MutationObserver`];
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}());
|
||
|
|
||
|
const triggers = (el, type) => {
|
||
|
el.data(type).split(' ').forEach(id => {
|
||
|
$(`#${id}`)[ type === 'close' ? 'trigger' : 'triggerHandler'](`${type}.zf.trigger`, [el]);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
var Triggers = {
|
||
|
Listeners: {
|
||
|
Basic: {},
|
||
|
Global: {}
|
||
|
},
|
||
|
Initializers: {}
|
||
|
}
|
||
|
|
||
|
Triggers.Listeners.Basic = {
|
||
|
openListener: function() {
|
||
|
triggers($(this), 'open');
|
||
|
},
|
||
|
closeListener: function() {
|
||
|
let id = $(this).data('close');
|
||
|
if (id) {
|
||
|
triggers($(this), 'close');
|
||
|
}
|
||
|
else {
|
||
|
$(this).trigger('close.zf.trigger');
|
||
|
}
|
||
|
},
|
||
|
toggleListener: function() {
|
||
|
let id = $(this).data('toggle');
|
||
|
if (id) {
|
||
|
triggers($(this), 'toggle');
|
||
|
} else {
|
||
|
$(this).trigger('toggle.zf.trigger');
|
||
|
}
|
||
|
},
|
||
|
closeableListener: function(e) {
|
||
|
e.stopPropagation();
|
||
|
let animation = $(this).data('closable');
|
||
|
|
||
|
if(animation !== ''){
|
||
|
Motion.animateOut($(this), animation, function() {
|
||
|
$(this).trigger('closed.zf');
|
||
|
});
|
||
|
}else{
|
||
|
$(this).fadeOut().trigger('closed.zf');
|
||
|
}
|
||
|
},
|
||
|
toggleFocusListener: function() {
|
||
|
let id = $(this).data('toggle-focus');
|
||
|
$(`#${id}`).triggerHandler('toggle.zf.trigger', [$(this)]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Elements with [data-open] will reveal a plugin that supports it when clicked.
|
||
|
Triggers.Initializers.addOpenListener = ($elem) => {
|
||
|
$elem.off('click.zf.trigger', Triggers.Listeners.Basic.openListener);
|
||
|
$elem.on('click.zf.trigger', '[data-open]', Triggers.Listeners.Basic.openListener);
|
||
|
}
|
||
|
|
||
|
// Elements with [data-close] will close a plugin that supports it when clicked.
|
||
|
// If used without a value on [data-close], the event will bubble, allowing it to close a parent component.
|
||
|
Triggers.Initializers.addCloseListener = ($elem) => {
|
||
|
$elem.off('click.zf.trigger', Triggers.Listeners.Basic.closeListener);
|
||
|
$elem.on('click.zf.trigger', '[data-close]', Triggers.Listeners.Basic.closeListener);
|
||
|
}
|
||
|
|
||
|
// Elements with [data-toggle] will toggle a plugin that supports it when clicked.
|
||
|
Triggers.Initializers.addToggleListener = ($elem) => {
|
||
|
$elem.off('click.zf.trigger', Triggers.Listeners.Basic.toggleListener);
|
||
|
$elem.on('click.zf.trigger', '[data-toggle]', Triggers.Listeners.Basic.toggleListener);
|
||
|
}
|
||
|
|
||
|
// Elements with [data-closable] will respond to close.zf.trigger events.
|
||
|
Triggers.Initializers.addCloseableListener = ($elem) => {
|
||
|
$elem.off('close.zf.trigger', Triggers.Listeners.Basic.closeableListener);
|
||
|
$elem.on('close.zf.trigger', '[data-closeable], [data-closable]', Triggers.Listeners.Basic.closeableListener);
|
||
|
}
|
||
|
|
||
|
// Elements with [data-toggle-focus] will respond to coming in and out of focus
|
||
|
Triggers.Initializers.addToggleFocusListener = ($elem) => {
|
||
|
$elem.off('focus.zf.trigger blur.zf.trigger', Triggers.Listeners.Basic.toggleFocusListener);
|
||
|
$elem.on('focus.zf.trigger blur.zf.trigger', '[data-toggle-focus]', Triggers.Listeners.Basic.toggleFocusListener);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// More Global/complex listeners and triggers
|
||
|
Triggers.Listeners.Global = {
|
||
|
resizeListener: function($nodes) {
|
||
|
if(!MutationObserver){//fallback for IE 9
|
||
|
$nodes.each(function(){
|
||
|
$(this).triggerHandler('resizeme.zf.trigger');
|
||
|
});
|
||
|
}
|
||
|
//trigger all listening elements and signal a resize event
|
||
|
$nodes.attr('data-events', "resize");
|
||
|
},
|
||
|
scrollListener: function($nodes) {
|
||
|
if(!MutationObserver){//fallback for IE 9
|
||
|
$nodes.each(function(){
|
||
|
$(this).triggerHandler('scrollme.zf.trigger');
|
||
|
});
|
||
|
}
|
||
|
//trigger all listening elements and signal a scroll event
|
||
|
$nodes.attr('data-events', "scroll");
|
||
|
},
|
||
|
closeMeListener: function(e, pluginId){
|
||
|
let plugin = e.namespace.split('.')[0];
|
||
|
let plugins = $(`[data-${plugin}]`).not(`[data-yeti-box="${pluginId}"]`);
|
||
|
|
||
|
plugins.each(function(){
|
||
|
let _this = $(this);
|
||
|
_this.triggerHandler('close.zf.trigger', [_this]);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Global, parses whole document.
|
||
|
Triggers.Initializers.addClosemeListener = function(pluginName) {
|
||
|
var yetiBoxes = $('[data-yeti-box]'),
|
||
|
plugNames = ['dropdown', 'tooltip', 'reveal'];
|
||
|
|
||
|
if(pluginName){
|
||
|
if(typeof pluginName === 'string'){
|
||
|
plugNames.push(pluginName);
|
||
|
}else if(typeof pluginName === 'object' && typeof pluginName[0] === 'string'){
|
||
|
plugNames.concat(pluginName);
|
||
|
}else{
|
||
|
console.error('Plugin names must be strings');
|
||
|
}
|
||
|
}
|
||
|
if(yetiBoxes.length){
|
||
|
let listeners = plugNames.map((name) => {
|
||
|
return `closeme.zf.${name}`;
|
||
|
}).join(' ');
|
||
|
|
||
|
$(window).off(listeners).on(listeners, Triggers.Listeners.Global.closeMeListener);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function debounceGlobalListener(debounce, trigger, listener) {
|
||
|
let timer, args = Array.prototype.slice.call(arguments, 3);
|
||
|
$(window).off(trigger).on(trigger, function(e) {
|
||
|
if (timer) { clearTimeout(timer); }
|
||
|
timer = setTimeout(function(){
|
||
|
listener.apply(null, args);
|
||
|
}, debounce || 10);//default time to emit scroll event
|
||
|
});
|
||
|
}
|
||
|
|
||
|
Triggers.Initializers.addResizeListener = function(debounce){
|
||
|
let $nodes = $('[data-resize]');
|
||
|
if($nodes.length){
|
||
|
debounceGlobalListener(debounce, 'resize.zf.trigger', Triggers.Listeners.Global.resizeListener, $nodes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Triggers.Initializers.addScrollListener = function(debounce){
|
||
|
let $nodes = $('[data-scroll]');
|
||
|
if($nodes.length){
|
||
|
debounceGlobalListener(debounce, 'scroll.zf.trigger', Triggers.Listeners.Global.scrollListener, $nodes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Triggers.Initializers.addMutationEventsListener = function($elem) {
|
||
|
if(!MutationObserver){ return false; }
|
||
|
let $nodes = $elem.find('[data-resize], [data-scroll], [data-mutate]');
|
||
|
|
||
|
//element callback
|
||
|
var listeningElementsMutation = function (mutationRecordsList) {
|
||
|
var $target = $(mutationRecordsList[0].target);
|
||
|
|
||
|
//trigger the event handler for the element depending on type
|
||
|
switch (mutationRecordsList[0].type) {
|
||
|
case "attributes":
|
||
|
if ($target.attr("data-events") === "scroll" && mutationRecordsList[0].attributeName === "data-events") {
|
||
|
$target.triggerHandler('scrollme.zf.trigger', [$target, window.pageYOffset]);
|
||
|
}
|
||
|
if ($target.attr("data-events") === "resize" && mutationRecordsList[0].attributeName === "data-events") {
|
||
|
$target.triggerHandler('resizeme.zf.trigger', [$target]);
|
||
|
}
|
||
|
if (mutationRecordsList[0].attributeName === "style") {
|
||
|
$target.closest("[data-mutate]").attr("data-events","mutate");
|
||
|
$target.closest("[data-mutate]").triggerHandler('mutateme.zf.trigger', [$target.closest("[data-mutate]")]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case "childList":
|
||
|
$target.closest("[data-mutate]").attr("data-events","mutate");
|
||
|
$target.closest("[data-mutate]").triggerHandler('mutateme.zf.trigger', [$target.closest("[data-mutate]")]);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return false;
|
||
|
//nothing
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if ($nodes.length) {
|
||
|
//for each element that needs to listen for resizing, scrolling, or mutation add a single observer
|
||
|
for (var i = 0; i <= $nodes.length - 1; i++) {
|
||
|
var elementObserver = new MutationObserver(listeningElementsMutation);
|
||
|
elementObserver.observe($nodes[i], { attributes: true, childList: true, characterData: false, subtree: true, attributeFilter: ["data-events", "style"] });
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Triggers.Initializers.addSimpleListeners = function() {
|
||
|
let $document = $(document);
|
||
|
|
||
|
Triggers.Initializers.addOpenListener($document);
|
||
|
Triggers.Initializers.addCloseListener($document);
|
||
|
Triggers.Initializers.addToggleListener($document);
|
||
|
Triggers.Initializers.addCloseableListener($document);
|
||
|
Triggers.Initializers.addToggleFocusListener($document);
|
||
|
|
||
|
}
|
||
|
|
||
|
Triggers.Initializers.addGlobalListeners = function() {
|
||
|
let $document = $(document);
|
||
|
Triggers.Initializers.addMutationEventsListener($document);
|
||
|
Triggers.Initializers.addResizeListener();
|
||
|
Triggers.Initializers.addScrollListener();
|
||
|
Triggers.Initializers.addClosemeListener();
|
||
|
}
|
||
|
|
||
|
|
||
|
Triggers.init = function ($, Foundation) {
|
||
|
onLoad($(window), function () {
|
||
|
if ($.triggersInitialized !== true) {
|
||
|
Triggers.Initializers.addSimpleListeners();
|
||
|
Triggers.Initializers.addGlobalListeners();
|
||
|
$.triggersInitialized = true;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if(Foundation) {
|
||
|
Foundation.Triggers = Triggers;
|
||
|
// Legacy included to be backwards compatible for now.
|
||
|
Foundation.IHearYou = Triggers.Initializers.addGlobalListeners
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export {Triggers};
|