File: /var/www/html/wp-content/themes/thegem-elementor/js/thegem-scrollMonitor.js
(function( factory ) {
if (typeof define !== 'undefined' && define.amd) {
define([], factory);
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = factory();
} else {
window.scrollMonitor = factory();
}
})(function() {
var scrollTop = function() {
return window.pageYOffset ||
(document.documentElement && document.documentElement.scrollTop) ||
document.body.scrollTop;
};
var exports = {};
var watchers = [];
var VISIBILITYCHANGE = 'visibilityChange';
var ENTERVIEWPORT = 'enterViewport';
var FULLYENTERVIEWPORT = 'fullyEnterViewport';
var EXITVIEWPORT = 'exitViewport';
var PARTIALLYEXITVIEWPORT = 'partiallyExitViewport';
var LOCATIONCHANGE = 'locationChange';
var STATECHANGE = 'stateChange';
var eventTypes = [
VISIBILITYCHANGE,
ENTERVIEWPORT,
FULLYENTERVIEWPORT,
EXITVIEWPORT,
PARTIALLYEXITVIEWPORT,
LOCATIONCHANGE,
STATECHANGE
];
var defaultOffsets = {top: 0, bottom: 0};
var getViewportHeight = function() {
return window.innerHeight || document.documentElement.clientHeight;
};
var getDocumentHeight = function() {
// jQuery approach
// whichever is greatest
return Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.documentElement.clientHeight
);
};
exports.viewportTop = null;
exports.viewportBottom = null;
exports.documentHeight = null;
exports.viewportHeight = getViewportHeight();
var previousDocumentHeight;
var latestEvent;
var calculateViewportI;
function calculateViewport() {
exports.viewportTop = scrollTop();
exports.viewportBottom = exports.viewportTop + exports.viewportHeight;
exports.documentHeight = getDocumentHeight();
if (exports.documentHeight !== previousDocumentHeight) {
calculateViewportI = watchers.length;
while( calculateViewportI-- ) {
watchers[calculateViewportI].recalculateLocation();
}
previousDocumentHeight = exports.documentHeight;
}
}
function recalculateWatchLocationsAndTrigger() {
exports.viewportHeight = getViewportHeight();
calculateViewport();
updateAndTriggerWatchers();
}
var recalculateAndTriggerTimer;
function debouncedRecalcuateAndTrigger() {
clearTimeout(recalculateAndTriggerTimer);
recalculateAndTriggerTimer = setTimeout( recalculateWatchLocationsAndTrigger, 100 );
}
var updateAndTriggerWatchersI;
function updateAndTriggerWatchers() {
// update all watchers then trigger the events so one can rely on another being up to date.
updateAndTriggerWatchersI = watchers.length;
var i = 0;
while( i < updateAndTriggerWatchersI ) {
watchers[i].update();
i++;
}
updateAndTriggerWatchersI = watchers.length;
var j = 0,
newLength;
while( j < updateAndTriggerWatchersI ) {
watchers[j].triggerCallbacks();
newLength = watchers.length;
if (newLength < updateAndTriggerWatchersI) {
j -= updateAndTriggerWatchersI - newLength;
}
updateAndTriggerWatchersI = newLength;
j++;
}
}
function ElementWatcher( watchItem, offsets ) {
var self = this;
this.watchItem = watchItem;
this.uid = Math.random().toString(36).substring(8);
if (!offsets) {
this.offsets = defaultOffsets;
} else if (offsets === +offsets) {
this.offsets = {top: offsets, bottom: offsets};
} else {
this.offsets = {
top: offsets.top || defaultOffsets.top,
bottom: offsets.bottom || defaultOffsets.bottom
};
}
this.callbacks = {}; // {callback: function, isOne: true }
for (var i = 0, j = eventTypes.length; i < j; i++) {
self.callbacks[eventTypes[i]] = [];
}
this.locked = false;
var wasInViewport;
var wasFullyInViewport;
var wasAboveViewport;
var wasBelowViewport;
var listenerToTriggerListI;
var listener;
function triggerCallbackArray( listeners ) {
if (listeners.length === 0) {
return;
}
listenerToTriggerListI = listeners.length;
while( listenerToTriggerListI-- ) {
listener = listeners[listenerToTriggerListI];
listener.callback.call( self, latestEvent );
if (listener.isOne) {
listeners.splice(listenerToTriggerListI, 1);
}
}
}
this.triggerCallbacks = function triggerCallbacks() {
if (this.isInViewport && !wasInViewport) {
triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
}
if (this.isFullyInViewport && !wasFullyInViewport) {
triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
}
if (this.isAboveViewport !== wasAboveViewport &&
this.isBelowViewport !== wasBelowViewport) {
triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );
// if you skip completely past this element
if (!wasFullyInViewport && !this.isFullyInViewport) {
triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
}
if (!wasInViewport && !this.isInViewport) {
triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
}
}
if (!this.isFullyInViewport && wasFullyInViewport) {
triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
}
if (!this.isInViewport && wasInViewport) {
triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
}
if (this.isInViewport !== wasInViewport) {
triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );
}
switch( true ) {
case wasInViewport !== this.isInViewport:
case wasFullyInViewport !== this.isFullyInViewport:
case wasAboveViewport !== this.isAboveViewport:
case wasBelowViewport !== this.isBelowViewport:
triggerCallbackArray( this.callbacks[STATECHANGE] );
}
wasInViewport = this.isInViewport;
wasFullyInViewport = this.isFullyInViewport;
wasAboveViewport = this.isAboveViewport;
wasBelowViewport = this.isBelowViewport;
};
this.recalculateLocation = function() {
if (this.locked) {
return;
}
var previousTop = this.top;
var previousBottom = this.bottom;
if (this.watchItem.nodeName) { // a dom element
var cachedDisplay = this.watchItem.style.display;
if (cachedDisplay === 'none') {
this.watchItem.style.display = '';
}
var boundingRect = this.watchItem.getBoundingClientRect();
this.top = boundingRect.top + exports.viewportTop;
this.bottom = boundingRect.bottom + exports.viewportTop;
if (cachedDisplay === 'none') {
this.watchItem.style.display = cachedDisplay;
}
} else if (this.watchItem === +this.watchItem) { // number
if (this.watchItem > 0) {
this.top = this.bottom = this.watchItem;
} else {
this.top = this.bottom = exports.documentHeight - this.watchItem;
}
} else { // an object with a top and bottom property
this.top = this.watchItem.top;
this.bottom = this.watchItem.bottom;
}
this.top -= this.offsets.top;
this.bottom += this.offsets.bottom;
this.height = this.bottom - this.top;
if ( (previousTop !== undefined || previousBottom !== undefined) && (this.top !== previousTop || this.bottom !== previousBottom) ) {
triggerCallbackArray( this.callbacks[LOCATIONCHANGE] );
}
};
this.recalculateLocation();
this.update();
wasInViewport = this.isInViewport;
wasFullyInViewport = this.isFullyInViewport;
wasAboveViewport = this.isAboveViewport;
wasBelowViewport = this.isBelowViewport;
}
ElementWatcher.prototype = {
on: function( event, callback, isOne ) {
// trigger the event if it applies to the element right now.
switch( true ) {
case event === VISIBILITYCHANGE && !this.isInViewport && this.isAboveViewport:
case event === ENTERVIEWPORT && this.isInViewport:
case event === FULLYENTERVIEWPORT && this.isFullyInViewport:
case event === EXITVIEWPORT && this.isAboveViewport && !this.isInViewport:
case event === PARTIALLYEXITVIEWPORT && this.isAboveViewport:
callback.call( this, latestEvent );
if (isOne) {
return;
}
}
if (this.callbacks[event]) {
this.callbacks[event].push({callback: callback, isOne: isOne||false});
} else {
throw new Error('Tried to add a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
}
},
off: function( event, callback ) {
if (this.callbacks[event]) {
for (var i = 0, item; item = this.callbacks[event][i]; i++) {
if (item.callback === callback) {
this.callbacks[event].splice(i, 1);
break;
}
}
} else {
throw new Error('Tried to remove a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
}
},
one: function( event, callback ) {
this.on( event, callback, true);
},
recalculateSize: function() {
this.height = this.watchItem.offsetHeight + this.offsets.top + this.offsets.bottom;
this.bottom = this.top + this.height;
},
update: function() {
this.isAboveViewport = this.top < exports.viewportTop;
this.isBelowViewport = this.bottom > exports.viewportBottom;
this.isInViewport = (this.top <= exports.viewportBottom && this.bottom >= exports.viewportTop);
this.isFullyInViewport = (this.top >= exports.viewportTop && this.bottom <= exports.viewportBottom) ||
(this.isAboveViewport && this.isBelowViewport);
},
destroy: function() {
var index = -1,
self = this;
for (var i = 0; i < watchers.length; i++) {
if (this.uid == watchers[i].uid) {
index = i;
break;
}
}
if (index == -1) {
index = watchers.indexOf(this);
}
watchers.splice(index, 1);
for (var i = 0, j = eventTypes.length; i < j; i++) {
self.callbacks[eventTypes[i]].length = 0;
}
},
// prevent recalculating the element location
lock: function() {
this.locked = true;
},
unlock: function() {
this.locked = false;
}
};
var eventHandlerFactory = function (type) {
return function( callback, isOne ) {
this.on.call(this, type, callback, isOne);
};
};
for (var i = 0, j = eventTypes.length; i < j; i++) {
var type = eventTypes[i];
ElementWatcher.prototype[type] = eventHandlerFactory(type);
}
try {
calculateViewport();
} catch (e) {
try {
window.$(calculateViewport);
} catch (e) {
throw new Error('If you must put scrollMonitor in the <head>, you must use jQuery.');
}
}
function scrollMonitorListener(event) {
latestEvent = event;
calculateViewport();
updateAndTriggerWatchers();
}
if (window.addEventListener) {
window.addEventListener('scroll', scrollMonitorListener);
window.addEventListener('resize', debouncedRecalcuateAndTrigger);
} else {
// Old IE support
window.attachEvent('onscroll', scrollMonitorListener);
window.attachEvent('onresize', debouncedRecalcuateAndTrigger);
}
exports.beget = exports.create = function( element, offsets ) {
if (typeof element === 'string') {
element = document.querySelector(element);
} else if (element && element.length > 0) {
element = element[0];
}
var watcher = new ElementWatcher( element, offsets );
watchers.push(watcher);
watcher.update();
return watcher;
};
exports.update = function() {
latestEvent = null;
calculateViewport();
updateAndTriggerWatchers();
};
exports.recalculateLocations = function() {
exports.documentHeight = 0;
exports.update();
};
return exports;
});