Created
December 2, 2018 17:10
-
-
Save snewcomer/c026f325cb4812a8e1daf622f611a305 to your computer and use it in GitHub Desktop.
io-observer-es5-dist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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; | |
}))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment