parent
33b49ebffd
commit
5dfdfd49e9
2 changed files with 60 additions and 32 deletions
|
@ -1,5 +1,7 @@
|
||||||
<div class='pager'>
|
<div class='pager'>
|
||||||
<div class='page-header-holder'></div>
|
<div class='page-header-holder'></div>
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
|
<div class='page-guard top'></div>
|
||||||
<div class='pages-holder'></div>
|
<div class='pages-holder'></div>
|
||||||
|
<div class='page-guard bottom'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,6 +6,13 @@ const views = require('../util/views.js');
|
||||||
const holderTemplate = views.getTemplate('endless-pager');
|
const holderTemplate = views.getTemplate('endless-pager');
|
||||||
const pageTemplate = views.getTemplate('endless-pager-page');
|
const pageTemplate = views.getTemplate('endless-pager-page');
|
||||||
|
|
||||||
|
function isScrolledIntoView(el) {
|
||||||
|
const elemTop = el.getBoundingClientRect().top;
|
||||||
|
const elemBottom = el.getBoundingClientRect().bottom;
|
||||||
|
const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
|
||||||
|
return isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
class EndlessPageView {
|
class EndlessPageView {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
this._hostNode = document.getElementById('content-holder');
|
this._hostNode = document.getElementById('content-holder');
|
||||||
|
@ -13,28 +20,35 @@ class EndlessPageView {
|
||||||
}
|
}
|
||||||
|
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
|
this._destroy();
|
||||||
|
|
||||||
this._active = true;
|
this._active = true;
|
||||||
this._working = 0;
|
this._runningRequests = 0;
|
||||||
this._init = false;
|
this._initialPageLoad = true;
|
||||||
|
|
||||||
this.clearMessages();
|
this.clearMessages();
|
||||||
views.emptyContent(this._pagesHolderNode);
|
views.emptyContent(this._pagesHolderNode);
|
||||||
|
|
||||||
this.threshold = window.innerHeight / 3;
|
|
||||||
this.minOffsetShown = null;
|
this.minOffsetShown = null;
|
||||||
this.maxOffsetShown = null;
|
this.maxOffsetShown = null;
|
||||||
this.totalRecords = null;
|
this.totalRecords = null;
|
||||||
this.currentOffset = 0;
|
this.currentOffset = 0;
|
||||||
|
this.defaultLimit = parseInt(ctx.parameters.limit || ctx.defaultLimit);
|
||||||
|
|
||||||
const offset = parseInt(ctx.parameters.offset || 0);
|
const initialOffset = parseInt(ctx.parameters.offset || 0);
|
||||||
const limit = parseInt(ctx.parameters.limit || ctx.defaultLimit);
|
this._loadPage(ctx, initialOffset, this.defaultLimit, true)
|
||||||
this._loadPage(ctx, offset, limit, true)
|
|
||||||
.then(pageNode => {
|
.then(pageNode => {
|
||||||
if (offset !== 0) {
|
if (initialOffset !== 0) {
|
||||||
pageNode.scrollIntoView();
|
pageNode.scrollIntoView();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._probePageLoad(ctx);
|
|
||||||
|
this._timeout = window.setInterval(() => {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
this._probePageLoad(ctx);
|
||||||
|
this._syncUrl(ctx);
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
|
||||||
views.monitorNodeRemoval(this._pagesHolderNode, () => this._destroy());
|
views.monitorNodeRemoval(this._pagesHolderNode, () => this._destroy());
|
||||||
}
|
}
|
||||||
|
@ -43,27 +57,24 @@ class EndlessPageView {
|
||||||
return this._hostNode.querySelector('.page-header-holder');
|
return this._hostNode.querySelector('.page-header-holder');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get topPageGuardNode() {
|
||||||
|
return this._hostNode.querySelector('.page-guard.top');
|
||||||
|
}
|
||||||
|
|
||||||
|
get bottomPageGuardNode() {
|
||||||
|
return this._hostNode.querySelector('.page-guard.bottom');
|
||||||
|
}
|
||||||
|
|
||||||
get _pagesHolderNode() {
|
get _pagesHolderNode() {
|
||||||
return this._hostNode.querySelector('.pages-holder');
|
return this._hostNode.querySelector('.pages-holder');
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroy() {
|
_destroy() {
|
||||||
|
window.clearInterval(this._timeout);
|
||||||
this._active = false;
|
this._active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_probePageLoad(ctx) {
|
_syncUrl(ctx) {
|
||||||
if (this._active) {
|
|
||||||
window.setTimeout(() => {
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
this._probePageLoad(ctx);
|
|
||||||
});
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._working) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let topPageNode = null;
|
let topPageNode = null;
|
||||||
let element = document.elementFromPoint(
|
let element = document.elementFromPoint(
|
||||||
window.innerWidth / 2,
|
window.innerWidth / 2,
|
||||||
|
@ -89,6 +100,12 @@ class EndlessPageView {
|
||||||
false);
|
false);
|
||||||
this.currentOffset = topOffset;
|
this.currentOffset = topOffset;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_probePageLoad(ctx) {
|
||||||
|
if (!this._active || this._runningRequests) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.totalRecords === null) {
|
if (this.totalRecords === null) {
|
||||||
return;
|
return;
|
||||||
|
@ -97,32 +114,41 @@ class EndlessPageView {
|
||||||
document.documentElement.scrollHeight -
|
document.documentElement.scrollHeight -
|
||||||
document.documentElement.clientHeight;
|
document.documentElement.clientHeight;
|
||||||
|
|
||||||
if (this.minOffsetShown > 0 && window.scrollY < this.threshold) {
|
if (this.minOffsetShown > 0 &&
|
||||||
|
isScrolledIntoView(this.topPageGuardNode)) {
|
||||||
this._loadPage(
|
this._loadPage(
|
||||||
ctx, this.minOffsetShown - topLimit, topLimit, false);
|
ctx,
|
||||||
} else if (this.maxOffsetShown < this.totalRecords &&
|
this.minOffsetShown - this.defaultLimit,
|
||||||
window.scrollY + this.threshold > scrollHeight) {
|
this.defaultLimit,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.maxOffsetShown < this.totalRecords &&
|
||||||
|
isScrolledIntoView(this.bottomPageGuardNode)) {
|
||||||
this._loadPage(
|
this._loadPage(
|
||||||
ctx, this.maxOffsetShown, topLimit, true);
|
ctx,
|
||||||
|
this.maxOffsetShown,
|
||||||
|
this.defaultLimit,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadPage(ctx, offset, limit, append) {
|
_loadPage(ctx, offset, limit, append) {
|
||||||
this._working++;
|
this._runningRequests++;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ctx.requestPage(offset, limit).then(response => {
|
ctx.requestPage(offset, limit).then(response => {
|
||||||
if (!this._active) {
|
if (!this._active) {
|
||||||
this._working--;
|
this._runningRequests--;
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
let pageNode = this._renderPage(ctx, append, response);
|
let pageNode = this._renderPage(ctx, append, response);
|
||||||
this._working--;
|
this._runningRequests--;
|
||||||
resolve(pageNode);
|
resolve(pageNode);
|
||||||
});
|
});
|
||||||
}, error => {
|
}, error => {
|
||||||
this.showError(error.message);
|
this.showError(error.message);
|
||||||
this._working--;
|
this._runningRequests--;
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -165,7 +191,7 @@ class EndlessPageView {
|
||||||
|
|
||||||
if (append) {
|
if (append) {
|
||||||
this._pagesHolderNode.appendChild(pageNode);
|
this._pagesHolderNode.appendChild(pageNode);
|
||||||
if (!this._init && response.offset > 0) {
|
if (this._initialPageLoad && response.offset > 0) {
|
||||||
window.scroll(0, pageNode.getBoundingClientRect().top);
|
window.scroll(0, pageNode.getBoundingClientRect().top);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,7 +205,7 @@ class EndlessPageView {
|
||||||
this.showInfo('No data to show');
|
this.showInfo('No data to show');
|
||||||
}
|
}
|
||||||
|
|
||||||
this._init = true;
|
this._initialPageLoad = false;
|
||||||
return pageNode;
|
return pageNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue