@webcreate/infinite-ajax-scroll
Advanced tools
Comparing version 3.0.0-beta.6 to 3.0.0-rc.1
/** | ||
* Infinite Ajax Scroll v3.0.0-beta.6 | ||
* Infinite Ajax Scroll v3.0.0-rc.1 | ||
* Turn your existing pagination into infinite scrolling pages with ease | ||
@@ -8,3 +8,3 @@ * | ||
* | ||
* Copyright 2014-2020 Webcreate (Jeroen Fiege) | ||
* Copyright 2014-2021 Webcreate (Jeroen Fiege) | ||
* https://infiniteajaxscroll.com | ||
@@ -17,3 +17,3 @@ */ | ||
var defaults = { | ||
var defaults$3 = { | ||
item: undefined, | ||
@@ -30,4 +30,7 @@ next: undefined, | ||
trigger: false, | ||
prefill: true, | ||
}; | ||
/* eslint no-console: "off" */ | ||
var Assert = { | ||
@@ -106,10 +109,16 @@ singleElement: function singleElement(elementOrSelector, property) { | ||
function getDistanceToFold(el, scrollContainer) { | ||
var scroll = getScrollPosition(scrollContainer); | ||
var rootRect = getRootRect(scrollContainer); | ||
var boundingRect = el.getBoundingClientRect(); | ||
function getDistanceToFold(sentinel, scrollContainerScrollPosition, scrollContainerRootRect) { | ||
var rootRect = scrollContainerRootRect; | ||
var scrollYBottom = scroll.y + rootRect.height; | ||
var bottom = scroll.y + boundingRect.bottom - rootRect.top; | ||
// this means the container the doesn't have any items yet - it's empty | ||
if (!sentinel) { | ||
return rootRect.height * -1; | ||
} | ||
var scrollYTop = scrollContainerScrollPosition.y; | ||
var boundingRect = sentinel.getBoundingClientRect(); | ||
var scrollYBottom = scrollYTop + rootRect.height; | ||
var bottom = scrollYTop + boundingRect.bottom - rootRect.top; | ||
return Math.trunc(bottom - scrollYBottom); | ||
@@ -125,8 +134,31 @@ } | ||
var LOADED = 'loaded'; | ||
var ERROR = 'error'; | ||
var LAST = 'last'; | ||
var NEXT = 'next'; | ||
var READY = 'ready'; | ||
var SCROLLED = 'scrolled'; | ||
var RESIZED = 'resized'; | ||
var PAGE = 'page'; | ||
var PREFILL = 'prefill'; | ||
var PREFILLED = 'prefilled'; | ||
var events = { | ||
APPEND: APPEND, | ||
APPENDED: APPENDED, | ||
BINDED: BINDED, | ||
UNBINDED: UNBINDED, | ||
HIT: HIT, | ||
LOAD: LOAD, | ||
LOADED: LOADED, | ||
ERROR: ERROR, | ||
LAST: LAST, | ||
NEXT: NEXT, | ||
READY: READY, | ||
SCROLLED: SCROLLED, | ||
RESIZED: RESIZED, | ||
PAGE: PAGE, | ||
PREFILL: PREFILL, | ||
PREFILLED: PREFILLED, | ||
}; | ||
var defaultLastScroll = { | ||
@@ -201,3 +233,3 @@ y: 0, | ||
var defaults$1 = { | ||
var defaults$2 = { | ||
element: undefined, | ||
@@ -207,3 +239,3 @@ hide: false | ||
function expand(options) { | ||
function expand$3(options) { | ||
if (typeof options === 'string' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -225,3 +257,3 @@ options = { | ||
var Pagination = function Pagination(ias, options) { | ||
this.options = extend({}, defaults$1, expand(options)); | ||
this.options = extend({}, defaults$2, expand$3(options)); | ||
this.originalDisplayStyles = new WeakMap(); | ||
@@ -240,3 +272,3 @@ | ||
Pagination.prototype.hide = function hide () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -246,3 +278,3 @@ var els = $(this.options.element); | ||
els.forEach(function (el) { | ||
this$1.originalDisplayStyles.set(el, window.getComputedStyle(el).display); | ||
this$1$1.originalDisplayStyles.set(el, window.getComputedStyle(el).display); | ||
@@ -254,3 +286,3 @@ el.style.display = 'none'; | ||
Pagination.prototype.restore = function restore () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -260,7 +292,7 @@ var els = $(this.options.element); | ||
els.forEach(function (el) { | ||
el.style.display = this$1.originalDisplayStyles.get(el) || 'block'; | ||
el.style.display = this$1$1.originalDisplayStyles.get(el) || 'block'; | ||
}); | ||
}; | ||
var defaults$2 = { | ||
var defaults$1 = { | ||
element: undefined, | ||
@@ -276,3 +308,3 @@ delay: 600, | ||
function expand$1(options) { | ||
function expand$2(options) { | ||
if (typeof options === 'string' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -294,3 +326,3 @@ options = { | ||
this.ias = ias; | ||
this.options = extend({}, defaults$2, expand$1(options)); | ||
this.options = extend({}, defaults$1, expand$2(options)); | ||
@@ -394,6 +426,12 @@ if (this.options.element !== undefined) { | ||
console.log(("Page changed [pageIndex=" + (event.pageIndex) + "]")); | ||
} | ||
}, | ||
prefill: function (event) { | ||
console.log("Start prefilling"); | ||
}, | ||
prefilled: function (event) { | ||
console.log("Finished prefilling"); | ||
}, | ||
}; | ||
function expand$2(options) { | ||
function expand$1(options) { | ||
if (options === true) { | ||
@@ -412,3 +450,3 @@ options = defaultLogger; | ||
var logger = expand$2(options); | ||
var logger = expand$1(options); | ||
@@ -464,3 +502,3 @@ Object.keys(logger).forEach(function (key) { | ||
Paging.prototype.next = function next (nextEvent) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -470,3 +508,2 @@ var url = document.location.toString(); | ||
// @todo can be moved inside appended when eventStack is implemented | ||
var loaded = function (event) { | ||
@@ -482,14 +519,13 @@ url = event.url; | ||
this.ias.once(APPENDED, function () { | ||
this$1.pageBreaks.push({ | ||
nextEvent.promise.then(function () { | ||
this$1$1.pageBreaks.push({ | ||
pageIndex: nextEvent.pageIndex, | ||
url: url, | ||
title: title, | ||
sentinel: this$1.ias.sentinel() | ||
sentinel: this$1$1.ias.sentinel() | ||
}); | ||
this$1.update(); | ||
this$1$1.update(); | ||
// @todo can be removed when eventStack is implemented | ||
this$1.ias.off(LOADED, loaded); | ||
this$1$1.ias.off(LOADED, loaded); | ||
}); | ||
@@ -514,3 +550,3 @@ }; | ||
var defaults$3 = { | ||
var defaults = { | ||
element: undefined, | ||
@@ -526,3 +562,3 @@ when: function (pageIndex) { return true; }, | ||
function expand$3(options) { | ||
function expand(options) { | ||
if (typeof options === 'string' || typeof options === 'function' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -551,3 +587,3 @@ options = { | ||
var Trigger = function Trigger(ias, options) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -560,3 +596,3 @@ // no trigger wanted | ||
this.ias = ias; | ||
this.options = extend({}, defaults$3, expand$3(options)); | ||
this.options = extend({}, defaults, expand(options)); | ||
@@ -577,3 +613,3 @@ if (this.options.element !== undefined) { | ||
ias.on(HIT, this.hit.bind(this)); | ||
ias.on(NEXT, function (e) { return this$1.ias.once(APPENDED, function () { return this$1.update(e.pageIndex); }); }); | ||
ias.on(NEXT, function (e) { return this$1$1.ias.once(APPENDED, function () { return this$1$1.update(e.pageIndex); }); }); | ||
}; | ||
@@ -593,5 +629,5 @@ | ||
Trigger.prototype.clickHandler = function clickHandler () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
this.hide().then(function () { return this$1.ias.next(); }); | ||
this.hide().then(function () { return this$1$1.ias.next(); }); | ||
}; | ||
@@ -648,4 +684,122 @@ | ||
/* eslint no-console: "off" */ | ||
var NativeResizeObserver = window.ResizeObserver; | ||
var EventListenerResizeObserver = function EventListenerResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
}; | ||
EventListenerResizeObserver.prototype.observe = function observe () { | ||
this.el.addEventListener('resize', this.listener); | ||
}; | ||
EventListenerResizeObserver.prototype.unobserve = function unobserve () { | ||
this.el.removeEventListener('resize', this.listener); | ||
}; | ||
var NativeWrapperResizeObserver = function NativeWrapperResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
this.ro = new NativeResizeObserver(this.listener); | ||
}; | ||
NativeWrapperResizeObserver.prototype.observe = function observe () { | ||
this.ro.observe(this.el); | ||
}; | ||
NativeWrapperResizeObserver.prototype.unobserve = function unobserve () { | ||
this.ro.unobserve(); | ||
}; | ||
var PollingResizeObserver = function PollingResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
this.interval = null; | ||
this.lastHeight = null; | ||
}; | ||
PollingResizeObserver.prototype.pollHeight = function pollHeight () { | ||
var height = Math.trunc(getRootRect(this.el).height); | ||
if (this.lastHeight !== null && this.lastHeight !== height) { | ||
this.listener(); | ||
} | ||
this.lastHeight = height; | ||
}; | ||
PollingResizeObserver.prototype.observe = function observe () { | ||
this.interval = setInterval(this.pollHeight.bind(this), 200); | ||
}; | ||
PollingResizeObserver.prototype.unobserve = function unobserve () { | ||
clearInterval(this.interval); | ||
}; | ||
function ResizeObserverFactory(ias, el) { | ||
var listener = throttle(resizeHandler, 200).bind(ias); | ||
if (el === window) { | ||
return new EventListenerResizeObserver(el, listener); | ||
} | ||
if (NativeResizeObserver) { | ||
return new NativeWrapperResizeObserver(el, listener); | ||
} | ||
if (console && console.warn) { | ||
console.warn('ResizeObserver not supported. Falling back on polling.'); | ||
} | ||
return new PollingResizeObserver(el, listener); | ||
} | ||
var Prefill = function Prefill(ias, options) { | ||
this.ias = ias; | ||
this.enabled = options; | ||
}; | ||
Prefill.prototype.prefill = function prefill () { | ||
var this$1$1 = this; | ||
if (!this.enabled) { | ||
return; | ||
} | ||
var distance = this.ias.distance(); | ||
if (distance > 0) { | ||
return; | ||
} | ||
this.ias.emitter.emit(events.PREFILL); | ||
return this._prefill().then(function () { | ||
this$1$1.ias.emitter.emit(events.PREFILLED); | ||
// @todo reevaluate if we should actually call `measure` here. | ||
this$1$1.ias.measure(); | ||
}); | ||
}; | ||
Prefill.prototype._prefill = function _prefill () { | ||
var this$1$1 = this; | ||
return this.ias.next().then(function (hasNextUrl) { | ||
if (!hasNextUrl) { | ||
return; | ||
} | ||
var distance = this$1$1.ias.distance(); | ||
if (distance < 0) { | ||
return this$1$1._prefill(); | ||
} | ||
}); | ||
}; | ||
var InfiniteAjaxScroll = function InfiniteAjaxScroll(container, options) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
if ( options === void 0 ) options = {}; | ||
@@ -656,8 +810,6 @@ | ||
this.container = $(container)[0]; | ||
this.options = extend({}, defaults, options); | ||
this.options = extend({}, defaults$3, options); | ||
this.emitter = new Emitter(); | ||
// @todo might need to call enableLoadOnScroll (or disableLoadOnScroll) | ||
// instead of injecting the value right away | ||
this.loadOnScroll = this.options.loadOnScroll; | ||
this.options.loadOnScroll ? this.enableLoadOnScroll() : this.disableLoadOnScroll(); | ||
this.negativeMargin = Math.abs(this.options.negativeMargin); | ||
@@ -680,2 +832,7 @@ | ||
this.resizeObserver = ResizeObserverFactory(this, this.scrollContainer); | ||
this._scrollListener = throttle(scrollHandler, 200).bind(this); | ||
this.ready = false; | ||
this.bindOnReady = true; | ||
this.binded = false; | ||
@@ -686,7 +843,7 @@ this.paused = false; | ||
this.on(HIT, function () { | ||
if (!this$1.loadOnScroll) { | ||
if (!this$1$1.loadOnScroll) { | ||
return; | ||
} | ||
this$1.next(); | ||
this$1$1.next(); | ||
}); | ||
@@ -703,10 +860,25 @@ | ||
this.trigger = new Trigger(this, this.options.trigger); | ||
this.prefill = new Prefill(this, this.options.prefill); | ||
// @todo review this logic when prefill support is added | ||
// measure after all plugins are done binding | ||
this.on(BINDED, this.measure); | ||
// prefill/measure after all plugins are done binding | ||
this.on(BINDED, this.prefill.prefill.bind(this.prefill)); | ||
if (this.options.bind) { | ||
// @todo on document.ready? (window.addEventListener('DOMContentLoaded')) | ||
this.bind(); | ||
var ready = function () { | ||
if (this$1$1.ready) { | ||
return; | ||
} | ||
this$1$1.ready = true; | ||
this$1$1.emitter.emit(READY); | ||
if (this$1$1.bindOnReady && this$1$1.options.bind) { | ||
this$1$1.bind(); | ||
} | ||
}; | ||
if (document.readyState === "complete" || document.readyState === "interactive") { | ||
setTimeout(ready, 1); | ||
} else { | ||
window.addEventListener('DOMContentLoaded', ready); | ||
} | ||
@@ -720,7 +892,10 @@ }; | ||
this._scrollListener = throttle(scrollHandler, 200).bind(this); | ||
this._resizeListener = throttle(resizeHandler, 200).bind(this); | ||
// If we manually call bind before the dom is ready, we assume that we want | ||
// to take control over the bind flow. | ||
if (!this.ready) { | ||
this.bindOnReady = false; | ||
} | ||
this.scrollContainer.addEventListener('scroll', this._scrollListener); | ||
this.scrollContainer.addEventListener('resize', this._resizeListener); | ||
this.resizeObserver.observe(); | ||
@@ -734,6 +909,10 @@ this.binded = true; | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
this.once(BINDED, this.unbind); | ||
} | ||
return; | ||
} | ||
this.scrollContainer.removeEventListener('resize', this._resizeListener); | ||
this.resizeObserver.unobserve(); | ||
this.scrollContainer.removeEventListener('scroll', this._scrollListener); | ||
@@ -747,27 +926,44 @@ | ||
InfiniteAjaxScroll.prototype.next = function next () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
return this.once(BINDED, this.next); | ||
} | ||
return; | ||
} | ||
this.pause(); | ||
var event = { | ||
pageIndex: this.pageIndex + 1, | ||
}; | ||
var pageIndex = this.pageIndex + 1; | ||
this.emitter.emit(NEXT, event); | ||
var promise = Promise.resolve(this.nextHandler(pageIndex)) | ||
.then(function (hasNextUrl) { | ||
this$1$1.pageIndex = pageIndex; | ||
return Promise.resolve(this.nextHandler(event.pageIndex)) | ||
.then(function (result) { | ||
this$1.pageIndex = event.pageIndex; | ||
if (!hasNextUrl) { | ||
this$1$1.emitter.emit(LAST); | ||
if (!result) { | ||
this$1.emitter.emit(LAST); | ||
return; | ||
} | ||
this$1.resume(); | ||
this$1$1.resume(); | ||
}) | ||
; | ||
var event = { | ||
pageIndex: this.pageIndex + 1, | ||
promise: promise | ||
}; | ||
this.emitter.emit(NEXT, event); | ||
return promise; | ||
}; | ||
/** | ||
* @param {string} url | ||
* @returns {Promise} returns LOADED event on success | ||
*/ | ||
InfiniteAjaxScroll.prototype.load = function load (url) { | ||
@@ -779,2 +975,28 @@ var ias = this; | ||
var loadEvent = { | ||
url: url, | ||
xhr: xhr, | ||
method: 'GET', | ||
body: null, | ||
nocache: false, | ||
responseType: ias.options.responseType, | ||
headers: { | ||
'X-Requested-With': 'XMLHttpRequest', | ||
}, | ||
}; | ||
// event properties are mutable | ||
ias.emitter.emit(LOAD, loadEvent); | ||
var finalUrl = loadEvent.url; | ||
var method = loadEvent.method; | ||
var responseType = loadEvent.responseType; | ||
var headers = loadEvent.headers; | ||
var body = loadEvent.body; | ||
if (!loadEvent.nocache) { | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
finalUrl = finalUrl + ((/\?/).test(finalUrl) ? "&" : "?") + (new Date()).getTime(); | ||
} | ||
xhr.onreadystatechange = function() { | ||
@@ -785,6 +1007,7 @@ if (xhr.readyState !== XMLHttpRequest.DONE) { | ||
if (xhr.status === 200) { | ||
if (xhr.status === 0) ; | ||
else if (xhr.status === 200) { | ||
var items = xhr.response; | ||
if (ias.options.responseType === 'document') { | ||
if (responseType === 'document') { | ||
items = $(ias.options.item, xhr.response); | ||
@@ -794,8 +1017,9 @@ // @todo assert there actually are items in the response | ||
ias.emitter.emit(LOADED, {items: items, url: url, xhr: xhr}); | ||
// we don't use a shared loadedEvent variable here, because these values should be immutable | ||
resolve({items: items, url: url, xhr: xhr}); | ||
ias.emitter.emit(LOADED, {items: items, url: finalUrl, xhr: xhr}); | ||
resolve({items: items, url: finalUrl, xhr: xhr}); | ||
} else { | ||
// @todo is console.error the best approach? | ||
console.error('Request failed'); | ||
ias.emitter.emit(ERROR, {url: finalUrl, method: method, xhr: xhr}); | ||
@@ -806,15 +1030,16 @@ reject(xhr); | ||
// FIXME: make no-caching configurable | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
var nocacheUrl = url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime(); | ||
xhr.onerror = function() { | ||
ias.emitter.emit(ERROR, {url: finalUrl, method: method, xhr: xhr}); | ||
xhr.open('GET', nocacheUrl, true); | ||
xhr.responseType = ias.options.responseType; | ||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); | ||
reject(xhr); | ||
}; | ||
// @todo define event variable and pass that around so it can be manipulated | ||
xhr.open(method, finalUrl, true); | ||
xhr.responseType = responseType; | ||
ias.emitter.emit(LOAD, {url: url, xhr: xhr}); | ||
for (var header in headers) { | ||
xhr.setRequestHeader(header, headers[header]); | ||
} | ||
xhr.send(); | ||
xhr.send(body); | ||
}); | ||
@@ -868,4 +1093,2 @@ }; | ||
this.paused = false; | ||
this.measure(); | ||
}; | ||
@@ -881,2 +1104,17 @@ | ||
InfiniteAjaxScroll.prototype.distance = function distance (rootRect, sentinel) { | ||
var _rootRect = rootRect || getRootRect(this.scrollContainer); | ||
var _sentinel = sentinel || this.sentinel(); | ||
var scrollPosition = getScrollPosition(this.scrollContainer); | ||
var distance = getDistanceToFold(_sentinel, scrollPosition, _rootRect); | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
return distance; | ||
}; | ||
InfiniteAjaxScroll.prototype.measure = function measure () { | ||
@@ -887,13 +1125,18 @@ if (this.paused) { | ||
var distance = 0; | ||
var sentinel = this.sentinel(); | ||
var rootRect = getRootRect(this.scrollContainer); | ||
// @todo review this logic when prefill support is added | ||
if (sentinel) { | ||
distance = getDistanceToFold(sentinel, this.scrollContainer); | ||
// When the scroll container has no height, this could indicate that | ||
// the element is not visible (display = none). Without a height | ||
// we cannot calculate the distance to fold. On the other hand we don't | ||
// have to, because it's not visible anyway. Our resize observer will | ||
// monitor the height, once it's greater than 0 everything will resume as normal. | ||
if (rootRect.height === 0) { | ||
// @todo DX: show warning in console that this is happening | ||
return; | ||
} | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
var sentinel = this.sentinel(); | ||
var distance = this.distance(rootRect, sentinel); | ||
if (distance <= 0) { | ||
@@ -917,9 +1160,14 @@ this.emitter.emit(HIT, {distance: distance}); | ||
InfiniteAjaxScroll.prototype.once = function once (event, callback) { | ||
this.emitter.once(event, callback, this); | ||
var this$1$1 = this; | ||
if (event === BINDED && this.binded) { | ||
callback.bind(this)(); | ||
} | ||
return new Promise(function (resolve) { | ||
this$1$1.emitter.once(event, function() { Promise.resolve(callback.apply(this, arguments)).then(resolve); }, this$1$1); | ||
if (event === BINDED && this$1$1.binded) { | ||
callback.bind(this$1$1)(); | ||
resolve(); | ||
} | ||
}) | ||
}; | ||
export default InfiniteAjaxScroll; | ||
export { InfiniteAjaxScroll as default }; |
/** | ||
* Infinite Ajax Scroll v3.0.0-beta.6 | ||
* Infinite Ajax Scroll v3.0.0-rc.1 | ||
* Turn your existing pagination into infinite scrolling pages with ease | ||
@@ -8,3 +8,3 @@ * | ||
* | ||
* Copyright 2014-2020 Webcreate (Jeroen Fiege) | ||
* Copyright 2014-2021 Webcreate (Jeroen Fiege) | ||
* https://infiniteajaxscroll.com | ||
@@ -15,3 +15,3 @@ */ | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global.InfiniteAjaxScroll = factory()); | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.InfiniteAjaxScroll = factory()); | ||
}(this, (function () { 'use strict'; | ||
@@ -689,3 +689,3 @@ | ||
var defaults = { | ||
var defaults$3 = { | ||
item: undefined, | ||
@@ -702,4 +702,7 @@ next: undefined, | ||
trigger: false, | ||
prefill: true, | ||
}; | ||
/* eslint no-console: "off" */ | ||
var Assert = { | ||
@@ -778,10 +781,16 @@ singleElement: function singleElement(elementOrSelector, property) { | ||
function getDistanceToFold(el, scrollContainer) { | ||
var scroll = getScrollPosition(scrollContainer); | ||
var rootRect = getRootRect(scrollContainer); | ||
var boundingRect = el.getBoundingClientRect(); | ||
function getDistanceToFold(sentinel, scrollContainerScrollPosition, scrollContainerRootRect) { | ||
var rootRect = scrollContainerRootRect; | ||
var scrollYBottom = scroll.y + rootRect.height; | ||
var bottom = scroll.y + boundingRect.bottom - rootRect.top; | ||
// this means the container the doesn't have any items yet - it's empty | ||
if (!sentinel) { | ||
return rootRect.height * -1; | ||
} | ||
var scrollYTop = scrollContainerScrollPosition.y; | ||
var boundingRect = sentinel.getBoundingClientRect(); | ||
var scrollYBottom = scrollYTop + rootRect.height; | ||
var bottom = scrollYTop + boundingRect.bottom - rootRect.top; | ||
return Math.trunc(bottom - scrollYBottom); | ||
@@ -797,8 +806,31 @@ } | ||
var LOADED = 'loaded'; | ||
var ERROR = 'error'; | ||
var LAST = 'last'; | ||
var NEXT = 'next'; | ||
var READY = 'ready'; | ||
var SCROLLED = 'scrolled'; | ||
var RESIZED = 'resized'; | ||
var PAGE = 'page'; | ||
var PREFILL = 'prefill'; | ||
var PREFILLED = 'prefilled'; | ||
var events = { | ||
APPEND: APPEND, | ||
APPENDED: APPENDED, | ||
BINDED: BINDED, | ||
UNBINDED: UNBINDED, | ||
HIT: HIT, | ||
LOAD: LOAD, | ||
LOADED: LOADED, | ||
ERROR: ERROR, | ||
LAST: LAST, | ||
NEXT: NEXT, | ||
READY: READY, | ||
SCROLLED: SCROLLED, | ||
RESIZED: RESIZED, | ||
PAGE: PAGE, | ||
PREFILL: PREFILL, | ||
PREFILLED: PREFILLED, | ||
}; | ||
var defaultLastScroll = { | ||
@@ -941,3 +973,3 @@ y: 0, | ||
var defaults$1 = { | ||
var defaults$2 = { | ||
element: undefined, | ||
@@ -947,3 +979,3 @@ hide: false | ||
function expand(options) { | ||
function expand$3(options) { | ||
if (typeof options === 'string' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -965,3 +997,3 @@ options = { | ||
var Pagination = function Pagination(ias, options) { | ||
this.options = extend({}, defaults$1, expand(options)); | ||
this.options = extend({}, defaults$2, expand$3(options)); | ||
this.originalDisplayStyles = new WeakMap(); | ||
@@ -980,3 +1012,3 @@ | ||
Pagination.prototype.hide = function hide () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -986,3 +1018,3 @@ var els = tealight(this.options.element); | ||
els.forEach(function (el) { | ||
this$1.originalDisplayStyles.set(el, window.getComputedStyle(el).display); | ||
this$1$1.originalDisplayStyles.set(el, window.getComputedStyle(el).display); | ||
@@ -994,3 +1026,3 @@ el.style.display = 'none'; | ||
Pagination.prototype.restore = function restore () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -1000,7 +1032,7 @@ var els = tealight(this.options.element); | ||
els.forEach(function (el) { | ||
el.style.display = this$1.originalDisplayStyles.get(el) || 'block'; | ||
el.style.display = this$1$1.originalDisplayStyles.get(el) || 'block'; | ||
}); | ||
}; | ||
var defaults$2 = { | ||
var defaults$1 = { | ||
element: undefined, | ||
@@ -1016,3 +1048,3 @@ delay: 600, | ||
function expand$1(options) { | ||
function expand$2(options) { | ||
if (typeof options === 'string' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -1034,3 +1066,3 @@ options = { | ||
this.ias = ias; | ||
this.options = extend({}, defaults$2, expand$1(options)); | ||
this.options = extend({}, defaults$1, expand$2(options)); | ||
@@ -1134,6 +1166,12 @@ if (this.options.element !== undefined) { | ||
console.log(("Page changed [pageIndex=" + (event.pageIndex) + "]")); | ||
} | ||
}, | ||
prefill: function (event) { | ||
console.log("Start prefilling"); | ||
}, | ||
prefilled: function (event) { | ||
console.log("Finished prefilling"); | ||
}, | ||
}; | ||
function expand$2(options) { | ||
function expand$1(options) { | ||
if (options === true) { | ||
@@ -1152,3 +1190,3 @@ options = defaultLogger; | ||
var logger = expand$2(options); | ||
var logger = expand$1(options); | ||
@@ -1204,3 +1242,3 @@ Object.keys(logger).forEach(function (key) { | ||
Paging.prototype.next = function next (nextEvent) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -1210,3 +1248,2 @@ var url = document.location.toString(); | ||
// @todo can be moved inside appended when eventStack is implemented | ||
var loaded = function (event) { | ||
@@ -1222,14 +1259,13 @@ url = event.url; | ||
this.ias.once(APPENDED, function () { | ||
this$1.pageBreaks.push({ | ||
nextEvent.promise.then(function () { | ||
this$1$1.pageBreaks.push({ | ||
pageIndex: nextEvent.pageIndex, | ||
url: url, | ||
title: title, | ||
sentinel: this$1.ias.sentinel() | ||
sentinel: this$1$1.ias.sentinel() | ||
}); | ||
this$1.update(); | ||
this$1$1.update(); | ||
// @todo can be removed when eventStack is implemented | ||
this$1.ias.off(LOADED, loaded); | ||
this$1$1.ias.off(LOADED, loaded); | ||
}); | ||
@@ -1254,3 +1290,3 @@ }; | ||
var defaults$3 = { | ||
var defaults = { | ||
element: undefined, | ||
@@ -1266,3 +1302,3 @@ when: function (pageIndex) { return true; }, | ||
function expand$3(options) { | ||
function expand(options) { | ||
if (typeof options === 'string' || typeof options === 'function' || (typeof options === 'object' && options.nodeType === Node.ELEMENT_NODE)) { | ||
@@ -1291,3 +1327,3 @@ options = { | ||
var Trigger = function Trigger(ias, options) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
@@ -1300,3 +1336,3 @@ // no trigger wanted | ||
this.ias = ias; | ||
this.options = extend({}, defaults$3, expand$3(options)); | ||
this.options = extend({}, defaults, expand(options)); | ||
@@ -1317,3 +1353,3 @@ if (this.options.element !== undefined) { | ||
ias.on(HIT, this.hit.bind(this)); | ||
ias.on(NEXT, function (e) { return this$1.ias.once(APPENDED, function () { return this$1.update(e.pageIndex); }); }); | ||
ias.on(NEXT, function (e) { return this$1$1.ias.once(APPENDED, function () { return this$1$1.update(e.pageIndex); }); }); | ||
}; | ||
@@ -1333,5 +1369,5 @@ | ||
Trigger.prototype.clickHandler = function clickHandler () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
this.hide().then(function () { return this$1.ias.next(); }); | ||
this.hide().then(function () { return this$1$1.ias.next(); }); | ||
}; | ||
@@ -1388,4 +1424,122 @@ | ||
/* eslint no-console: "off" */ | ||
var NativeResizeObserver = window.ResizeObserver; | ||
var EventListenerResizeObserver = function EventListenerResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
}; | ||
EventListenerResizeObserver.prototype.observe = function observe () { | ||
this.el.addEventListener('resize', this.listener); | ||
}; | ||
EventListenerResizeObserver.prototype.unobserve = function unobserve () { | ||
this.el.removeEventListener('resize', this.listener); | ||
}; | ||
var NativeWrapperResizeObserver = function NativeWrapperResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
this.ro = new NativeResizeObserver(this.listener); | ||
}; | ||
NativeWrapperResizeObserver.prototype.observe = function observe () { | ||
this.ro.observe(this.el); | ||
}; | ||
NativeWrapperResizeObserver.prototype.unobserve = function unobserve () { | ||
this.ro.unobserve(); | ||
}; | ||
var PollingResizeObserver = function PollingResizeObserver(el, listener) { | ||
this.el = el; | ||
this.listener = listener; | ||
this.interval = null; | ||
this.lastHeight = null; | ||
}; | ||
PollingResizeObserver.prototype.pollHeight = function pollHeight () { | ||
var height = Math.trunc(getRootRect(this.el).height); | ||
if (this.lastHeight !== null && this.lastHeight !== height) { | ||
this.listener(); | ||
} | ||
this.lastHeight = height; | ||
}; | ||
PollingResizeObserver.prototype.observe = function observe () { | ||
this.interval = setInterval(this.pollHeight.bind(this), 200); | ||
}; | ||
PollingResizeObserver.prototype.unobserve = function unobserve () { | ||
clearInterval(this.interval); | ||
}; | ||
function ResizeObserverFactory(ias, el) { | ||
var listener = lodash_throttle(resizeHandler, 200).bind(ias); | ||
if (el === window) { | ||
return new EventListenerResizeObserver(el, listener); | ||
} | ||
if (NativeResizeObserver) { | ||
return new NativeWrapperResizeObserver(el, listener); | ||
} | ||
if (console && console.warn) { | ||
console.warn('ResizeObserver not supported. Falling back on polling.'); | ||
} | ||
return new PollingResizeObserver(el, listener); | ||
} | ||
var Prefill = function Prefill(ias, options) { | ||
this.ias = ias; | ||
this.enabled = options; | ||
}; | ||
Prefill.prototype.prefill = function prefill () { | ||
var this$1$1 = this; | ||
if (!this.enabled) { | ||
return; | ||
} | ||
var distance = this.ias.distance(); | ||
if (distance > 0) { | ||
return; | ||
} | ||
this.ias.emitter.emit(events.PREFILL); | ||
return this._prefill().then(function () { | ||
this$1$1.ias.emitter.emit(events.PREFILLED); | ||
// @todo reevaluate if we should actually call `measure` here. | ||
this$1$1.ias.measure(); | ||
}); | ||
}; | ||
Prefill.prototype._prefill = function _prefill () { | ||
var this$1$1 = this; | ||
return this.ias.next().then(function (hasNextUrl) { | ||
if (!hasNextUrl) { | ||
return; | ||
} | ||
var distance = this$1$1.ias.distance(); | ||
if (distance < 0) { | ||
return this$1$1._prefill(); | ||
} | ||
}); | ||
}; | ||
var InfiniteAjaxScroll = function InfiniteAjaxScroll(container, options) { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
if ( options === void 0 ) options = {}; | ||
@@ -1396,8 +1550,6 @@ | ||
this.container = tealight(container)[0]; | ||
this.options = extend({}, defaults, options); | ||
this.options = extend({}, defaults$3, options); | ||
this.emitter = new tinyEmitter(); | ||
// @todo might need to call enableLoadOnScroll (or disableLoadOnScroll) | ||
// instead of injecting the value right away | ||
this.loadOnScroll = this.options.loadOnScroll; | ||
this.options.loadOnScroll ? this.enableLoadOnScroll() : this.disableLoadOnScroll(); | ||
this.negativeMargin = Math.abs(this.options.negativeMargin); | ||
@@ -1420,2 +1572,7 @@ | ||
this.resizeObserver = ResizeObserverFactory(this, this.scrollContainer); | ||
this._scrollListener = lodash_throttle(scrollHandler, 200).bind(this); | ||
this.ready = false; | ||
this.bindOnReady = true; | ||
this.binded = false; | ||
@@ -1426,7 +1583,7 @@ this.paused = false; | ||
this.on(HIT, function () { | ||
if (!this$1.loadOnScroll) { | ||
if (!this$1$1.loadOnScroll) { | ||
return; | ||
} | ||
this$1.next(); | ||
this$1$1.next(); | ||
}); | ||
@@ -1443,10 +1600,25 @@ | ||
this.trigger = new Trigger(this, this.options.trigger); | ||
this.prefill = new Prefill(this, this.options.prefill); | ||
// @todo review this logic when prefill support is added | ||
// measure after all plugins are done binding | ||
this.on(BINDED, this.measure); | ||
// prefill/measure after all plugins are done binding | ||
this.on(BINDED, this.prefill.prefill.bind(this.prefill)); | ||
if (this.options.bind) { | ||
// @todo on document.ready? (window.addEventListener('DOMContentLoaded')) | ||
this.bind(); | ||
var ready = function () { | ||
if (this$1$1.ready) { | ||
return; | ||
} | ||
this$1$1.ready = true; | ||
this$1$1.emitter.emit(READY); | ||
if (this$1$1.bindOnReady && this$1$1.options.bind) { | ||
this$1$1.bind(); | ||
} | ||
}; | ||
if (document.readyState === "complete" || document.readyState === "interactive") { | ||
setTimeout(ready, 1); | ||
} else { | ||
window.addEventListener('DOMContentLoaded', ready); | ||
} | ||
@@ -1460,7 +1632,10 @@ }; | ||
this._scrollListener = lodash_throttle(scrollHandler, 200).bind(this); | ||
this._resizeListener = lodash_throttle(resizeHandler, 200).bind(this); | ||
// If we manually call bind before the dom is ready, we assume that we want | ||
// to take control over the bind flow. | ||
if (!this.ready) { | ||
this.bindOnReady = false; | ||
} | ||
this.scrollContainer.addEventListener('scroll', this._scrollListener); | ||
this.scrollContainer.addEventListener('resize', this._resizeListener); | ||
this.resizeObserver.observe(); | ||
@@ -1474,6 +1649,10 @@ this.binded = true; | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
this.once(BINDED, this.unbind); | ||
} | ||
return; | ||
} | ||
this.scrollContainer.removeEventListener('resize', this._resizeListener); | ||
this.resizeObserver.unobserve(); | ||
this.scrollContainer.removeEventListener('scroll', this._scrollListener); | ||
@@ -1487,27 +1666,44 @@ | ||
InfiniteAjaxScroll.prototype.next = function next () { | ||
var this$1 = this; | ||
var this$1$1 = this; | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
return this.once(BINDED, this.next); | ||
} | ||
return; | ||
} | ||
this.pause(); | ||
var event = { | ||
pageIndex: this.pageIndex + 1, | ||
}; | ||
var pageIndex = this.pageIndex + 1; | ||
this.emitter.emit(NEXT, event); | ||
var promise = Promise.resolve(this.nextHandler(pageIndex)) | ||
.then(function (hasNextUrl) { | ||
this$1$1.pageIndex = pageIndex; | ||
return Promise.resolve(this.nextHandler(event.pageIndex)) | ||
.then(function (result) { | ||
this$1.pageIndex = event.pageIndex; | ||
if (!hasNextUrl) { | ||
this$1$1.emitter.emit(LAST); | ||
if (!result) { | ||
this$1.emitter.emit(LAST); | ||
return; | ||
} | ||
this$1.resume(); | ||
this$1$1.resume(); | ||
}) | ||
; | ||
var event = { | ||
pageIndex: this.pageIndex + 1, | ||
promise: promise | ||
}; | ||
this.emitter.emit(NEXT, event); | ||
return promise; | ||
}; | ||
/** | ||
* @param {string} url | ||
* @returns {Promise} returns LOADED event on success | ||
*/ | ||
InfiniteAjaxScroll.prototype.load = function load (url) { | ||
@@ -1519,2 +1715,28 @@ var ias = this; | ||
var loadEvent = { | ||
url: url, | ||
xhr: xhr, | ||
method: 'GET', | ||
body: null, | ||
nocache: false, | ||
responseType: ias.options.responseType, | ||
headers: { | ||
'X-Requested-With': 'XMLHttpRequest', | ||
}, | ||
}; | ||
// event properties are mutable | ||
ias.emitter.emit(LOAD, loadEvent); | ||
var finalUrl = loadEvent.url; | ||
var method = loadEvent.method; | ||
var responseType = loadEvent.responseType; | ||
var headers = loadEvent.headers; | ||
var body = loadEvent.body; | ||
if (!loadEvent.nocache) { | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
finalUrl = finalUrl + ((/\?/).test(finalUrl) ? "&" : "?") + (new Date()).getTime(); | ||
} | ||
xhr.onreadystatechange = function() { | ||
@@ -1525,6 +1747,7 @@ if (xhr.readyState !== XMLHttpRequest.DONE) { | ||
if (xhr.status === 200) { | ||
if (xhr.status === 0) ; | ||
else if (xhr.status === 200) { | ||
var items = xhr.response; | ||
if (ias.options.responseType === 'document') { | ||
if (responseType === 'document') { | ||
items = tealight(ias.options.item, xhr.response); | ||
@@ -1534,8 +1757,9 @@ // @todo assert there actually are items in the response | ||
ias.emitter.emit(LOADED, {items: items, url: url, xhr: xhr}); | ||
// we don't use a shared loadedEvent variable here, because these values should be immutable | ||
resolve({items: items, url: url, xhr: xhr}); | ||
ias.emitter.emit(LOADED, {items: items, url: finalUrl, xhr: xhr}); | ||
resolve({items: items, url: finalUrl, xhr: xhr}); | ||
} else { | ||
// @todo is console.error the best approach? | ||
console.error('Request failed'); | ||
ias.emitter.emit(ERROR, {url: finalUrl, method: method, xhr: xhr}); | ||
@@ -1546,15 +1770,16 @@ reject(xhr); | ||
// FIXME: make no-caching configurable | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
var nocacheUrl = url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime(); | ||
xhr.onerror = function() { | ||
ias.emitter.emit(ERROR, {url: finalUrl, method: method, xhr: xhr}); | ||
xhr.open('GET', nocacheUrl, true); | ||
xhr.responseType = ias.options.responseType; | ||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); | ||
reject(xhr); | ||
}; | ||
// @todo define event variable and pass that around so it can be manipulated | ||
xhr.open(method, finalUrl, true); | ||
xhr.responseType = responseType; | ||
ias.emitter.emit(LOAD, {url: url, xhr: xhr}); | ||
for (var header in headers) { | ||
xhr.setRequestHeader(header, headers[header]); | ||
} | ||
xhr.send(); | ||
xhr.send(body); | ||
}); | ||
@@ -1608,4 +1833,2 @@ }; | ||
this.paused = false; | ||
this.measure(); | ||
}; | ||
@@ -1621,2 +1844,17 @@ | ||
InfiniteAjaxScroll.prototype.distance = function distance (rootRect, sentinel) { | ||
var _rootRect = rootRect || getRootRect(this.scrollContainer); | ||
var _sentinel = sentinel || this.sentinel(); | ||
var scrollPosition = getScrollPosition(this.scrollContainer); | ||
var distance = getDistanceToFold(_sentinel, scrollPosition, _rootRect); | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
return distance; | ||
}; | ||
InfiniteAjaxScroll.prototype.measure = function measure () { | ||
@@ -1627,13 +1865,18 @@ if (this.paused) { | ||
var distance = 0; | ||
var sentinel = this.sentinel(); | ||
var rootRect = getRootRect(this.scrollContainer); | ||
// @todo review this logic when prefill support is added | ||
if (sentinel) { | ||
distance = getDistanceToFold(sentinel, this.scrollContainer); | ||
// When the scroll container has no height, this could indicate that | ||
// the element is not visible (display = none). Without a height | ||
// we cannot calculate the distance to fold. On the other hand we don't | ||
// have to, because it's not visible anyway. Our resize observer will | ||
// monitor the height, once it's greater than 0 everything will resume as normal. | ||
if (rootRect.height === 0) { | ||
// @todo DX: show warning in console that this is happening | ||
return; | ||
} | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
var sentinel = this.sentinel(); | ||
var distance = this.distance(rootRect, sentinel); | ||
if (distance <= 0) { | ||
@@ -1657,7 +1900,12 @@ this.emitter.emit(HIT, {distance: distance}); | ||
InfiniteAjaxScroll.prototype.once = function once (event, callback) { | ||
this.emitter.once(event, callback, this); | ||
var this$1$1 = this; | ||
if (event === BINDED && this.binded) { | ||
callback.bind(this)(); | ||
} | ||
return new Promise(function (resolve) { | ||
this$1$1.emitter.once(event, function() { Promise.resolve(callback.apply(this, arguments)).then(resolve); }, this$1$1); | ||
if (event === BINDED && this$1$1.binded) { | ||
callback.bind(this$1$1)(); | ||
resolve(); | ||
} | ||
}) | ||
}; | ||
@@ -1664,0 +1912,0 @@ |
/** | ||
* Infinite Ajax Scroll v3.0.0-beta.6 | ||
* Infinite Ajax Scroll v3.0.0-rc.1 | ||
* Turn your existing pagination into infinite scrolling pages with ease | ||
@@ -8,5 +8,5 @@ * | ||
* | ||
* Copyright 2014-2020 Webcreate (Jeroen Fiege) | ||
* Copyright 2014-2021 Webcreate (Jeroen Fiege) | ||
* https://infiniteajaxscroll.com | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).InfiniteAjaxScroll=e()}(this,(function(){"use strict";function t(t){return"object"==typeof window.Node?t instanceof window.Node:null!==t&&"object"==typeof t&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName}function e(e,n){if(void 0===n&&(n=document),e instanceof Array)return e.filter(t);if(t(e))return[e];if(o=Object.prototype.toString.call(i=e),"object"==typeof window.NodeList?i instanceof window.NodeList:null!==i&&"object"==typeof i&&"number"==typeof i.length&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(o)&&(0===i.length||t(i[0])))return Array.prototype.slice.call(e);var i,o;if("string"==typeof e)try{var r=n.querySelectorAll(e);return Array.prototype.slice.call(r)}catch(t){return[]}return[]}var n=Object.prototype.hasOwnProperty,i=Object.prototype.toString,o=Object.defineProperty,r=Object.getOwnPropertyDescriptor,s=function(t){return"function"==typeof Array.isArray?Array.isArray(t):"[object Array]"===i.call(t)},l=function(t){if(!t||"[object Object]"!==i.call(t))return!1;var e,o=n.call(t,"constructor"),r=t.constructor&&t.constructor.prototype&&n.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!o&&!r)return!1;for(e in t);return void 0===e||n.call(t,e)},a=function(t,e){o&&"__proto__"===e.name?o(t,e.name,{enumerable:!0,configurable:!0,value:e.newValue,writable:!0}):t[e.name]=e.newValue},c=function(t,e){if("__proto__"===e){if(!n.call(t,e))return;if(r)return r(t,e).value}return t[e]},h=function t(){var e,n,i,o,r,h,u=arguments,d=arguments[0],p=1,f=arguments.length,m=!1;for("boolean"==typeof d&&(m=d,d=arguments[1]||{},p=2),(null==d||"object"!=typeof d&&"function"!=typeof d)&&(d={});f>p;++p)if(null!=(e=u[p]))for(n in e)i=c(d,n),d!==(o=c(e,n))&&(m&&o&&(l(o)||(r=s(o)))?(r?(r=!1,h=i&&s(i)?i:[]):h=i&&l(i)?i:{},a(d,{name:n,newValue:t(m,h,o)})):void 0!==o&&a(d,{name:n,newValue:o}));return d},u="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},d=/^\s+|\s+$/g,p=/^[-+]0x[0-9a-f]+$/i,f=/^0b[01]+$/i,m=/^0o[0-7]+$/i,g=parseInt,y="object"==typeof self&&self&&self.Object===Object&&self,v="object"==typeof u&&u&&u.Object===Object&&u||y||Function("return this")(),b=Object.prototype.toString,w=Math.max,x=Math.min,E=function(){return v.Date.now()};function O(t,e,n){var i,o,r,s,l,a,c=0,h=!1,u=!1,d=!0;if("function"!=typeof t)throw new TypeError("Expected a function");function p(e){var n=i,r=o;return i=o=void 0,c=e,s=t.apply(r,n)}function f(t){return c=t,l=setTimeout(g,e),h?p(t):s}function m(t){var n=t-a;return void 0===a||n>=e||0>n||u&&t-c>=r}function g(){var t=E();if(m(t))return y(t);l=setTimeout(g,function(t){var n=e-(t-a);return u?x(n,r-(t-c)):n}(t))}function y(t){return l=void 0,d&&i?p(t):(i=o=void 0,s)}function v(){var t=E(),n=m(t);if(i=arguments,o=this,a=t,n){if(void 0===l)return f(a);if(u)return l=setTimeout(g,e),p(a)}return void 0===l&&(l=setTimeout(g,e)),s}return e=T(e)||0,S(n)&&(h=!!n.leading,r=(u="maxWait"in n)?w(T(n.maxWait)||0,e):r,d="trailing"in n?!!n.trailing:d),v.cancel=function(){void 0!==l&&clearTimeout(l),c=0,i=a=o=l=void 0},v.flush=function(){return void 0===l?s:y(E())},v}function S(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}function T(t){if("number"==typeof t)return t;if(function(t){return"symbol"==typeof t||function(t){return!!t&&"object"==typeof t}(t)&&"[object Symbol]"==b.call(t)}(t))return NaN;if(S(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=S(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(d,"");var n=f.test(t);return n||m.test(t)?g(t.slice(2),n?2:8):p.test(t)?NaN:+t}var j=function(t,e,n){var i=!0,o=!0;if("function"!=typeof t)throw new TypeError("Expected a function");return S(n)&&(i="leading"in n?!!n.leading:i,o="trailing"in n?!!n.trailing:o),O(t,e,{leading:i,maxWait:e,trailing:o})},L={item:void 0,next:void 0,pagination:void 0,responseType:"document",bind:!0,scrollContainer:window,spinner:!1,logger:!0,loadOnScroll:!0,negativeMargin:0,trigger:!1},_=function(t,n){var i=e(t);if(i.length>1)throw Error('Expected single element for "'+n+'"');if(0===i.length)throw Error('Element "'+t+'" not found for "'+n+'"')},C=function(t,n){if(0===e(t).length)throw Error('Element "'+t+'" not found for "'+n+'"')},I=function(t){for(var e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];try{t.apply(void 0,e)}catch(t){console&&console.warn&&console.warn(t.message)}};function N(t){if(t!==window)return{x:t.scrollLeft,y:t.scrollTop};var e=void 0!==window.pageXOffset,n="CSS1Compat"===(document.compatMode||"");return{x:e?window.pageXOffset:n?document.documentElement.scrollLeft:document.body.scrollLeft,y:e?window.pageYOffset:n?document.documentElement.scrollTop:document.body.scrollTop}}function M(t){var e;if(t!==window)e=t.getBoundingClientRect();else{var n=document.documentElement,i=document.body;e={top:0,left:0,right:n.clientWidth||i.clientWidth,width:n.clientWidth||i.clientWidth,bottom:n.clientHeight||i.clientHeight,height:n.clientHeight||i.clientHeight}}return e}var P="binded",F={y:0,x:0,deltaY:0,deltaX:0};function H(t,e){var n=N(t);return n.deltaY=n.y-(e?e.y:n.y),n.deltaX=n.x-(e?e.x:n.x),n}function A(){var t=this._lastScroll=H(this.scrollContainer,this._lastScroll||F);this.emitter.emit("scrolled",{scroll:t})}function D(){var t=this._lastScroll=H(this.scrollContainer,this._lastScroll||F);this.emitter.emit("resized",{scroll:t})}function k(){}k.prototype={on:function(t,e,n){var i=this.e||(this.e={});return(i[t]||(i[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var i=this;function o(){i.off(t,o),e.apply(n,arguments)}return o._=e,this.on(t,o,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),i=0,o=n.length;o>i;i++)n[i].fn.apply(n[i].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),i=n[t],o=[];if(i&&e)for(var r=0,s=i.length;s>r;r++)i[r].fn!==e&&i[r].fn._!==e&&o.push(i[r]);return o.length?n[t]=o:delete n[t],this}};var R=k;function B(t){var n=this,i=n._lastResponse||document,o=e(n.options.next,i)[0];if(o)return n.load(o.href).then((function(o){i=n._lastResponse=o.xhr.response;var r=e(n.options.next,i)[0];return n.append(o.items).then((function(){return!!r})).then((function(e){return!e&&1>=t&&console&&console.warn&&console.warn('Element "'+n.options.next+'" not found for "options.next" on "'+o.url+'"'),e}))}));I(_,n.options.next,"options.next")}R.TinyEmitter=k;var W={element:void 0,hide:!1};var q=function(t,e){this.options=h({},W,function(t){return"string"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE?t={element:t,hide:!0}:"boolean"==typeof t&&(t={element:void 0,hide:t}),t}(e)),this.originalDisplayStyles=new WeakMap,this.options.hide&&(I(C,this.options.element,"pagination.element"),t.on(P,this.hide.bind(this)),t.on("unbinded",this.restore.bind(this)))};q.prototype.hide=function(){var t=this;e(this.options.element).forEach((function(e){t.originalDisplayStyles.set(e,window.getComputedStyle(e).display),e.style.display="none"}))},q.prototype.restore=function(){var t=this;e(this.options.element).forEach((function(e){e.style.display=t.originalDisplayStyles.get(e)||"block"}))};var z={element:void 0,delay:600,show:function(t){t.style.opacity="1"},hide:function(t){t.style.opacity="0"}};var X=function(t,n){!1!==n&&(this.ias=t,this.options=h({},z,function(t){return("string"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE)&&(t={element:t}),t}(n)),void 0!==this.options.element&&_(this.options.element,"spinner.element"),this.element=e(this.options.element)[0],this.hideFn=this.options.hide,this.showFn=this.options.show,t.on(P,this.bind.bind(this)),t.on(P,this.hide.bind(this)))};X.prototype.bind=function(){var t,e,n=this,i=this.ias;i.on("next",(function(){t=+new Date,n.show()})),i.on("last",(function(){n.hide()})),i.on("append",(function(i){e=Math.max(0,n.options.delay-(+new Date-t));var o=i.appendFn;i.appendFn=function(t,i,r){return new Promise((function(s){setTimeout((function(){Promise.resolve(n.hide()).then((function(){o(t,i,r),s()}))}),e)}))}}))},X.prototype.show=function(){return Promise.resolve(this.showFn(this.element))},X.prototype.hide=function(){return Promise.resolve(this.hideFn(this.element))};var $={hit:function(){console.log("Hit scroll threshold")},binded:function(){console.log("Binded event handlers")},unbinded:function(){console.log("Unbinded event handlers")},next:function(t){console.log("Next page triggered [pageIndex="+t.pageIndex+"]")},load:function(t){console.log("Start loading "+t.url)},loaded:function(){console.log("Finished loading")},append:function(){console.log("Start appending items")},appended:function(t){console.log("Finished appending "+t.items.length+" item(s)")},last:function(){console.log("No more pages left to load")},page:function(t){console.log("Page changed [pageIndex="+t.pageIndex+"]")}};var V=function(t,e){if(!1!==e){var n=function(t){return!0===t&&(t=$),t}(e);Object.keys(n).forEach((function(e){t.on(e,n[e])}))}};var Y=function(t){this.ias=t,this.pageBreaks=[],this.currentPageIndex=t.pageIndex,this.currentScrollTop=0,t.on(P,this.binded.bind(this)),t.on("next",this.next.bind(this)),t.on("scrolled",this.scrolled.bind(this)),t.on("resized",this.scrolled.bind(this))};Y.prototype.binded=function(){this.ias.sentinel()&&this.pageBreaks.push({pageIndex:this.currentPageIndex,url:""+document.location,title:document.title,sentinel:this.ias.sentinel()})},Y.prototype.next=function(t){var e=this,n=""+document.location,i=document.title,o=function(t){n=t.url,t.xhr.response&&(i=t.xhr.response.title)};this.ias.once("loaded",o),this.ias.once("appended",(function(){e.pageBreaks.push({pageIndex:t.pageIndex,url:n,title:i,sentinel:e.ias.sentinel()}),e.update(),e.ias.off("loaded",o)}))},Y.prototype.scrolled=function(t){this.update(t.scroll.y)},Y.prototype.update=function(t){this.currentScrollTop=t||this.currentScrollTop;var e=function(t,e,n){for(var i=e+M(n).height,o=t.length-1;o>=0;o--){if(i>t[o].sentinel.getBoundingClientRect().bottom+e)return t[Math.min(o+1,t.length-1)]}return t[0]}(this.pageBreaks,this.currentScrollTop,this.ias.scrollContainer);e&&e.pageIndex!==this.currentPageIndex&&(this.ias.emitter.emit("page",e),this.currentPageIndex=e.pageIndex)};var G={element:void 0,when:function(t){return!0},show:function(t){t.style.opacity="1"},hide:function(t){t.style.opacity="0"}};var U=function(t,n){var i=this;!1!==n&&(this.ias=t,this.options=h({},G,function(t){if(("string"==typeof t||"function"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE)&&(t={element:t}),"function"==typeof t.element&&(t.element=t.element()),t.when&&Array.isArray(t.when)){var e=t.when;t.when=function(t){return-1!==e.indexOf(t)}}return t}(n)),void 0!==this.options.element&&_(this.options.element,"trigger.element"),this.element=e(this.options.element)[0],this.hideFn=this.options.hide,this.showFn=this.options.show,this.voter=this.options.when,this.showing=void 0,this.enabled=void 0,t.on(P,this.bind.bind(this)),t.on("unbinded",this.unbind.bind(this)),t.on("hit",this.hit.bind(this)),t.on("next",(function(t){return i.ias.once("appended",(function(){return i.update(t.pageIndex)}))})))};function J(t,e,n){var i=n?n.nextSibling:null,o=document.createDocumentFragment();t.forEach((function(t){o.appendChild(t)})),e.insertBefore(o,i)}U.prototype.bind=function(){this.hide(),this.update(this.ias.pageIndex),this.element.addEventListener("click",this.clickHandler.bind(this))},U.prototype.unbind=function(){this.element.removeEventListener("click",this.clickHandler.bind(this))},U.prototype.clickHandler=function(){var t=this;this.hide().then((function(){return t.ias.next()}))},U.prototype.update=function(t){this.enabled=this.voter(t),this.enabled?this.ias.disableLoadOnScroll():this.ias.enableLoadOnScroll()},U.prototype.hit=function(){this.enabled&&this.show()},U.prototype.show=function(){if(!this.showing)return this.showing=!0,Promise.resolve(this.showFn(this.element))},U.prototype.hide=function(){if(this.showing||void 0===this.showing)return this.showing=!1,Promise.resolve(this.hideFn(this.element))};var K=function(t,n){var i=this;void 0===n&&(n={}),_(t,"container"),this.container=e(t)[0],this.options=h({},L,n),this.emitter=new R,this.loadOnScroll=this.options.loadOnScroll,this.negativeMargin=Math.abs(this.options.negativeMargin),this.scrollContainer=this.options.scrollContainer,this.options.scrollContainer!==window&&(_(this.options.scrollContainer,"options.scrollContainer"),this.scrollContainer=e(this.options.scrollContainer)[0]),this.nextHandler=B,!1===this.options.next?this.nextHandler=function(){}:"function"==typeof this.options.next&&(this.nextHandler=this.options.next),this.binded=!1,this.paused=!1,this.pageIndex=this.sentinel()?0:-1,this.on("hit",(function(){i.loadOnScroll&&i.next()})),this.on("scrolled",this.measure),this.on("resized",this.measure),this.pagination=new q(this,this.options.pagination),this.spinner=new X(this,this.options.spinner),this.logger=new V(this,this.options.logger),this.paging=new Y(this),this.trigger=new U(this,this.options.trigger),this.on(P,this.measure),this.options.bind&&this.bind()};return K.prototype.bind=function(){this.binded||(this._scrollListener=j(A,200).bind(this),this._resizeListener=j(D,200).bind(this),this.scrollContainer.addEventListener("scroll",this._scrollListener),this.scrollContainer.addEventListener("resize",this._resizeListener),this.binded=!0,this.emitter.emit(P))},K.prototype.unbind=function(){this.binded&&(this.scrollContainer.removeEventListener("resize",this._resizeListener),this.scrollContainer.removeEventListener("scroll",this._scrollListener),this.binded=!1,this.emitter.emit("unbinded"))},K.prototype.next=function(){var t=this;this.pause();var e={pageIndex:this.pageIndex+1};return this.emitter.emit("next",e),Promise.resolve(this.nextHandler(e.pageIndex)).then((function(n){t.pageIndex=e.pageIndex,n?t.resume():t.emitter.emit("last")}))},K.prototype.load=function(t){var n=this;return new Promise((function(i,o){var r=new XMLHttpRequest;r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE)if(200===r.status){var s=r.response;"document"===n.options.responseType&&(s=e(n.options.item,r.response)),n.emitter.emit("loaded",{items:s,url:t,xhr:r}),i({items:s,url:t,xhr:r})}else console.error("Request failed"),o(r)};var s=t+(/\?/.test(t)?"&":"?")+(new Date).getTime();r.open("GET",s,!0),r.responseType=n.options.responseType,r.setRequestHeader("X-Requested-With","XMLHttpRequest"),n.emitter.emit("load",{url:t,xhr:r}),r.send()}))},K.prototype.append=function(t,e){var n=this,i={items:t,parent:e=e||n.container,appendFn:J};n.emitter.emit("append",i);return new Promise((function(o){window.requestAnimationFrame((function(){Promise.resolve(i.appendFn(i.items,i.parent,n.sentinel())).then((function(){o({items:t,parent:e})}))}))})).then((function(t){n.emitter.emit("appended",t)}))},K.prototype.sentinel=function(){var t=e(this.options.item,this.container);return t.length?t[t.length-1]:null},K.prototype.pause=function(){this.paused=!0},K.prototype.resume=function(){this.paused=!1,this.measure()},K.prototype.enableLoadOnScroll=function(){this.loadOnScroll=!0},K.prototype.disableLoadOnScroll=function(){this.loadOnScroll=!1},K.prototype.measure=function(){if(!this.paused){var t,e,n,i,o,r=0,s=this.sentinel();s&&(t=s,n=N(e=this.scrollContainer),i=M(e),o=t.getBoundingClientRect(),r=Math.trunc(n.y+o.bottom-i.top-(n.y+i.height))),(r-=this.negativeMargin)>0||this.emitter.emit("hit",{distance:r})}},K.prototype.on=function(t,e){this.emitter.on(t,e,this),t===P&&this.binded&&e.bind(this)()},K.prototype.off=function(t,e){this.emitter.off(t,e,this)},K.prototype.once=function(t,e){this.emitter.once(t,e,this),t===P&&this.binded&&e.bind(this)()},K})); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).InfiniteAjaxScroll=e()}(this,(function(){"use strict";function t(t){return"object"==typeof window.Node?t instanceof window.Node:null!==t&&"object"==typeof t&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName}function e(e,n){if(void 0===n&&(n=document),e instanceof Array)return e.filter(t);if(t(e))return[e];if(o=Object.prototype.toString.call(i=e),"object"==typeof window.NodeList?i instanceof window.NodeList:null!==i&&"object"==typeof i&&"number"==typeof i.length&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(o)&&(0===i.length||t(i[0])))return Array.prototype.slice.call(e);var i,o;if("string"==typeof e)try{var r=n.querySelectorAll(e);return Array.prototype.slice.call(r)}catch(t){return[]}return[]}var n=Object.prototype.hasOwnProperty,i=Object.prototype.toString,o=Object.defineProperty,r=Object.getOwnPropertyDescriptor,s=function(t){return"function"==typeof Array.isArray?Array.isArray(t):"[object Array]"===i.call(t)},l=function(t){if(!t||"[object Object]"!==i.call(t))return!1;var e,o=n.call(t,"constructor"),r=t.constructor&&t.constructor.prototype&&n.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!o&&!r)return!1;for(e in t);return void 0===e||n.call(t,e)},a=function(t,e){o&&"__proto__"===e.name?o(t,e.name,{enumerable:!0,configurable:!0,value:e.newValue,writable:!0}):t[e.name]=e.newValue},h=function(t,e){if("__proto__"===e){if(!n.call(t,e))return;if(r)return r(t,e).value}return t[e]},c=function t(){var e,n,i,o,r,c,u=arguments,p=arguments[0],d=1,f=arguments.length,m=!1;for("boolean"==typeof p&&(m=p,p=arguments[1]||{},d=2),(null==p||"object"!=typeof p&&"function"!=typeof p)&&(p={});f>d;++d)if(null!=(e=u[d]))for(n in e)i=h(p,n),p!==(o=h(e,n))&&(m&&o&&(l(o)||(r=s(o)))?(r?(r=!1,c=i&&s(i)?i:[]):c=i&&l(i)?i:{},a(p,{name:n,newValue:t(m,c,o)})):void 0!==o&&a(p,{name:n,newValue:o}));return p},u="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},p="Expected a function",d=/^\s+|\s+$/g,f=/^[-+]0x[0-9a-f]+$/i,m=/^0b[01]+$/i,y=/^0o[0-7]+$/i,g=parseInt,v="object"==typeof self&&self&&self.Object===Object&&self,b="object"==typeof u&&u&&u.Object===Object&&u||v||Function("return this")(),w=Object.prototype.toString,x=Math.max,O=Math.min,E=function(){return b.Date.now()};function S(t,e,n){var i,o,r,s,l,a,h=0,c=!1,u=!1,d=!0;if("function"!=typeof t)throw new TypeError(p);function f(e){var n=i,r=o;return i=o=void 0,h=e,s=t.apply(r,n)}function m(t){return h=t,l=setTimeout(g,e),c?f(t):s}function y(t){var n=t-a;return void 0===a||n>=e||0>n||u&&t-h>=r}function g(){var t=E();if(y(t))return v(t);l=setTimeout(g,function(t){var n=e-(t-a);return u?O(n,r-(t-h)):n}(t))}function v(t){return l=void 0,d&&i?f(t):(i=o=void 0,s)}function b(){var t=E(),n=y(t);if(i=arguments,o=this,a=t,n){if(void 0===l)return m(a);if(u)return l=setTimeout(g,e),f(a)}return void 0===l&&(l=setTimeout(g,e)),s}return e=j(e)||0,T(n)&&(c=!!n.leading,r=(u="maxWait"in n)?x(j(n.maxWait)||0,e):r,d="trailing"in n?!!n.trailing:d),b.cancel=function(){void 0!==l&&clearTimeout(l),h=0,i=a=o=l=void 0},b.flush=function(){return void 0===l?s:v(E())},b}function T(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}function j(t){if("number"==typeof t)return t;if(function(t){return"symbol"==typeof t||function(t){return!!t&&"object"==typeof t}(t)&&"[object Symbol]"==w.call(t)}(t))return NaN;if(T(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=T(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(d,"");var n=m.test(t);return n||y.test(t)?g(t.slice(2),n?2:8):f.test(t)?NaN:+t}var L=function(t,e,n){var i=!0,o=!0;if("function"!=typeof t)throw new TypeError(p);return T(n)&&(i="leading"in n?!!n.leading:i,o="trailing"in n?!!n.trailing:o),S(t,e,{leading:i,maxWait:e,trailing:o})},C={item:void 0,next:void 0,pagination:void 0,responseType:"document",bind:!0,scrollContainer:window,spinner:!1,logger:!0,loadOnScroll:!0,negativeMargin:0,trigger:!1,prefill:!0},I=function(t,n){var i=e(t);if(i.length>1)throw Error('Expected single element for "'+n+'"');if(0===i.length)throw Error('Element "'+t+'" not found for "'+n+'"')},_=function(t,n){if(0===e(t).length)throw Error('Element "'+t+'" not found for "'+n+'"')},H=function(t){for(var e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];try{t.apply(void 0,e)}catch(t){console&&console.warn&&console.warn(t.message)}};function N(t){if(t!==window)return{x:t.scrollLeft,y:t.scrollTop};var e=void 0!==window.pageXOffset,n="CSS1Compat"===(document.compatMode||"");return{x:e?window.pageXOffset:n?document.documentElement.scrollLeft:document.body.scrollLeft,y:e?window.pageYOffset:n?document.documentElement.scrollTop:document.body.scrollTop}}function M(t){var e;if(t!==window)e=t.getBoundingClientRect();else{var n=document.documentElement,i=document.body;e={top:0,left:0,right:n.clientWidth||i.clientWidth,width:n.clientWidth||i.clientWidth,bottom:n.clientHeight||i.clientHeight,height:n.clientHeight||i.clientHeight}}return e}var P="append",F="appended",R="binded",D="unbinded",k="hit",A="load",B="loaded",W="error",z="last",X="next",q="ready",$="scrolled",V="resized",Y="page",G="prefill",U="prefilled",J={y:0,x:0,deltaY:0,deltaX:0};function K(t,e){var n=N(t);return n.deltaY=n.y-(e?e.y:n.y),n.deltaX=n.x-(e?e.x:n.x),n}function Q(){var t=this,e=t._lastScroll=K(t.scrollContainer,t._lastScroll||J);this.emitter.emit($,{scroll:e})}function Z(){var t=this,e=t._lastScroll=K(t.scrollContainer,t._lastScroll||J);this.emitter.emit(V,{scroll:e})}function tt(){}tt.prototype={on:function(t,e,n){var i=this.e||(this.e={});return(i[t]||(i[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var i=this;function o(){i.off(t,o),e.apply(n,arguments)}return o._=e,this.on(t,o,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),i=0,o=n.length;o>i;i++)n[i].fn.apply(n[i].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),i=n[t],o=[];if(i&&e)for(var r=0,s=i.length;s>r;r++)i[r].fn!==e&&i[r].fn._!==e&&o.push(i[r]);return o.length?n[t]=o:delete n[t],this}};var et=tt;function nt(t){var n=this,i=n._lastResponse||document,o=e(n.options.next,i)[0];if(o)return n.load(o.href).then((function(o){i=n._lastResponse=o.xhr.response;var r=e(n.options.next,i)[0];return n.append(o.items).then((function(){return!!r})).then((function(e){return!e&&1>=t&&console&&console.warn&&console.warn('Element "'+n.options.next+'" not found for "options.next" on "'+o.url+'"'),e}))}));H(I,n.options.next,"options.next")}et.TinyEmitter=tt;var it={element:void 0,hide:!1};var ot=function(t,e){this.options=c({},it,function(t){return"string"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE?t={element:t,hide:!0}:"boolean"==typeof t&&(t={element:void 0,hide:t}),t}(e)),this.originalDisplayStyles=new WeakMap,this.options.hide&&(H(_,this.options.element,"pagination.element"),t.on(R,this.hide.bind(this)),t.on(D,this.restore.bind(this)))};ot.prototype.hide=function(){var t=this;e(this.options.element).forEach((function(e){t.originalDisplayStyles.set(e,window.getComputedStyle(e).display),e.style.display="none"}))},ot.prototype.restore=function(){var t=this;e(this.options.element).forEach((function(e){e.style.display=t.originalDisplayStyles.get(e)||"block"}))};var rt={element:void 0,delay:600,show:function(t){t.style.opacity="1"},hide:function(t){t.style.opacity="0"}};var st=function(t,n){!1!==n&&(this.ias=t,this.options=c({},rt,function(t){return("string"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE)&&(t={element:t}),t}(n)),void 0!==this.options.element&&I(this.options.element,"spinner.element"),this.element=e(this.options.element)[0],this.hideFn=this.options.hide,this.showFn=this.options.show,t.on(R,this.bind.bind(this)),t.on(R,this.hide.bind(this)))};st.prototype.bind=function(){var t,e,n=this,i=this.ias;i.on(X,(function(){t=+new Date,n.show()})),i.on(z,(function(){n.hide()})),i.on(P,(function(i){e=Math.max(0,n.options.delay-(+new Date-t));var o=i.appendFn;i.appendFn=function(t,i,r){return new Promise((function(s){setTimeout((function(){Promise.resolve(n.hide()).then((function(){o(t,i,r),s()}))}),e)}))}}))},st.prototype.show=function(){return Promise.resolve(this.showFn(this.element))},st.prototype.hide=function(){return Promise.resolve(this.hideFn(this.element))};var lt={hit:function(){console.log("Hit scroll threshold")},binded:function(){console.log("Binded event handlers")},unbinded:function(){console.log("Unbinded event handlers")},next:function(t){console.log("Next page triggered [pageIndex="+t.pageIndex+"]")},load:function(t){console.log("Start loading "+t.url)},loaded:function(){console.log("Finished loading")},append:function(){console.log("Start appending items")},appended:function(t){console.log("Finished appending "+t.items.length+" item(s)")},last:function(){console.log("No more pages left to load")},page:function(t){console.log("Page changed [pageIndex="+t.pageIndex+"]")},prefill:function(t){console.log("Start prefilling")},prefilled:function(t){console.log("Finished prefilling")}};var at=function(t,e){if(!1!==e){var n=function(t){return!0===t&&(t=lt),t}(e);Object.keys(n).forEach((function(e){t.on(e,n[e])}))}};var ht=function(t){this.ias=t,this.pageBreaks=[],this.currentPageIndex=t.pageIndex,this.currentScrollTop=0,t.on(R,this.binded.bind(this)),t.on(X,this.next.bind(this)),t.on($,this.scrolled.bind(this)),t.on(V,this.scrolled.bind(this))};ht.prototype.binded=function(){this.ias.sentinel()&&this.pageBreaks.push({pageIndex:this.currentPageIndex,url:""+document.location,title:document.title,sentinel:this.ias.sentinel()})},ht.prototype.next=function(t){var e=this,n=""+document.location,i=document.title,o=function(t){n=t.url,t.xhr.response&&(i=t.xhr.response.title)};this.ias.once(B,o),t.promise.then((function(){e.pageBreaks.push({pageIndex:t.pageIndex,url:n,title:i,sentinel:e.ias.sentinel()}),e.update(),e.ias.off(B,o)}))},ht.prototype.scrolled=function(t){this.update(t.scroll.y)},ht.prototype.update=function(t){this.currentScrollTop=t||this.currentScrollTop;var e=function(t,e,n){for(var i=e+M(n).height,o=t.length-1;o>=0;o--)if(i>t[o].sentinel.getBoundingClientRect().bottom+e)return t[Math.min(o+1,t.length-1)];return t[0]}(this.pageBreaks,this.currentScrollTop,this.ias.scrollContainer);e&&e.pageIndex!==this.currentPageIndex&&(this.ias.emitter.emit(Y,e),this.currentPageIndex=e.pageIndex)};var ct={element:void 0,when:function(t){return!0},show:function(t){t.style.opacity="1"},hide:function(t){t.style.opacity="0"}};var ut=function(t,n){var i=this;!1!==n&&(this.ias=t,this.options=c({},ct,function(t){if(("string"==typeof t||"function"==typeof t||"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE)&&(t={element:t}),"function"==typeof t.element&&(t.element=t.element()),t.when&&Array.isArray(t.when)){var e=t.when;t.when=function(t){return-1!==e.indexOf(t)}}return t}(n)),void 0!==this.options.element&&I(this.options.element,"trigger.element"),this.element=e(this.options.element)[0],this.hideFn=this.options.hide,this.showFn=this.options.show,this.voter=this.options.when,this.showing=void 0,this.enabled=void 0,t.on(R,this.bind.bind(this)),t.on(D,this.unbind.bind(this)),t.on(k,this.hit.bind(this)),t.on(X,(function(t){return i.ias.once(F,(function(){return i.update(t.pageIndex)}))})))};function pt(t,e,n){var i=n?n.nextSibling:null,o=document.createDocumentFragment();t.forEach((function(t){o.appendChild(t)})),e.insertBefore(o,i)}ut.prototype.bind=function(){this.hide(),this.update(this.ias.pageIndex),this.element.addEventListener("click",this.clickHandler.bind(this))},ut.prototype.unbind=function(){this.element.removeEventListener("click",this.clickHandler.bind(this))},ut.prototype.clickHandler=function(){var t=this;this.hide().then((function(){return t.ias.next()}))},ut.prototype.update=function(t){this.enabled=this.voter(t),this.enabled?this.ias.disableLoadOnScroll():this.ias.enableLoadOnScroll()},ut.prototype.hit=function(){this.enabled&&this.show()},ut.prototype.show=function(){if(!this.showing)return this.showing=!0,Promise.resolve(this.showFn(this.element))},ut.prototype.hide=function(){if(this.showing||void 0===this.showing)return this.showing=!1,Promise.resolve(this.hideFn(this.element))};var dt=window.ResizeObserver,ft=function(t,e){this.el=t,this.listener=e};ft.prototype.observe=function(){this.el.addEventListener("resize",this.listener)},ft.prototype.unobserve=function(){this.el.removeEventListener("resize",this.listener)};var mt=function(t,e){this.el=t,this.listener=e,this.ro=new dt(this.listener)};mt.prototype.observe=function(){this.ro.observe(this.el)},mt.prototype.unobserve=function(){this.ro.unobserve()};var yt=function(t,e){this.el=t,this.listener=e,this.interval=null,this.lastHeight=null};yt.prototype.pollHeight=function(){var t=Math.trunc(M(this.el).height);null!==this.lastHeight&&this.lastHeight!==t&&this.listener(),this.lastHeight=t},yt.prototype.observe=function(){this.interval=setInterval(this.pollHeight.bind(this),200)},yt.prototype.unobserve=function(){clearInterval(this.interval)};var gt=function(t,e){this.ias=t,this.enabled=e};gt.prototype.prefill=function(){var t=this;if(this.enabled&&0>=this.ias.distance())return this.ias.emitter.emit(G),this._prefill().then((function(){t.ias.emitter.emit(U),t.ias.measure()}))},gt.prototype._prefill=function(){var t=this;return this.ias.next().then((function(e){if(e)return 0>t.ias.distance()?t._prefill():void 0}))};var vt=function(t,n){var i,o,r,s=this;void 0===n&&(n={}),I(t,"container"),this.container=e(t)[0],this.options=c({},C,n),this.emitter=new et,this.options.loadOnScroll?this.enableLoadOnScroll():this.disableLoadOnScroll(),this.negativeMargin=Math.abs(this.options.negativeMargin),this.scrollContainer=this.options.scrollContainer,this.options.scrollContainer!==window&&(I(this.options.scrollContainer,"options.scrollContainer"),this.scrollContainer=e(this.options.scrollContainer)[0]),this.nextHandler=nt,!1===this.options.next?this.nextHandler=function(){}:"function"==typeof this.options.next&&(this.nextHandler=this.options.next),this.resizeObserver=(i=this,o=this.scrollContainer,r=L(Z,200).bind(i),o===window?new ft(o,r):dt?new mt(o,r):(console&&console.warn&&console.warn("ResizeObserver not supported. Falling back on polling."),new yt(o,r))),this._scrollListener=L(Q,200).bind(this),this.ready=!1,this.bindOnReady=!0,this.binded=!1,this.paused=!1,this.pageIndex=this.sentinel()?0:-1,this.on(k,(function(){s.loadOnScroll&&s.next()})),this.on($,this.measure),this.on(V,this.measure),this.pagination=new ot(this,this.options.pagination),this.spinner=new st(this,this.options.spinner),this.logger=new at(this,this.options.logger),this.paging=new ht(this),this.trigger=new ut(this,this.options.trigger),this.prefill=new gt(this,this.options.prefill),this.on(R,this.prefill.prefill.bind(this.prefill));var l=function(){s.ready||(s.ready=!0,s.emitter.emit(q),s.bindOnReady&&s.options.bind&&s.bind())};"complete"===document.readyState||"interactive"===document.readyState?setTimeout(l,1):window.addEventListener("DOMContentLoaded",l)};return vt.prototype.bind=function(){this.binded||(this.ready||(this.bindOnReady=!1),this.scrollContainer.addEventListener("scroll",this._scrollListener),this.resizeObserver.observe(),this.binded=!0,this.emitter.emit(R))},vt.prototype.unbind=function(){this.binded?(this.resizeObserver.unobserve(),this.scrollContainer.removeEventListener("scroll",this._scrollListener),this.binded=!1,this.emitter.emit(D)):this.ready||this.once(R,this.unbind)},vt.prototype.next=function(){var t=this;if(!this.binded)return this.ready?void 0:this.once(R,this.next);this.pause();var e=this.pageIndex+1,n=Promise.resolve(this.nextHandler(e)).then((function(n){t.pageIndex=e,n?t.resume():t.emitter.emit(z)}));return this.emitter.emit(X,{pageIndex:this.pageIndex+1,promise:n}),n},vt.prototype.load=function(t){var n=this;return new Promise((function(i,o){var r=new XMLHttpRequest,s={url:t,xhr:r,method:"GET",body:null,nocache:!1,responseType:n.options.responseType,headers:{"X-Requested-With":"XMLHttpRequest"}};n.emitter.emit(A,s);var l=s.url,a=s.method,h=s.responseType,c=s.headers,u=s.body;for(var p in s.nocache||(l=l+(/\?/.test(l)?"&":"?")+(new Date).getTime()),r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE)if(0===r.status);else if(200===r.status){var t=r.response;"document"===h&&(t=e(n.options.item,r.response)),n.emitter.emit(B,{items:t,url:l,xhr:r}),i({items:t,url:l,xhr:r})}else n.emitter.emit(W,{url:l,method:a,xhr:r}),o(r)},r.onerror=function(){n.emitter.emit(W,{url:l,method:a,xhr:r}),o(r)},r.open(a,l,!0),r.responseType=h,c)r.setRequestHeader(p,c[p]);r.send(u)}))},vt.prototype.append=function(t,e){var n=this,i={items:t,parent:e=e||n.container,appendFn:pt};n.emitter.emit(P,i);return new Promise((function(o){window.requestAnimationFrame((function(){Promise.resolve(i.appendFn(i.items,i.parent,n.sentinel())).then((function(){o({items:t,parent:e})}))}))})).then((function(t){n.emitter.emit(F,t)}))},vt.prototype.sentinel=function(){var t=e(this.options.item,this.container);return t.length?t[t.length-1]:null},vt.prototype.pause=function(){this.paused=!0},vt.prototype.resume=function(){this.paused=!1},vt.prototype.enableLoadOnScroll=function(){this.loadOnScroll=!0},vt.prototype.disableLoadOnScroll=function(){this.loadOnScroll=!1},vt.prototype.distance=function(t,e){var n=t||M(this.scrollContainer),i=function(t,e,n){var i=n;if(!t)return-1*i.height;var o=e.y,r=t.getBoundingClientRect();return Math.trunc(o+r.bottom-i.top-(o+i.height))}(e||this.sentinel(),N(this.scrollContainer),n);return i-=this.negativeMargin,i},vt.prototype.measure=function(){if(!this.paused){var t=M(this.scrollContainer);if(0!==t.height){var e=this.sentinel(),n=this.distance(t,e);n>0||this.emitter.emit(k,{distance:n})}}},vt.prototype.on=function(t,e){this.emitter.on(t,e,this),t===R&&this.binded&&e.bind(this)()},vt.prototype.off=function(t,e){this.emitter.off(t,e,this)},vt.prototype.once=function(t,e){var n=this;return new Promise((function(i){n.emitter.once(t,(function(){Promise.resolve(e.apply(this,arguments)).then(i)}),n),t===R&&n.binded&&(e.bind(n)(),i())}))},vt})); |
{ | ||
"name": "@webcreate/infinite-ajax-scroll", | ||
"version": "3.0.0-beta.6", | ||
"version": "3.0.0-rc.1", | ||
"title": "Infinite Ajax Scroll", | ||
@@ -42,3 +42,3 @@ "description": "Turn your existing pagination into infinite scrolling pages with ease", | ||
"cypress": "cypress open -d", | ||
"start": "http-server -p 8080 ./ --silent -c-1 &", | ||
"start": "serve -l 8080 -n ./", | ||
"test": "cypress run", | ||
@@ -54,12 +54,12 @@ "lint": "eslint src test" | ||
"devDependencies": { | ||
"cypress": "^4.0.0", | ||
"eslint": "^6.0.1", | ||
"cypress": "^8.0.0", | ||
"eslint": "^7.3.1", | ||
"eslint-plugin-cypress": "^2.2.1", | ||
"http-server": "^0.12.0", | ||
"rollup": "^1.27.10", | ||
"rollup": "^2.0.3", | ||
"rollup-plugin-buble": "^0.19.8", | ||
"rollup-plugin-commonjs": "^10.0.1", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"rollup-plugin-terser": "^5.1.3" | ||
"rollup-plugin-terser": "^7.0.2", | ||
"serve": "^12.0.0" | ||
} | ||
} |
@@ -26,3 +26,3 @@ <p align="center"> | ||
```markup | ||
<script src="https://unpkg.com/@webcreate/infinite-ajax-scroll@3/dist/infinite-ajax-scroll.min.js"></script> | ||
<script src="https://unpkg.com/@webcreate/infinite-ajax-scroll@^3.0.0-beta.6/dist/infinite-ajax-scroll.min.js"></script> | ||
``` | ||
@@ -29,0 +29,0 @@ |
@@ -0,1 +1,2 @@ | ||
/* eslint no-console: "off" */ | ||
import $ from 'tealight'; | ||
@@ -2,0 +3,0 @@ |
@@ -13,2 +13,3 @@ export default { | ||
trigger: false, | ||
prefill: true, | ||
}; |
@@ -42,11 +42,17 @@ | ||
export function getDistanceToFold(el, scrollContainer) { | ||
let scroll = getScrollPosition(scrollContainer); | ||
let rootRect = getRootRect(scrollContainer); | ||
let boundingRect = el.getBoundingClientRect(); | ||
export function getDistanceToFold(sentinel, scrollContainerScrollPosition, scrollContainerRootRect) { | ||
let rootRect = scrollContainerRootRect; | ||
let scrollYBottom = scroll.y + rootRect.height; | ||
let bottom = scroll.y + boundingRect.bottom - rootRect.top; | ||
// this means the container the doesn't have any items yet - it's empty | ||
if (!sentinel) { | ||
return rootRect.height * -1; | ||
} | ||
let scrollYTop = scrollContainerScrollPosition.y; | ||
let boundingRect = sentinel.getBoundingClientRect(); | ||
let scrollYBottom = scrollYTop + rootRect.height; | ||
let bottom = scrollYTop + boundingRect.bottom - rootRect.top; | ||
return Math.trunc(bottom - scrollYBottom); | ||
} |
@@ -8,7 +8,11 @@ export const APPEND = 'append'; | ||
export const LOADED = 'loaded'; | ||
export const ERROR = 'error'; | ||
export const LAST = 'last'; | ||
export const NEXT = 'next'; | ||
export const READY = 'ready'; | ||
export const SCROLLED = 'scrolled'; | ||
export const RESIZED = 'resized'; | ||
export const PAGE = 'page'; | ||
export const PREFILL = 'prefill'; | ||
export const PREFILLED = 'prefilled'; | ||
@@ -23,9 +27,13 @@ const events = { | ||
LOADED, | ||
ERROR, | ||
LAST, | ||
NEXT, | ||
READY, | ||
SCROLLED, | ||
RESIZED, | ||
PAGE, | ||
PREFILL, | ||
PREFILLED, | ||
}; | ||
export default events; |
@@ -6,5 +6,5 @@ import $ from 'tealight'; | ||
import Assert from './assert'; | ||
import {scrollHandler, resizeHandler} from "./event-handlers"; | ||
import {scrollHandler} from "./event-handlers"; | ||
import Emitter from "tiny-emitter"; | ||
import {getDistanceToFold} from "./dimensions"; | ||
import {getDistanceToFold, getRootRect, getScrollPosition} from "./dimensions"; | ||
import {nextHandler} from './next-handler'; | ||
@@ -18,2 +18,4 @@ import Pagination from './pagination'; | ||
import * as Events from './events'; | ||
import ResizeObserverFactory from './resize-observer'; | ||
import Prefill from "./prefill"; | ||
@@ -28,5 +30,3 @@ export default class InfiniteAjaxScroll { | ||
// @todo might need to call enableLoadOnScroll (or disableLoadOnScroll) | ||
// instead of injecting the value right away | ||
this.loadOnScroll = this.options.loadOnScroll; | ||
this.options.loadOnScroll ? this.enableLoadOnScroll() : this.disableLoadOnScroll(); | ||
this.negativeMargin = Math.abs(this.options.negativeMargin); | ||
@@ -49,2 +49,7 @@ | ||
this.resizeObserver = ResizeObserverFactory(this, this.scrollContainer); | ||
this._scrollListener = throttle(scrollHandler, 200).bind(this); | ||
this.ready = false; | ||
this.bindOnReady = true; | ||
this.binded = false; | ||
@@ -71,10 +76,25 @@ this.paused = false; | ||
this.trigger = new Trigger(this, this.options.trigger); | ||
this.prefill = new Prefill(this, this.options.prefill); | ||
// @todo review this logic when prefill support is added | ||
// measure after all plugins are done binding | ||
this.on(Events.BINDED, this.measure); | ||
// prefill/measure after all plugins are done binding | ||
this.on(Events.BINDED, this.prefill.prefill.bind(this.prefill)); | ||
if (this.options.bind) { | ||
// @todo on document.ready? (window.addEventListener('DOMContentLoaded')) | ||
this.bind(); | ||
let ready = () => { | ||
if (this.ready) { | ||
return; | ||
} | ||
this.ready = true; | ||
this.emitter.emit(Events.READY); | ||
if (this.bindOnReady && this.options.bind) { | ||
this.bind(); | ||
} | ||
}; | ||
if (document.readyState === "complete" || document.readyState === "interactive") { | ||
setTimeout(ready, 1); | ||
} else { | ||
window.addEventListener('DOMContentLoaded', ready); | ||
} | ||
@@ -88,7 +108,10 @@ } | ||
this._scrollListener = throttle(scrollHandler, 200).bind(this); | ||
this._resizeListener = throttle(resizeHandler, 200).bind(this); | ||
// If we manually call bind before the dom is ready, we assume that we want | ||
// to take control over the bind flow. | ||
if (!this.ready) { | ||
this.bindOnReady = false; | ||
} | ||
this.scrollContainer.addEventListener('scroll', this._scrollListener); | ||
this.scrollContainer.addEventListener('resize', this._resizeListener); | ||
this.resizeObserver.observe(); | ||
@@ -102,6 +125,10 @@ this.binded = true; | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
this.once(Events.BINDED, this.unbind); | ||
} | ||
return; | ||
} | ||
this.scrollContainer.removeEventListener('resize', this._resizeListener); | ||
this.resizeObserver.unobserve(); | ||
this.scrollContainer.removeEventListener('scroll', this._scrollListener); | ||
@@ -115,15 +142,19 @@ | ||
next() { | ||
if (!this.binded) { | ||
if (!this.ready) { | ||
return this.once(Events.BINDED, this.next); | ||
} | ||
return; | ||
} | ||
this.pause(); | ||
let event = { | ||
pageIndex: this.pageIndex + 1, | ||
}; | ||
const pageIndex = this.pageIndex + 1; | ||
this.emitter.emit(Events.NEXT, event); | ||
const promise = Promise.resolve(this.nextHandler(pageIndex)) | ||
.then((hasNextUrl) => { | ||
this.pageIndex = pageIndex; | ||
return Promise.resolve(this.nextHandler(event.pageIndex)) | ||
.then((result) => { | ||
this.pageIndex = event.pageIndex; | ||
if (!result) { | ||
if (!hasNextUrl) { | ||
this.emitter.emit(Events.LAST); | ||
@@ -137,4 +168,17 @@ | ||
; | ||
const event = { | ||
pageIndex: this.pageIndex + 1, | ||
promise | ||
}; | ||
this.emitter.emit(Events.NEXT, event); | ||
return promise; | ||
} | ||
/** | ||
* @param {string} url | ||
* @returns {Promise} returns LOADED event on success | ||
*/ | ||
load(url) { | ||
@@ -146,2 +190,28 @@ let ias = this; | ||
let loadEvent = { | ||
url, | ||
xhr, | ||
method: 'GET', | ||
body: null, | ||
nocache: false, | ||
responseType: ias.options.responseType, | ||
headers: { | ||
'X-Requested-With': 'XMLHttpRequest', | ||
}, | ||
}; | ||
// event properties are mutable | ||
ias.emitter.emit(Events.LOAD, loadEvent); | ||
let finalUrl = loadEvent.url; | ||
let method = loadEvent.method; | ||
let responseType = loadEvent.responseType; | ||
let headers = loadEvent.headers; | ||
let body = loadEvent.body; | ||
if (!loadEvent.nocache) { | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
finalUrl = finalUrl + ((/\?/).test(finalUrl) ? "&" : "?") + (new Date()).getTime(); | ||
} | ||
xhr.onreadystatechange = function() { | ||
@@ -152,6 +222,9 @@ if (xhr.readyState !== XMLHttpRequest.DONE) { | ||
if (xhr.status === 200) { | ||
if (xhr.status === 0) { | ||
// weird status happening during Cypress tests | ||
} | ||
else if (xhr.status === 200) { | ||
let items = xhr.response; | ||
if (ias.options.responseType === 'document') { | ||
if (responseType === 'document') { | ||
items = $(ias.options.item, xhr.response); | ||
@@ -161,8 +234,9 @@ // @todo assert there actually are items in the response | ||
ias.emitter.emit(Events.LOADED, {items, url, xhr}); | ||
// we don't use a shared loadedEvent variable here, because these values should be immutable | ||
resolve({items, url, xhr}); | ||
ias.emitter.emit(Events.LOADED, {items, url: finalUrl, xhr}); | ||
resolve({items, url: finalUrl, xhr}); | ||
} else { | ||
// @todo is console.error the best approach? | ||
console.error('Request failed'); | ||
ias.emitter.emit(Events.ERROR, {url: finalUrl, method, xhr}); | ||
@@ -173,15 +247,16 @@ reject(xhr); | ||
// FIXME: make no-caching configurable | ||
// @see https://developer.mozilla.org/nl/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache | ||
let nocacheUrl = url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime(); | ||
xhr.onerror = function() { | ||
ias.emitter.emit(Events.ERROR, {url: finalUrl, method, xhr}); | ||
xhr.open('GET', nocacheUrl, true); | ||
xhr.responseType = ias.options.responseType; | ||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); | ||
reject(xhr); | ||
} | ||
// @todo define event variable and pass that around so it can be manipulated | ||
xhr.open(method, finalUrl, true); | ||
xhr.responseType = responseType; | ||
ias.emitter.emit(Events.LOAD, {url, xhr}); | ||
for (let header in headers) { | ||
xhr.setRequestHeader(header, headers[header]); | ||
} | ||
xhr.send(); | ||
xhr.send(body); | ||
}); | ||
@@ -235,4 +310,2 @@ } | ||
this.paused = false; | ||
this.measure(); | ||
} | ||
@@ -248,2 +321,17 @@ | ||
distance(rootRect, sentinel) { | ||
const _rootRect = rootRect || getRootRect(this.scrollContainer); | ||
const _sentinel = sentinel || this.sentinel(); | ||
const scrollPosition = getScrollPosition(this.scrollContainer); | ||
let distance = getDistanceToFold(_sentinel, scrollPosition, _rootRect); | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
return distance; | ||
} | ||
measure() { | ||
@@ -254,13 +342,18 @@ if (this.paused) { | ||
let distance = 0; | ||
const sentinel = this.sentinel(); | ||
const rootRect = getRootRect(this.scrollContainer); | ||
// @todo review this logic when prefill support is added | ||
if (sentinel) { | ||
distance = getDistanceToFold(sentinel, this.scrollContainer); | ||
// When the scroll container has no height, this could indicate that | ||
// the element is not visible (display = none). Without a height | ||
// we cannot calculate the distance to fold. On the other hand we don't | ||
// have to, because it's not visible anyway. Our resize observer will | ||
// monitor the height, once it's greater than 0 everything will resume as normal. | ||
if (rootRect.height === 0) { | ||
// @todo DX: show warning in console that this is happening | ||
return; | ||
} | ||
// apply negative margin | ||
distance -= this.negativeMargin; | ||
const sentinel = this.sentinel(); | ||
let distance = this.distance(rootRect, sentinel); | ||
if (distance <= 0) { | ||
@@ -284,8 +377,11 @@ this.emitter.emit(Events.HIT, {distance}); | ||
once(event, callback) { | ||
this.emitter.once(event, callback, this); | ||
return new Promise((resolve) => { | ||
this.emitter.once(event, function() { Promise.resolve(callback.apply(this, arguments)).then(resolve) }, this); | ||
if (event === Events.BINDED && this.binded) { | ||
callback.bind(this)(); | ||
} | ||
if (event === Events.BINDED && this.binded) { | ||
callback.bind(this)(); | ||
resolve() | ||
} | ||
}) | ||
} | ||
} |
@@ -39,3 +39,9 @@ /* eslint no-console: "off" */ | ||
console.log(`Page changed [pageIndex=${event.pageIndex}]`); | ||
} | ||
}, | ||
prefill: (event) => { | ||
console.log(`Start prefilling`); | ||
}, | ||
prefilled: (event) => { | ||
console.log(`Finished prefilling`); | ||
}, | ||
}; | ||
@@ -42,0 +48,0 @@ |
@@ -52,3 +52,2 @@ import {getRootRect} from "./dimensions"; | ||
// @todo can be moved inside appended when eventStack is implemented | ||
let loaded = (event) => { | ||
@@ -64,3 +63,3 @@ url = event.url; | ||
this.ias.once(Events.APPENDED, () => { | ||
nextEvent.promise.then(() => { | ||
this.pageBreaks.push({ | ||
@@ -75,3 +74,2 @@ pageIndex: nextEvent.pageIndex, | ||
// @todo can be removed when eventStack is implemented | ||
this.ias.off(Events.LOADED, loaded); | ||
@@ -78,0 +76,0 @@ }); |
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
131095
21
3399