intersection-observer-admin
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -1,1 +0,277 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.intersectionObserverAdmin=t()}(this,function(){"use strict";var e,t,n=(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(){this.DOMRef=new WeakMap}return e.prototype.observe=function(e,t,n,r,o){var i;if(e&&r){var s,f=r.root,a=void 0===f?window:f,c=this._findRoot(a);if(c&&(s=this._determineMatchingElements(r,c)),s){var u=s.elements,p=s.intersectionObserver;return u.push({element:e,enterCallback:t,exitCallback:n}),void p.observe(e)}var l=new IntersectionObserver(this._setupOnIntersection(r,o).bind(this),r);l.observe(e);var v={elements:[{element:e,enterCallback:t,exitCallback:n}],intersectionObserver:l,observerOptions:r},b=this._stringifyObserverOptions(r,o);c?c[b]=v:this.DOMRef&&this.DOMRef.set(a,((i={})[b]=v,i))}},e.prototype.unobserve=function(e,t,n){var r=this._findMatchingRootEntry(t,n);if(r){var o=r.intersectionObserver,i=r.elements;o.unobserve(e);for(var s=i.length-1;0<=s;s--)if(i[s]&&i[s].element===e){i.splice(s,1);break}}},e.prototype.destroy=function(){this.DOMRef=null},e.prototype._setupOnIntersection=function(t,n){var r=this;return function(e){return r._onIntersection(t,n,e)}},e.prototype._onIntersection=function(o,i,e){var s=this;e.forEach(function(t){var e=t.isIntersecting,n=t.intersectionRatio;if(e)(r=s._findMatchingRootEntry(o,i))&&r.elements.some(function(e){return e.element===t.target&&(e.enterCallback&&e.enterCallback(),!0)});else if(n<=0){var r;(r=s._findMatchingRootEntry(o,i))&&r.elements.some(function(e){return e.element===t.target&&(e.exitCallback&&e.exitCallback(),!0)})}})},e.prototype._findRoot=function(e){if(this.DOMRef)return this.DOMRef.get(e)},e.prototype._findMatchingRootEntry=function(e,t){var n=e.root,r=void 0===n?window:n,o=this._findRoot(r);if(o)return o[this._stringifyObserverOptions(e,t)]},e.prototype._determineMatchingElements=function(n,r){var o=this;if(r){var e=Object.keys(r).filter(function(e){var t=r[e].observerOptions;return o._areOptionsSame(n,t)})[0];return r[e]}},e.prototype._areOptionsSame=function(e,t){var n=Object.prototype.toString.call(e),r=Object.prototype.toString.call(t);if(n!==r)return!1;if("[object Object]"!==n&&"[object Object]"!==r)return e===t;for(var o in e)if(e.hasOwnProperty(o)&&!1===this._areOptionsSame(e[o],t[o]))return!1;return!0},e.prototype._stringifyObserverOptions=function(e,n){return JSON.stringify(e,function(e,t){return"root"===e&&n?n:t})},e}();t.default=n}(e={exports:{}},e.exports),e.exports);return(t=n)&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}); | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.intersectionObserverAdmin = factory()); | ||
}(this, (function () { 'use strict'; | ||
function unwrapExports (x) { | ||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x.default : x; | ||
} | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
var es = createCommonjsModule(function (module, exports) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var IntersectionObserverAdmin = /** @class */ (function () { | ||
function IntersectionObserverAdmin() { | ||
this.DOMRef = new WeakMap(); | ||
} | ||
/** | ||
* Adds element to observe via IntersectionObserver and stores element + relevant callbacks and observer options in static | ||
* administrator for lookup in the future | ||
* | ||
* @method add | ||
* @param {HTMLElement | Window} element | ||
* @param {Function} enterCallback | ||
* @param {Function} exitCallback | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
* @public | ||
*/ | ||
IntersectionObserverAdmin.prototype.observe = function (element, enterCallback, exitCallback, observerOptions, scrollableArea) { | ||
var _a; | ||
if (!element || !observerOptions) { | ||
return; | ||
} | ||
var _b = observerOptions.root, root = _b === void 0 ? window : _b; | ||
// first find shared root element (window or scrollable area) | ||
var potentialRootMatch = this._findRoot(root); | ||
// second if there is a matching root, find an entry with the same observerOptions | ||
var matchingEntryForRoot; | ||
if (potentialRootMatch) { | ||
matchingEntryForRoot = this._determineMatchingElements(observerOptions, potentialRootMatch); | ||
} | ||
if (matchingEntryForRoot) { | ||
var elements = matchingEntryForRoot.elements, intersectionObserver = matchingEntryForRoot.intersectionObserver; | ||
elements.push({ element: element, enterCallback: enterCallback, exitCallback: exitCallback }); | ||
intersectionObserver.observe(element); | ||
return; | ||
} | ||
// No matching entry for root in static admin, thus create new IntersectionObserver instance | ||
var newIO = new IntersectionObserver(this._setupOnIntersection(observerOptions, scrollableArea).bind(this), observerOptions); | ||
newIO.observe(element); | ||
var observerEntry = { | ||
elements: [{ element: element, enterCallback: enterCallback, exitCallback: exitCallback }], | ||
intersectionObserver: newIO, | ||
observerOptions: observerOptions | ||
}; | ||
var stringifiedOptions = this._stringifyObserverOptions(observerOptions, scrollableArea); | ||
if (potentialRootMatch) { | ||
// if share same root and need to add new entry to root match | ||
potentialRootMatch[stringifiedOptions] = observerEntry; | ||
} | ||
else { | ||
// no root exists, so add to WeakMap | ||
if (this.DOMRef) { | ||
this.DOMRef.set(root, (_a = {}, _a[stringifiedOptions] = observerEntry, _a)); | ||
} | ||
} | ||
}; | ||
/** | ||
* Unobserve target element and remove element from static admin | ||
* | ||
* @method unobserve | ||
* @param {HTMLElement|Window} target | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
* @public | ||
*/ | ||
IntersectionObserverAdmin.prototype.unobserve = function (target, observerOptions, scrollableArea) { | ||
var matchingRootEntry = this._findMatchingRootEntry(observerOptions, scrollableArea); | ||
if (matchingRootEntry) { | ||
var intersectionObserver = matchingRootEntry.intersectionObserver, elements = matchingRootEntry.elements; | ||
intersectionObserver.unobserve(target); | ||
// important to do this in reverse order | ||
for (var i = elements.length - 1; i >= 0; i--) { | ||
if (elements[i] && elements[i].element === target) { | ||
elements.splice(i, 1); | ||
break; | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* cleanup data structures and unobserve elements | ||
* | ||
* @method destroy | ||
* @public | ||
*/ | ||
IntersectionObserverAdmin.prototype.destroy = function () { | ||
this.DOMRef = null; | ||
}; | ||
/** | ||
* use function composition to curry observerOptions | ||
* | ||
* @method _setupOnIntersection | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
*/ | ||
IntersectionObserverAdmin.prototype._setupOnIntersection = function (observerOptions, scrollableArea) { | ||
var _this = this; | ||
return function (entries) { | ||
return _this._onIntersection(observerOptions, scrollableArea, entries); | ||
}; | ||
}; | ||
/** | ||
* IntersectionObserver callback when element is intersecting viewport | ||
* | ||
* @method _onIntersection | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
* @param {Array} ioEntries | ||
* @private | ||
*/ | ||
IntersectionObserverAdmin.prototype._onIntersection = function (observerOptions, scrollableArea, ioEntries) { | ||
var _this = this; | ||
ioEntries.forEach(function (entry) { | ||
var isIntersecting = entry.isIntersecting, intersectionRatio = entry.intersectionRatio; | ||
// first determine if entry intersecting | ||
if (isIntersecting) { | ||
// then find entry's callback in static administration | ||
var matchingRootEntry = _this._findMatchingRootEntry(observerOptions, scrollableArea); | ||
if (matchingRootEntry) { | ||
matchingRootEntry.elements.some(function (obj) { | ||
if (obj.element === entry.target) { | ||
// call entry's enter callback | ||
if (obj.enterCallback) { | ||
obj.enterCallback(); | ||
} | ||
return true; | ||
} | ||
return false; | ||
}); | ||
} | ||
} | ||
else if (intersectionRatio <= 0) { | ||
// then find entry's callback in static administration | ||
var matchingRootEntry = _this._findMatchingRootEntry(observerOptions, scrollableArea); | ||
if (matchingRootEntry) { | ||
matchingRootEntry.elements.some(function (obj) { | ||
if (obj.element === entry.target) { | ||
// call entry's enter callback | ||
if (obj.exitCallback) { | ||
obj.exitCallback(); | ||
} | ||
return true; | ||
} | ||
return false; | ||
}); | ||
} | ||
} | ||
}); | ||
}; | ||
/** | ||
* { root: { stringifiedOptions: { elements: []...] } } | ||
* @method _findRoot | ||
* @param {HTMLElement|Window} root | ||
* @private | ||
* @return {Object} of elements that share same root | ||
*/ | ||
IntersectionObserverAdmin.prototype._findRoot = function (root) { | ||
if (this.DOMRef) { | ||
return this.DOMRef.get(root); | ||
} | ||
}; | ||
/** | ||
* Used for onIntersection callbacks and unobserving the IntersectionObserver | ||
* We don't care about observerOptions key order because we already added | ||
* to the static administrator or found an existing IntersectionObserver with the same | ||
* root && observerOptions to reuse | ||
* | ||
* @method _findMatchingRootEntry | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
* @return {Object} entry with elements and other options | ||
*/ | ||
IntersectionObserverAdmin.prototype._findMatchingRootEntry = function (observerOptions, scrollableArea) { | ||
var _a = observerOptions.root, root = _a === void 0 ? window : _a; | ||
var matchingRoot = this._findRoot(root); | ||
if (matchingRoot) { | ||
var stringifiedOptions = this._stringifyObserverOptions(observerOptions, scrollableArea); | ||
return matchingRoot[stringifiedOptions]; | ||
} | ||
}; | ||
/** | ||
* Determine if existing elements for a given root based on passed in observerOptions | ||
* regardless of sort order of keys | ||
* | ||
* @method _determineMatchingElements | ||
* @param {Object} observerOptions | ||
* @param {Object} potentialRootMatch e.g. { stringifiedOptions: { elements: [], ... }, stringifiedOptions: { elements: [], ... }} | ||
* @private | ||
* @return {Object} containing array of elements and other meta | ||
*/ | ||
IntersectionObserverAdmin.prototype._determineMatchingElements = function (observerOptions, potentialRootMatch) { | ||
var _this = this; | ||
if (!potentialRootMatch) { | ||
return; | ||
} | ||
var matchingKey = Object.keys(potentialRootMatch).filter(function (key) { | ||
var comparableOptions = potentialRootMatch[key].observerOptions; | ||
return _this._areOptionsSame(observerOptions, comparableOptions); | ||
})[0]; | ||
return potentialRootMatch[matchingKey]; | ||
}; | ||
/** | ||
* recursive method to test primitive string, number, null, etc and complex | ||
* object equality. | ||
* | ||
* @method _areOptionsSame | ||
* @param {Object} observerOptions | ||
* @param {Object} comparableOptions | ||
* @private | ||
* @return {Boolean} | ||
*/ | ||
IntersectionObserverAdmin.prototype._areOptionsSame = function (observerOptions, comparableOptions) { | ||
// simple comparison of string, number or even null/undefined | ||
var type1 = Object.prototype.toString.call(observerOptions); | ||
var type2 = Object.prototype.toString.call(comparableOptions); | ||
if (type1 !== type2) { | ||
return false; | ||
} | ||
else if (type1 !== '[object Object]' && type2 !== '[object Object]') { | ||
return observerOptions === comparableOptions; | ||
} | ||
// complex comparison for only type of [object Object] | ||
for (var key in observerOptions) { | ||
if (observerOptions.hasOwnProperty(key)) { | ||
// recursion to check nested | ||
if (this._areOptionsSame(observerOptions[key], comparableOptions[key]) === | ||
false) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
}; | ||
/** | ||
* Stringify observerOptions for use as a key. | ||
* Excludes observerOptions.root so that the resulting key is stable | ||
* | ||
* @param {Object} observerOptions | ||
* @param {String} scrollableArea | ||
* @private | ||
* @return {String} | ||
*/ | ||
IntersectionObserverAdmin.prototype._stringifyObserverOptions = function (observerOptions, scrollableArea) { | ||
var replacer = function (key, value) { | ||
if (key === 'root' && scrollableArea) { | ||
return scrollableArea; | ||
} | ||
return value; | ||
}; | ||
return JSON.stringify(observerOptions, replacer); | ||
}; | ||
return IntersectionObserverAdmin; | ||
}()); | ||
exports.default = IntersectionObserverAdmin; | ||
}); | ||
var index = unwrapExports(es); | ||
return index; | ||
}))); |
{ | ||
"name": "intersection-observer-admin", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Intersection Observer Admin for better performance", | ||
@@ -5,0 +5,0 @@ "main": "dist/intersection-observer-admin.umd.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38092
654