app.views.Content = class Content extends app.View { static el = "._content"; static loadingClass = "_content-loading"; static events = { click: "onClick" }; static shortcuts = { altUp: "scrollStepUp", altDown: "scrollStepDown", pageUp: "scrollPageUp", pageDown: "scrollPageDown", pageTop: "scrollToTop", pageBottom: "scrollToBottom", altF: "onAltF", }; static 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) ) { this.find("a:not(:empty)")?.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) { return url?.startsWith("http:") || url?.startsWith("https:"); }};
app.views.Content = class Content extends app.View {
static el = "._content";
static loadingClass = "_content-loading";
static events = { click: "onClick" };
static shortcuts = {
altUp: "scrollStepUp",
altDown: "scrollStepDown",
pageUp: "scrollPageUp",
pageDown: "scrollPageDown",
pageTop: "scrollToTop",
pageBottom: "scrollToBottom",
altF: "onAltF",
};
static 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)
) {
this.find("a:not(:empty)")?.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) {
return url?.startsWith("http:") || url?.startsWith("https:");
}
};