250 lines · 5.4 KB · JavaScript
RawDownload
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,      });      $.openDetailsAncestors(el);      $.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();     // If scroll position wasn't cached from an earlier visit, scroll to top.    if (!this.scrollMap[context.state.id]) {      this.scrollToTop();    }     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:");  }};