content.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Sanity-check the conversion and remove this comment.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS002: Fix invalid constructor
  6. * DS102: Remove unnecessary code created because of implicit returns
  7. * DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining
  8. * DS104: Avoid inline assignments
  9. * DS204: Change includes calls to have a more natural evaluation order
  10. * DS205: Consider reworking code to avoid use of IIFEs
  11. * DS206: Consider reworking classes to avoid initClass
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  14. */
  15. const Cls = (app.views.Content = class Content extends app.View {
  16. constructor(...args) {
  17. this.scrollToTop = this.scrollToTop.bind(this);
  18. this.scrollToBottom = this.scrollToBottom.bind(this);
  19. this.scrollStepUp = this.scrollStepUp.bind(this);
  20. this.scrollStepDown = this.scrollStepDown.bind(this);
  21. this.scrollPageUp = this.scrollPageUp.bind(this);
  22. this.scrollPageDown = this.scrollPageDown.bind(this);
  23. this.onReady = this.onReady.bind(this);
  24. this.onBootError = this.onBootError.bind(this);
  25. this.onEntryLoading = this.onEntryLoading.bind(this);
  26. this.onEntryLoaded = this.onEntryLoaded.bind(this);
  27. this.beforeRoute = this.beforeRoute.bind(this);
  28. this.afterRoute = this.afterRoute.bind(this);
  29. this.onClick = this.onClick.bind(this);
  30. this.onAltF = this.onAltF.bind(this);
  31. super(...args);
  32. }
  33. static initClass() {
  34. this.el = '._content';
  35. this.loadingClass = '_content-loading';
  36. this.events =
  37. {click: 'onClick'};
  38. this.shortcuts = {
  39. altUp: 'scrollStepUp',
  40. altDown: 'scrollStepDown',
  41. pageUp: 'scrollPageUp',
  42. pageDown: 'scrollPageDown',
  43. pageTop: 'scrollToTop',
  44. pageBottom: 'scrollToBottom',
  45. altF: 'onAltF'
  46. };
  47. this.routes = {
  48. before: 'beforeRoute',
  49. after: 'afterRoute'
  50. };
  51. }
  52. init() {
  53. this.scrollEl = app.isMobile() ?
  54. (document.scrollingElement || document.body)
  55. :
  56. this.el;
  57. this.scrollMap = {};
  58. this.scrollStack = [];
  59. this.rootPage = new app.views.RootPage;
  60. this.staticPage = new app.views.StaticPage;
  61. this.settingsPage = new app.views.SettingsPage;
  62. this.offlinePage = new app.views.OfflinePage;
  63. this.typePage = new app.views.TypePage;
  64. this.entryPage = new app.views.EntryPage;
  65. this.entryPage
  66. .on('loading', this.onEntryLoading)
  67. .on('loaded', this.onEntryLoaded);
  68. app
  69. .on('ready', this.onReady)
  70. .on('bootError', this.onBootError);
  71. }
  72. show(view) {
  73. this.hideLoading();
  74. if (view !== this.view) {
  75. if (this.view != null) {
  76. this.view.deactivate();
  77. }
  78. this.html(this.view = view);
  79. this.view.activate();
  80. }
  81. }
  82. showLoading() {
  83. this.addClass(this.constructor.loadingClass);
  84. }
  85. isLoading() {
  86. return this.el.classList.contains(this.constructor.loadingClass);
  87. }
  88. hideLoading() {
  89. this.removeClass(this.constructor.loadingClass);
  90. }
  91. scrollTo(value) {
  92. this.scrollEl.scrollTop = value || 0;
  93. }
  94. smoothScrollTo(value) {
  95. if (app.settings.get('fastScroll')) {
  96. this.scrollTo(value);
  97. } else {
  98. $.smoothScroll(this.scrollEl, value || 0);
  99. }
  100. }
  101. scrollBy(n) {
  102. this.smoothScrollTo(this.scrollEl.scrollTop + n);
  103. }
  104. scrollToTop() {
  105. this.smoothScrollTo(0);
  106. }
  107. scrollToBottom() {
  108. this.smoothScrollTo(this.scrollEl.scrollHeight);
  109. }
  110. scrollStepUp() {
  111. this.scrollBy(-80);
  112. }
  113. scrollStepDown() {
  114. this.scrollBy(80);
  115. }
  116. scrollPageUp() {
  117. this.scrollBy(40 - this.scrollEl.clientHeight);
  118. }
  119. scrollPageDown() {
  120. this.scrollBy(this.scrollEl.clientHeight - 40);
  121. }
  122. scrollToTarget() {
  123. let el;
  124. if (this.routeCtx.hash && (el = this.findTargetByHash(this.routeCtx.hash))) {
  125. $.scrollToWithImageLock(el, this.scrollEl, 'top',
  126. {margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top});
  127. $.highlight(el, {className: '_highlight'});
  128. } else {
  129. this.scrollTo(this.scrollMap[this.routeCtx.state.id]);
  130. }
  131. }
  132. onReady() {
  133. this.hideLoading();
  134. }
  135. onBootError() {
  136. this.hideLoading();
  137. this.html(this.tmpl('bootError'));
  138. }
  139. onEntryLoading() {
  140. this.showLoading();
  141. if (this.scrollToTargetTimeout) {
  142. clearTimeout(this.scrollToTargetTimeout);
  143. this.scrollToTargetTimeout = null;
  144. }
  145. }
  146. onEntryLoaded() {
  147. this.hideLoading();
  148. if (this.scrollToTargetTimeout) {
  149. clearTimeout(this.scrollToTargetTimeout);
  150. this.scrollToTargetTimeout = null;
  151. }
  152. this.scrollToTarget();
  153. }
  154. beforeRoute(context) {
  155. this.cacheScrollPosition();
  156. this.routeCtx = context;
  157. this.scrollToTargetTimeout = this.delay(this.scrollToTarget);
  158. }
  159. cacheScrollPosition() {
  160. if (!this.routeCtx || this.routeCtx.hash) { return; }
  161. if (this.routeCtx.path === '/') { return; }
  162. if (this.scrollMap[this.routeCtx.state.id] == null) {
  163. this.scrollStack.push(this.routeCtx.state.id);
  164. while (this.scrollStack.length > app.config.history_cache_size) {
  165. delete this.scrollMap[this.scrollStack.shift()];
  166. }
  167. }
  168. this.scrollMap[this.routeCtx.state.id] = this.scrollEl.scrollTop;
  169. }
  170. afterRoute(route, context) {
  171. if ((route !== 'entry') && (route !== 'type')) {
  172. resetFavicon();
  173. }
  174. switch (route) {
  175. case 'root':
  176. this.show(this.rootPage);
  177. break;
  178. case 'entry':
  179. this.show(this.entryPage);
  180. break;
  181. case 'type':
  182. this.show(this.typePage);
  183. break;
  184. case 'settings':
  185. this.show(this.settingsPage);
  186. break;
  187. case 'offline':
  188. this.show(this.offlinePage);
  189. break;
  190. default:
  191. this.show(this.staticPage);
  192. }
  193. this.view.onRoute(context);
  194. app.document.setTitle(typeof this.view.getTitle === 'function' ? this.view.getTitle() : undefined);
  195. }
  196. onClick(event) {
  197. const link = $.closestLink($.eventTarget(event), this.el);
  198. if (link && this.isExternalUrl(link.getAttribute('href'))) {
  199. $.stopEvent(event);
  200. $.popup(link);
  201. }
  202. }
  203. onAltF(event) {
  204. if (!document.activeElement || !$.hasChild(this.el, document.activeElement)) {
  205. __guard__(this.find('a:not(:empty)'), x => x.focus());
  206. return $.stopEvent(event);
  207. }
  208. }
  209. findTargetByHash(hash) {
  210. let el = (() => { try { return $.id(decodeURIComponent(hash)); } catch (error) {} })();
  211. if (!el) { el = (() => { try { return $.id(hash); } catch (error1) {} })(); }
  212. return el;
  213. }
  214. isExternalUrl(url) {
  215. let needle;
  216. return (needle = __guard__(url, x => x.slice(0, 6)), ['http:/', 'https:'].includes(needle));
  217. }
  218. });
  219. Cls.initClass();
  220. function __guard__(value, transform) {
  221. return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
  222. }