client/general: improve scrolling
This commit is contained in:
parent
5d8dd9cb05
commit
394e51ed21
16 changed files with 57 additions and 38 deletions
|
@ -24,12 +24,6 @@ router.enter(
|
|||
(ctx, next) => {
|
||||
mousetrap.reset();
|
||||
next();
|
||||
window.requestAnimationFrame(
|
||||
() => {
|
||||
window.scrollTo(
|
||||
ctx.state.scrollX || 0,
|
||||
ctx.state.scrollY || 0);
|
||||
});
|
||||
});
|
||||
|
||||
// register controller routes
|
||||
|
|
|
@ -390,17 +390,15 @@ function replaceContent(target, source) {
|
|||
}
|
||||
}
|
||||
|
||||
function scrollToHash() {
|
||||
window.setTimeout(() => {
|
||||
if (!window.location.hash) {
|
||||
return;
|
||||
}
|
||||
const el = document.getElementById(
|
||||
window.location.hash.replace(/#/, ''));
|
||||
if (el) {
|
||||
el.scrollIntoView();
|
||||
}
|
||||
}, 10);
|
||||
function syncScrollPosition() {
|
||||
window.requestAnimationFrame(
|
||||
() => {
|
||||
if (history.state.hasOwnProperty('scrollX')) {
|
||||
window.scrollTo(history.state.scrollX, history.state.scrollY);
|
||||
} else {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function slideDown(element) {
|
||||
|
@ -470,7 +468,7 @@ module.exports = {
|
|||
decorateValidator: decorateValidator,
|
||||
makeVoidElement: makeVoidElement,
|
||||
makeNonVoidElement: makeNonVoidElement,
|
||||
scrollToHash: scrollToHash,
|
||||
syncScrollPosition: syncScrollPosition,
|
||||
slideDown: slideDown,
|
||||
slideUp: slideUp,
|
||||
monitorNodeRemoval: monitorNodeRemoval,
|
||||
|
|
|
@ -11,6 +11,7 @@ class EmptyView {
|
|||
constructor() {
|
||||
this._hostNode = document.getElementById('content-holder');
|
||||
views.replaceContent(this._hostNode, template());
|
||||
views.syncScrollPosition();
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
|
|
|
@ -11,7 +11,7 @@ class EndlessPageView {
|
|||
this._hostNode = document.getElementById('content-holder');
|
||||
this._active = true;
|
||||
this._working = 0;
|
||||
this._init = true;
|
||||
this._init = false;
|
||||
|
||||
this.threshold = window.innerHeight / 3;
|
||||
this.minPageShown = null;
|
||||
|
@ -30,7 +30,11 @@ class EndlessPageView {
|
|||
ctx.headerRenderer(ctx.headerContext);
|
||||
}
|
||||
|
||||
this._loadPage(ctx, ctx.parameters.page, true);
|
||||
this._loadPage(ctx, ctx.parameters.page, true).then(pageNode => {
|
||||
if (ctx.parameters.page !== 1) {
|
||||
pageNode.scrollIntoView();
|
||||
}
|
||||
});
|
||||
this._probePageLoad(ctx);
|
||||
}
|
||||
|
||||
|
@ -87,26 +91,32 @@ class EndlessPageView {
|
|||
|
||||
_loadPage(ctx, pageNumber, append) {
|
||||
this._working++;
|
||||
ctx.requestPage(pageNumber).then(response => {
|
||||
if (!this._active) {
|
||||
this._working--;
|
||||
return Promise.reject();
|
||||
}
|
||||
this.totalPages = Math.ceil(response.total / response.pageSize);
|
||||
window.requestAnimationFrame(() => {
|
||||
this._renderPage(
|
||||
ctx, pageNumber, append, response);
|
||||
return new Promise((resolve, reject) => {
|
||||
ctx.requestPage(pageNumber).then(response => {
|
||||
if (!this._active) {
|
||||
this._working--;
|
||||
return Promise.reject();
|
||||
}
|
||||
this.totalPages = Math.ceil(response.total / response.pageSize);
|
||||
window.requestAnimationFrame(() => {
|
||||
let pageNode = this._renderPage(
|
||||
ctx, pageNumber, append, response);
|
||||
this._working--;
|
||||
resolve(pageNode);
|
||||
});
|
||||
}, response => {
|
||||
this.showError(response.description);
|
||||
this._working--;
|
||||
reject();
|
||||
});
|
||||
}, response => {
|
||||
this.showError(response.description);
|
||||
this._working--;
|
||||
});
|
||||
}
|
||||
|
||||
_renderPage(ctx, pageNumber, append, response) {
|
||||
let pageNode = null;
|
||||
|
||||
if (response.total) {
|
||||
const pageNode = pageTemplate({
|
||||
pageNode = pageTemplate({
|
||||
page: pageNumber,
|
||||
totalPages: this.totalPages,
|
||||
});
|
||||
|
@ -128,7 +138,7 @@ class EndlessPageView {
|
|||
|
||||
if (append) {
|
||||
this._pagesHolderNode.appendChild(pageNode);
|
||||
if (this._init && pageNumber !== 1) {
|
||||
if (!this._init && pageNumber !== 1) {
|
||||
window.scroll(0, pageNode.getBoundingClientRect().top);
|
||||
}
|
||||
} else {
|
||||
|
@ -141,7 +151,9 @@ class EndlessPageView {
|
|||
} else if (response.total <= (pageNumber - 1) * response.pageSize) {
|
||||
this.showInfo('No data to show');
|
||||
}
|
||||
this._init = false;
|
||||
|
||||
this._init = true;
|
||||
return pageNode;
|
||||
}
|
||||
|
||||
showSuccess(message) {
|
||||
|
|
|
@ -59,7 +59,7 @@ class HelpView {
|
|||
}
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
views.scrollToHash();
|
||||
views.syncScrollPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class HomeView {
|
|||
|
||||
const sourceNode = template(ctx);
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
views.syncScrollPosition();
|
||||
|
||||
if (this._formNode) {
|
||||
this._tagAutoCompleteControl = new TagAutoCompleteControl(
|
||||
|
|
|
@ -16,6 +16,7 @@ class LoginView extends events.EventTarget {
|
|||
passwordPattern: config.passwordRegex,
|
||||
canSendMails: config.canSendMails,
|
||||
}));
|
||||
views.syncScrollPosition();
|
||||
|
||||
views.decorateValidator(this._formNode);
|
||||
this._userNameFieldNode.setAttribute('pattern', config.userNameRegex);
|
||||
|
|
|
@ -107,6 +107,8 @@ class ManualPageView {
|
|||
if (response.total <= (currentPage - 1) * response.pageSize) {
|
||||
this.showInfo('No data to show');
|
||||
}
|
||||
|
||||
views.syncScrollPosition();
|
||||
}, response => {
|
||||
this.showError(response.description);
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ class NotFoundView {
|
|||
|
||||
const sourceNode = template({path: path});
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
views.syncScrollPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@ class PasswordResetView extends events.EventTarget {
|
|||
this._hostNode = document.getElementById('content-holder');
|
||||
|
||||
views.replaceContent(this._hostNode, template());
|
||||
views.decorateValidator(this._formNode);
|
||||
views.syncScrollPosition();
|
||||
|
||||
views.decorateValidator(this._formNode);
|
||||
this._hostNode.addEventListener('submit', e => {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('submit', {
|
||||
|
|
|
@ -23,6 +23,7 @@ class PostView {
|
|||
const postContainerNode = sourceNode.querySelector('.post-container');
|
||||
const sidebarNode = sourceNode.querySelector('.sidebar');
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
views.syncScrollPosition();
|
||||
|
||||
const postViewNode = document.body.querySelector('.content-wrapper');
|
||||
const topNavigationNode =
|
||||
|
|
|
@ -14,6 +14,7 @@ class RegistrationView extends events.EventTarget {
|
|||
userNamePattern: config.userNameRegex,
|
||||
passwordPattern: config.passwordRegex,
|
||||
}));
|
||||
views.syncScrollPosition();
|
||||
views.decorateValidator(this._formNode);
|
||||
this._formNode.addEventListener('submit', e => this._evtSubmit(e));
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ class SettingsView extends events.EventTarget {
|
|||
this._hostNode = document.getElementById('content-holder');
|
||||
views.replaceContent(
|
||||
this._hostNode, template({browsingSettings: ctx.settings}));
|
||||
views.decorateValidator(this._formNode);
|
||||
views.syncScrollPosition();
|
||||
|
||||
views.decorateValidator(this._formNode);
|
||||
this._formNode.addEventListener('submit', e => this._evtSubmit(e));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ class TagCategoriesView extends events.EventTarget {
|
|||
this._hostNode = document.getElementById('content-holder');
|
||||
|
||||
views.replaceContent(this._hostNode, template(ctx));
|
||||
views.syncScrollPosition();
|
||||
views.decorateValidator(this._formNode);
|
||||
|
||||
const categoriesToAdd = Array.from(ctx.tagCategories);
|
||||
|
|
|
@ -52,6 +52,8 @@ class TagView extends events.EventTarget {
|
|||
} else {
|
||||
this._view = new TagSummaryView(ctx);
|
||||
}
|
||||
|
||||
views.syncScrollPosition();
|
||||
}
|
||||
|
||||
clearMessages() {
|
||||
|
|
|
@ -47,6 +47,8 @@ class UserView extends events.EventTarget {
|
|||
} else {
|
||||
this._view = new UserSummaryView(ctx);
|
||||
}
|
||||
|
||||
views.syncScrollPosition();
|
||||
}
|
||||
|
||||
clearMessages() {
|
||||
|
|
Loading…
Reference in a new issue