client/general: improve scrolling

This commit is contained in:
rr- 2016-07-13 17:18:28 +02:00
parent 5d8dd9cb05
commit 394e51ed21
16 changed files with 57 additions and 38 deletions

View file

@ -24,12 +24,6 @@ router.enter(
(ctx, next) => { (ctx, next) => {
mousetrap.reset(); mousetrap.reset();
next(); next();
window.requestAnimationFrame(
() => {
window.scrollTo(
ctx.state.scrollX || 0,
ctx.state.scrollY || 0);
});
}); });
// register controller routes // register controller routes

View file

@ -390,17 +390,15 @@ function replaceContent(target, source) {
} }
} }
function scrollToHash() { function syncScrollPosition() {
window.setTimeout(() => { window.requestAnimationFrame(
if (!window.location.hash) { () => {
return; if (history.state.hasOwnProperty('scrollX')) {
} window.scrollTo(history.state.scrollX, history.state.scrollY);
const el = document.getElementById( } else {
window.location.hash.replace(/#/, '')); window.scrollTo(0, 0);
if (el) { }
el.scrollIntoView(); });
}
}, 10);
} }
function slideDown(element) { function slideDown(element) {
@ -470,7 +468,7 @@ module.exports = {
decorateValidator: decorateValidator, decorateValidator: decorateValidator,
makeVoidElement: makeVoidElement, makeVoidElement: makeVoidElement,
makeNonVoidElement: makeNonVoidElement, makeNonVoidElement: makeNonVoidElement,
scrollToHash: scrollToHash, syncScrollPosition: syncScrollPosition,
slideDown: slideDown, slideDown: slideDown,
slideUp: slideUp, slideUp: slideUp,
monitorNodeRemoval: monitorNodeRemoval, monitorNodeRemoval: monitorNodeRemoval,

View file

@ -11,6 +11,7 @@ class EmptyView {
constructor() { constructor() {
this._hostNode = document.getElementById('content-holder'); this._hostNode = document.getElementById('content-holder');
views.replaceContent(this._hostNode, template()); views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
} }
showError(message) { showError(message) {

View file

@ -11,7 +11,7 @@ class EndlessPageView {
this._hostNode = document.getElementById('content-holder'); this._hostNode = document.getElementById('content-holder');
this._active = true; this._active = true;
this._working = 0; this._working = 0;
this._init = true; this._init = false;
this.threshold = window.innerHeight / 3; this.threshold = window.innerHeight / 3;
this.minPageShown = null; this.minPageShown = null;
@ -30,7 +30,11 @@ class EndlessPageView {
ctx.headerRenderer(ctx.headerContext); 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); this._probePageLoad(ctx);
} }
@ -87,26 +91,32 @@ class EndlessPageView {
_loadPage(ctx, pageNumber, append) { _loadPage(ctx, pageNumber, append) {
this._working++; this._working++;
ctx.requestPage(pageNumber).then(response => { return new Promise((resolve, reject) => {
if (!this._active) { ctx.requestPage(pageNumber).then(response => {
this._working--; if (!this._active) {
return Promise.reject(); this._working--;
} return Promise.reject();
this.totalPages = Math.ceil(response.total / response.pageSize); }
window.requestAnimationFrame(() => { this.totalPages = Math.ceil(response.total / response.pageSize);
this._renderPage( window.requestAnimationFrame(() => {
ctx, pageNumber, append, response); let pageNode = this._renderPage(
ctx, pageNumber, append, response);
this._working--;
resolve(pageNode);
});
}, response => {
this.showError(response.description);
this._working--; this._working--;
reject();
}); });
}, response => {
this.showError(response.description);
this._working--;
}); });
} }
_renderPage(ctx, pageNumber, append, response) { _renderPage(ctx, pageNumber, append, response) {
let pageNode = null;
if (response.total) { if (response.total) {
const pageNode = pageTemplate({ pageNode = pageTemplate({
page: pageNumber, page: pageNumber,
totalPages: this.totalPages, totalPages: this.totalPages,
}); });
@ -128,7 +138,7 @@ class EndlessPageView {
if (append) { if (append) {
this._pagesHolderNode.appendChild(pageNode); this._pagesHolderNode.appendChild(pageNode);
if (this._init && pageNumber !== 1) { if (!this._init && pageNumber !== 1) {
window.scroll(0, pageNode.getBoundingClientRect().top); window.scroll(0, pageNode.getBoundingClientRect().top);
} }
} else { } else {
@ -141,7 +151,9 @@ class EndlessPageView {
} else if (response.total <= (pageNumber - 1) * response.pageSize) { } else if (response.total <= (pageNumber - 1) * response.pageSize) {
this.showInfo('No data to show'); this.showInfo('No data to show');
} }
this._init = false;
this._init = true;
return pageNode;
} }
showSuccess(message) { showSuccess(message) {

View file

@ -59,7 +59,7 @@ class HelpView {
} }
views.replaceContent(this._hostNode, sourceNode); views.replaceContent(this._hostNode, sourceNode);
views.scrollToHash(); views.syncScrollPosition();
} }
} }

View file

@ -20,6 +20,7 @@ class HomeView {
const sourceNode = template(ctx); const sourceNode = template(ctx);
views.replaceContent(this._hostNode, sourceNode); views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
if (this._formNode) { if (this._formNode) {
this._tagAutoCompleteControl = new TagAutoCompleteControl( this._tagAutoCompleteControl = new TagAutoCompleteControl(

View file

@ -16,6 +16,7 @@ class LoginView extends events.EventTarget {
passwordPattern: config.passwordRegex, passwordPattern: config.passwordRegex,
canSendMails: config.canSendMails, canSendMails: config.canSendMails,
})); }));
views.syncScrollPosition();
views.decorateValidator(this._formNode); views.decorateValidator(this._formNode);
this._userNameFieldNode.setAttribute('pattern', config.userNameRegex); this._userNameFieldNode.setAttribute('pattern', config.userNameRegex);

View file

@ -107,6 +107,8 @@ class ManualPageView {
if (response.total <= (currentPage - 1) * response.pageSize) { if (response.total <= (currentPage - 1) * response.pageSize) {
this.showInfo('No data to show'); this.showInfo('No data to show');
} }
views.syncScrollPosition();
}, response => { }, response => {
this.showError(response.description); this.showError(response.description);
}); });

View file

@ -11,6 +11,7 @@ class NotFoundView {
const sourceNode = template({path: path}); const sourceNode = template({path: path});
views.replaceContent(this._hostNode, sourceNode); views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
} }
} }

View file

@ -11,8 +11,9 @@ class PasswordResetView extends events.EventTarget {
this._hostNode = document.getElementById('content-holder'); this._hostNode = document.getElementById('content-holder');
views.replaceContent(this._hostNode, template()); views.replaceContent(this._hostNode, template());
views.decorateValidator(this._formNode); views.syncScrollPosition();
views.decorateValidator(this._formNode);
this._hostNode.addEventListener('submit', e => { this._hostNode.addEventListener('submit', e => {
e.preventDefault(); e.preventDefault();
this.dispatchEvent(new CustomEvent('submit', { this.dispatchEvent(new CustomEvent('submit', {

View file

@ -23,6 +23,7 @@ class PostView {
const postContainerNode = sourceNode.querySelector('.post-container'); const postContainerNode = sourceNode.querySelector('.post-container');
const sidebarNode = sourceNode.querySelector('.sidebar'); const sidebarNode = sourceNode.querySelector('.sidebar');
views.replaceContent(this._hostNode, sourceNode); views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
const postViewNode = document.body.querySelector('.content-wrapper'); const postViewNode = document.body.querySelector('.content-wrapper');
const topNavigationNode = const topNavigationNode =

View file

@ -14,6 +14,7 @@ class RegistrationView extends events.EventTarget {
userNamePattern: config.userNameRegex, userNamePattern: config.userNameRegex,
passwordPattern: config.passwordRegex, passwordPattern: config.passwordRegex,
})); }));
views.syncScrollPosition();
views.decorateValidator(this._formNode); views.decorateValidator(this._formNode);
this._formNode.addEventListener('submit', e => this._evtSubmit(e)); this._formNode.addEventListener('submit', e => this._evtSubmit(e));
} }

View file

@ -12,8 +12,9 @@ class SettingsView extends events.EventTarget {
this._hostNode = document.getElementById('content-holder'); this._hostNode = document.getElementById('content-holder');
views.replaceContent( views.replaceContent(
this._hostNode, template({browsingSettings: ctx.settings})); this._hostNode, template({browsingSettings: ctx.settings}));
views.decorateValidator(this._formNode); views.syncScrollPosition();
views.decorateValidator(this._formNode);
this._formNode.addEventListener('submit', e => this._evtSubmit(e)); this._formNode.addEventListener('submit', e => this._evtSubmit(e));
} }

View file

@ -14,6 +14,7 @@ class TagCategoriesView extends events.EventTarget {
this._hostNode = document.getElementById('content-holder'); this._hostNode = document.getElementById('content-holder');
views.replaceContent(this._hostNode, template(ctx)); views.replaceContent(this._hostNode, template(ctx));
views.syncScrollPosition();
views.decorateValidator(this._formNode); views.decorateValidator(this._formNode);
const categoriesToAdd = Array.from(ctx.tagCategories); const categoriesToAdd = Array.from(ctx.tagCategories);

View file

@ -52,6 +52,8 @@ class TagView extends events.EventTarget {
} else { } else {
this._view = new TagSummaryView(ctx); this._view = new TagSummaryView(ctx);
} }
views.syncScrollPosition();
} }
clearMessages() { clearMessages() {

View file

@ -47,6 +47,8 @@ class UserView extends events.EventTarget {
} else { } else {
this._view = new UserSummaryView(ctx); this._view = new UserSummaryView(ctx);
} }
views.syncScrollPosition();
} }
clearMessages() { clearMessages() {