You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
devdocs/assets/javascripts/views/content/content.js

259 lines
6.7 KiB

/*
* decaffeinate suggestions:
* DS002: Fix invalid constructor
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining
* DS104: Avoid inline assignments
* DS204: Change includes calls to have a more natural evaluation order
* DS205: Consider reworking code to avoid use of IIFEs
* DS206: Consider reworking classes to avoid initClass
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
const Cls = (app.views.Content = class Content extends app.View {
constructor(...args) {
this.scrollToTop = this.scrollToTop.bind(this);
this.scrollToBottom = this.scrollToBottom.bind(this);
this.scrollStepUp = this.scrollStepUp.bind(this);
this.scrollStepDown = this.scrollStepDown.bind(this);
this.scrollPageUp = this.scrollPageUp.bind(this);
this.scrollPageDown = this.scrollPageDown.bind(this);
this.onReady = this.onReady.bind(this);
this.onBootError = this.onBootError.bind(this);
this.onEntryLoading = this.onEntryLoading.bind(this);
this.onEntryLoaded = this.onEntryLoaded.bind(this);
this.beforeRoute = this.beforeRoute.bind(this);
this.afterRoute = this.afterRoute.bind(this);
this.onClick = this.onClick.bind(this);
this.onAltF = this.onAltF.bind(this);
super(...args);
}
static initClass() {
this.el = '._content';
this.loadingClass = '_content-loading';
this.events =
{click: 'onClick'};
this.shortcuts = {
altUp: 'scrollStepUp',
altDown: 'scrollStepDown',
pageUp: 'scrollPageUp',
pageDown: 'scrollPageDown',
pageTop: 'scrollToTop',
pageBottom: 'scrollToBottom',
altF: 'onAltF'
};
this.routes = {
before: 'beforeRoute',
after: 'afterRoute'
};
}
init() {
this.scrollEl = app.isMobile() ?
(document.scrollingElement || document.body)
:
this.el;
this.scrollMap = {};
this.scrollStack = [];
this.rootPage = new app.views.RootPage;
this.staticPage = new app.views.StaticPage;
this.settingsPage = new app.views.SettingsPage;
this.offlinePage = new app.views.OfflinePage;
this.typePage = new app.views.TypePage;
this.entryPage = new app.views.EntryPage;
this.entryPage
.on('loading', this.onEntryLoading)
.on('loaded', this.onEntryLoaded);
app
.on('ready', this.onReady)
.on('bootError', this.onBootError);
}
show(view) {
this.hideLoading();
if (view !== this.view) {
if (this.view != null) {
this.view.deactivate();
}
this.html(this.view = view);
this.view.activate();
}
}
showLoading() {
this.addClass(this.constructor.loadingClass);
}
isLoading() {
return this.el.classList.contains(this.constructor.loadingClass);
}
hideLoading() {
this.removeClass(this.constructor.loadingClass);
}
scrollTo(value) {
this.scrollEl.scrollTop = value || 0;
}
smoothScrollTo(value) {
if (app.settings.get('fastScroll')) {
this.scrollTo(value);
} else {
$.smoothScroll(this.scrollEl, value || 0);
}
}
scrollBy(n) {
this.smoothScrollTo(this.scrollEl.scrollTop + n);
}
scrollToTop() {
this.smoothScrollTo(0);
}
scrollToBottom() {
this.smoothScrollTo(this.scrollEl.scrollHeight);
}
scrollStepUp() {
this.scrollBy(-80);
}
scrollStepDown() {
this.scrollBy(80);
}
scrollPageUp() {
this.scrollBy(40 - this.scrollEl.clientHeight);
}
scrollPageDown() {
this.scrollBy(this.scrollEl.clientHeight - 40);
}
scrollToTarget() {
let el;
if (this.routeCtx.hash && (el = this.findTargetByHash(this.routeCtx.hash))) {
$.scrollToWithImageLock(el, this.scrollEl, 'top',
{margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top});
$.highlight(el, {className: '_highlight'});
} else {
this.scrollTo(this.scrollMap[this.routeCtx.state.id]);
}
}
onReady() {
this.hideLoading();
}
onBootError() {
this.hideLoading();
this.html(this.tmpl('bootError'));
}
onEntryLoading() {
this.showLoading();
if (this.scrollToTargetTimeout) {
clearTimeout(this.scrollToTargetTimeout);
this.scrollToTargetTimeout = null;
}
}
onEntryLoaded() {
this.hideLoading();
if (this.scrollToTargetTimeout) {
clearTimeout(this.scrollToTargetTimeout);
this.scrollToTargetTimeout = null;
}
this.scrollToTarget();
}
beforeRoute(context) {
this.cacheScrollPosition();
this.routeCtx = context;
this.scrollToTargetTimeout = this.delay(this.scrollToTarget);
}
cacheScrollPosition() {
if (!this.routeCtx || this.routeCtx.hash) { return; }
if (this.routeCtx.path === '/') { return; }
if (this.scrollMap[this.routeCtx.state.id] == null) {
this.scrollStack.push(this.routeCtx.state.id);
while (this.scrollStack.length > app.config.history_cache_size) {
delete this.scrollMap[this.scrollStack.shift()];
}
}
this.scrollMap[this.routeCtx.state.id] = this.scrollEl.scrollTop;
}
afterRoute(route, context) {
if ((route !== 'entry') && (route !== 'type')) {
resetFavicon();
}
switch (route) {
case 'root':
this.show(this.rootPage);
break;
case 'entry':
this.show(this.entryPage);
break;
case 'type':
this.show(this.typePage);
break;
case 'settings':
this.show(this.settingsPage);
break;
case 'offline':
this.show(this.offlinePage);
break;
default:
this.show(this.staticPage);
}
this.view.onRoute(context);
app.document.setTitle(typeof this.view.getTitle === 'function' ? this.view.getTitle() : undefined);
}
onClick(event) {
const link = $.closestLink($.eventTarget(event), this.el);
if (link && this.isExternalUrl(link.getAttribute('href'))) {
$.stopEvent(event);
$.popup(link);
}
}
onAltF(event) {
if (!document.activeElement || !$.hasChild(this.el, document.activeElement)) {
__guard__(this.find('a:not(:empty)'), x => x.focus());
return $.stopEvent(event);
}
}
findTargetByHash(hash) {
let el = (() => { try { return $.id(decodeURIComponent(hash)); } catch (error) {} })();
if (!el) { el = (() => { try { return $.id(hash); } catch (error1) {} })(); }
return el;
}
isExternalUrl(url) {
let needle;
return (needle = __guard__(url, x => x.slice(0, 6)), ['http:/', 'https:'].includes(needle));
}
});
Cls.initClass();
function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
}