szurubooru/client/js/views/endless_page_view.js

231 lines
6.8 KiB
JavaScript
Raw Normal View History

2016-04-12 23:49:46 +02:00
'use strict';
const router = require('../router.js');
2016-04-12 23:49:46 +02:00
const views = require('../util/views.js');
const holderTemplate = views.getTemplate('endless-pager');
const pageTemplate = views.getTemplate('endless-pager-page');
function isScrolledIntoView(element) {
let top = 0;
do {
top += element.offsetTop || 0;
element = element.offsetParent;
2020-06-04 20:09:35 +02:00
} while (element);
return (
(top >= window.scrollY) &&
(top <= window.scrollY + window.innerHeight));
}
2016-04-12 23:49:46 +02:00
class EndlessPageView {
constructor(ctx) {
this._hostNode = document.getElementById('content-holder');
views.replaceContent(this._hostNode, holderTemplate());
}
run(ctx) {
this._destroy();
this._active = true;
this._runningRequests = 0;
this._initialPageLoad = true;
2016-04-12 23:49:46 +02:00
this.clearMessages();
views.emptyContent(this._pagesHolderNode);
2017-02-09 00:48:06 +01:00
this.minOffsetShown = null;
this.maxOffsetShown = null;
this.totalRecords = null;
this.currentOffset = 0;
this.defaultLimit = parseInt(ctx.parameters.limit || ctx.defaultLimit);
2017-02-09 00:48:06 +01:00
const initialOffset = parseInt(ctx.parameters.offset || 0);
this._loadPage(ctx, initialOffset, this.defaultLimit, true)
2017-02-09 00:48:06 +01:00
.then(pageNode => {
if (initialOffset !== 0) {
2017-02-09 00:48:06 +01:00
pageNode.scrollIntoView();
}
});
this._timeout = window.setInterval(() => {
window.requestAnimationFrame(() => {
this._probePageLoad(ctx);
this._syncUrl(ctx);
});
}, 250);
views.monitorNodeRemoval(this._pagesHolderNode, () => this._destroy());
}
get pageHeaderHolderNode() {
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() {
return this._hostNode.querySelector('.pages-holder');
}
_destroy() {
window.clearInterval(this._timeout);
this._active = false;
}
2016-04-12 23:49:46 +02:00
_syncUrl(ctx) {
2016-06-12 21:01:18 +02:00
let topPageNode = null;
let element = document.elementFromPoint(
window.innerWidth / 2,
window.innerHeight / 2);
while (element.parentNode !== null) {
if (element.classList.contains('page')) {
topPageNode = element;
break;
}
element = element.parentNode;
}
if (!topPageNode) {
return;
}
2017-02-09 00:48:06 +01:00
let topOffset = parseInt(topPageNode.getAttribute('data-offset'));
let topLimit = parseInt(topPageNode.getAttribute('data-limit'));
if (topOffset !== this.currentOffset) {
2016-06-12 21:01:18 +02:00
router.replace(
2017-02-09 00:48:06 +01:00
ctx.getClientUrlForPage(
topOffset,
topLimit === ctx.defaultLimit ? null : topLimit),
ctx.state,
2016-06-12 21:01:18 +02:00
false);
2017-02-09 00:48:06 +01:00
this.currentOffset = topOffset;
2016-06-12 21:01:18 +02:00
}
}
_probePageLoad(ctx) {
if (!this._active || this._runningRequests) {
return;
}
2016-06-12 21:01:18 +02:00
2017-02-09 00:48:06 +01:00
if (this.totalRecords === null) {
2016-06-12 21:01:18 +02:00
return;
}
if (this.minOffsetShown > 0 &&
isScrolledIntoView(this.topPageGuardNode)) {
2017-02-09 00:48:06 +01:00
this._loadPage(
ctx,
this.minOffsetShown - this.defaultLimit,
this.defaultLimit,
false);
}
if (this.maxOffsetShown < this.totalRecords &&
isScrolledIntoView(this.bottomPageGuardNode)) {
2017-02-09 00:48:06 +01:00
this._loadPage(
ctx,
this.maxOffsetShown,
this.defaultLimit,
true);
2016-06-12 21:01:18 +02:00
}
}
2017-02-09 00:48:06 +01:00
_loadPage(ctx, offset, limit, append) {
this._runningRequests++;
2016-07-13 17:18:28 +02:00
return new Promise((resolve, reject) => {
2017-02-09 00:48:06 +01:00
ctx.requestPage(offset, limit).then(response => {
2016-07-13 17:18:28 +02:00
if (!this._active) {
this._runningRequests--;
2016-07-13 17:18:28 +02:00
return Promise.reject();
}
window.requestAnimationFrame(() => {
2017-02-09 00:48:06 +01:00
let pageNode = this._renderPage(ctx, append, response);
this._runningRequests--;
2016-07-13 17:18:28 +02:00
resolve(pageNode);
});
2017-01-08 02:12:38 +01:00
}, error => {
this.showError(error.message);
this._runningRequests--;
2016-07-13 17:18:28 +02:00
reject();
2016-06-12 21:01:18 +02:00
});
2016-04-12 23:49:46 +02:00
});
}
2016-06-12 21:01:18 +02:00
2017-02-09 00:48:06 +01:00
_renderPage(ctx, append, response) {
2016-07-13 17:18:28 +02:00
let pageNode = null;
2016-06-12 21:01:18 +02:00
if (response.total) {
2016-07-13 17:18:28 +02:00
pageNode = pageTemplate({
2017-02-09 00:48:06 +01:00
totalPages: Math.ceil(response.total / response.limit),
page: Math.ceil(
(response.offset + response.limit) / response.limit),
});
pageNode.setAttribute('data-offset', response.offset);
pageNode.setAttribute('data-limit', response.limit);
ctx.pageRenderer({
parameters: ctx.parameters,
response: response,
hostNode: pageNode.querySelector('.page-content-holder'),
2016-06-12 21:01:18 +02:00
});
2017-02-09 00:48:06 +01:00
this.totalRecords = response.total;
2016-06-12 21:01:18 +02:00
2017-02-09 00:48:06 +01:00
if (response.offset < this.minOffsetShown ||
this.minOffsetShown === null) {
this.minOffsetShown = response.offset;
2016-06-12 21:01:18 +02:00
}
2017-02-09 00:48:06 +01:00
if (response.offset + response.results.length
> this.maxOffsetShown ||
this.maxOffsetShown === null) {
this.maxOffsetShown =
response.offset + response.results.length;
2016-06-12 21:01:18 +02:00
}
response.results.addEventListener('remove', e => {
this.maxOffsetShown--;
this.totalRecords--;
});
2016-06-12 21:01:18 +02:00
if (append) {
this._pagesHolderNode.appendChild(pageNode);
if (this._initialPageLoad && response.offset > 0) {
2016-06-12 21:01:18 +02:00
window.scroll(0, pageNode.getBoundingClientRect().top);
}
2016-06-12 21:01:18 +02:00
} else {
this._pagesHolderNode.prependChild(pageNode);
2016-06-12 21:01:18 +02:00
window.scroll(
window.scrollX,
window.scrollY + pageNode.offsetHeight);
}
2017-02-09 00:48:06 +01:00
} else if (!response.results.length) {
this.showInfo('No data to show');
2016-06-12 21:01:18 +02:00
}
2016-07-13 17:18:28 +02:00
this._initialPageLoad = false;
2016-07-13 17:18:28 +02:00
return pageNode;
2016-06-12 21:01:18 +02:00
}
clearMessages() {
views.clearMessages(this._hostNode);
}
showSuccess(message) {
views.showSuccess(this._hostNode, message);
}
showError(message) {
views.showError(this._hostNode, message);
}
showInfo(message) {
views.showInfo(this._hostNode, message);
}
2016-04-12 23:49:46 +02:00
}
module.exports = EndlessPageView;