146 lines
5.3 KiB
JavaScript
146 lines
5.3 KiB
JavaScript
'use strict';
|
|
|
|
const page = require('page');
|
|
const events = require('../events.js');
|
|
const views = require('../util/views.js');
|
|
|
|
class EndlessPageView {
|
|
constructor() {
|
|
this.holderTemplate = views.getTemplate('endless-pager');
|
|
this.pageTemplate = views.getTemplate('endless-pager-page');
|
|
}
|
|
|
|
render(ctx) {
|
|
const target = document.getElementById('content-holder');
|
|
const source = this.holderTemplate();
|
|
const pageHeaderHolder = source.querySelector('.page-header-holder');
|
|
const pagesHolder = source.querySelector('.pages-holder');
|
|
views.listenToMessages(target);
|
|
views.showView(target, source);
|
|
|
|
let headerRendererCtx = ctx;
|
|
headerRendererCtx.target = pageHeaderHolder;
|
|
ctx.headerRenderer.render(headerRendererCtx);
|
|
|
|
const threshold = window.innerHeight / 3;
|
|
|
|
if (ctx.state && ctx.state.html) {
|
|
console.log('Loading from state');
|
|
this.minPageShown = ctx.state.minPageShown;
|
|
this.maxPageShown = ctx.state.maxPageShown;
|
|
this.totalPages = ctx.state.totalPages;
|
|
this.currentPage = ctx.state.currentPage;
|
|
} else {
|
|
this.minPageShown = null;
|
|
this.maxPageShown = null;
|
|
this.totalPages = null;
|
|
this.currentPage = null;
|
|
}
|
|
this.fetching = false;
|
|
|
|
this.updater = () => {
|
|
let topPage = null;
|
|
let allPageNodes =
|
|
pagesHolder.querySelectorAll('.page');
|
|
for (let pageNode of allPageNodes) {
|
|
if (pageNode.getBoundingClientRect().bottom >= 0) {
|
|
topPage = parseInt(pageNode.getAttribute('data-page'));
|
|
break;
|
|
}
|
|
}
|
|
if (topPage !== this.currentPage) {
|
|
page.replace(
|
|
ctx.clientUrl.format({page: topPage}),
|
|
{
|
|
minPageShown: this.minPageShown,
|
|
maxPageShown: this.maxPageShown,
|
|
totalPages: this.totalPages,
|
|
currentPage: this.currentPage,
|
|
html: pagesHolder.innerHTML,
|
|
scrollX: window.scrollX,
|
|
scrollY: window.scrollY,
|
|
},
|
|
false,
|
|
false);
|
|
this.currentPage = topPage;
|
|
}
|
|
|
|
if (this.fetching || this.totalPages === null) {
|
|
return;
|
|
}
|
|
let scrollHeight =
|
|
document.documentElement.scrollHeight -
|
|
document.documentElement.clientHeight;
|
|
|
|
if (this.minPageShown > 1 && window.scrollY - threshold < 0) {
|
|
this.loadPage(pagesHolder, ctx, this.minPageShown - 1, false);
|
|
} else if (this.maxPageShown < this.totalPages &&
|
|
window.scrollY + threshold > scrollHeight) {
|
|
this.loadPage(pagesHolder, ctx, this.maxPageShown + 1, true);
|
|
}
|
|
};
|
|
|
|
if (ctx.state && ctx.state.html) {
|
|
pagesHolder.innerHTML = ctx.state.html;
|
|
window.scroll(ctx.state.scrollX, ctx.state.scrollY);
|
|
} else {
|
|
this.loadPage(pagesHolder, ctx, ctx.searchQuery.page, true);
|
|
}
|
|
window.addEventListener('scroll', this.updater, true);
|
|
}
|
|
|
|
unrender() {
|
|
window.removeEventListener('scroll', this.updater, true);
|
|
}
|
|
|
|
loadPage(pagesHolder, ctx, pageNumber, append) {
|
|
this.fetching = true;
|
|
|
|
if (pageNumber < this.minPageShown || this.minPageShown === null) {
|
|
this.minPageShown = pageNumber;
|
|
}
|
|
if (pageNumber > this.maxPageShown || this.maxPageShown === null) {
|
|
this.maxPageShown = pageNumber;
|
|
}
|
|
|
|
ctx.requestPage(pageNumber).then(response => {
|
|
this.totalPages = Math.ceil(response.total / response.pageSize);
|
|
if (response.total) {
|
|
const pageNode = this.pageTemplate({
|
|
page: pageNumber,
|
|
totalPages: this.totalPages,
|
|
});
|
|
pageNode.setAttribute('data-page', pageNumber);
|
|
|
|
let pageRendererCtx = response;
|
|
pageRendererCtx.target = pageNode.querySelector(
|
|
'.page-content-holder');
|
|
ctx.pageRenderer.render(pageRendererCtx);
|
|
|
|
if (append) {
|
|
pagesHolder.appendChild(pageNode);
|
|
} else {
|
|
pagesHolder.prependChild(pageNode);
|
|
|
|
// note: with probability of 75%, if the user has scrolled
|
|
// with a mouse wheel, chrome 49 doesn't give a slightest
|
|
// fuck about this and loads all the way to page 1 at once
|
|
window.scroll(
|
|
window.scrollX,
|
|
window.scrollY + pageNode.offsetHeight);
|
|
}
|
|
}
|
|
|
|
this.fetching = false;
|
|
this.updater();
|
|
|
|
if (response.total <= (pageNumber - 1) * response.pageSize) {
|
|
events.notify(events.Info, 'No data to show');
|
|
}
|
|
}, response => {
|
|
events.notify(events.Error, response.description);
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = EndlessPageView;
|