History

Sanity-check decaffeinate app.views.EntryPage

Simon Legner committed 2 years ago

Commit 7fa81661 parent 1995d8a1 file · +215 −234Browse files

Unified · Split

assets/javascripts/views/content/entry_page.js+215−234
@@ -1,266 +1,247 @@
1// TODO: This file was created by bulk-decaffeinate.1app.views.EntryPage = class EntryPage extends app.View {
2// Sanity-check the conversion and remove this comment.2 static className = "_page";
3/*3 static errorClass = "_page-error";
4 * decaffeinate suggestions:
5 * DS101: Remove unnecessary use of Array.from
6 * DS102: Remove unnecessary code created because of implicit returns
7 * DS205: Consider reworking code to avoid use of IIFEs
8 * DS206: Consider reworking classes to avoid initClass
9 * DS207: Consider shorter variations of null checks
10 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
11 */
12(function () {
13 let LINKS = undefined;
14 app.views.EntryPage = class EntryPage extends app.View {
15 static initClass() {
16 this.className = "_page";
17 this.errorClass = "_page-error";
18
19 this.events = { click: "onClick" };
20
21 this.shortcuts = {
22 altC: "onAltC",
23 altO: "onAltO",
24 };
25
26 this.routes = { before: "beforeRoute" };
27
28 LINKS = {
29 home: "Homepage",
30 code: "Source code",
31 };
32 }
33
34 init() {
35 this.cacheMap = {};
36 this.cacheStack = [];
37 }
38
39 deactivate() {
40 if (super.deactivate(...arguments)) {
41 this.empty();
42 this.entry = null;
43 }
44 }
45
46 loading() {
47 this.empty();
48 this.trigger("loading");
49 }
50
51 render(content, fromCache) {
52 if (content == null) {
53 content = "";
54 }
55 if (fromCache == null) {
56 fromCache = false;
57 }
58 if (!this.activated) {
59 return;
60 }
61 this.empty();
62 this.subview = new (this.subViewClass())(this.el, this.entry);
63 4
64 $.batchUpdate(this.el, () => {5 static events = { click: "onClick" };
65 this.subview.render(content, fromCache);
66 if (!fromCache) {
67 this.addCopyButtons();
68 }
69 });
70 6
71 if (app.disabledDocs.findBy("slug", this.entry.doc.slug)) {7 static shortcuts = {
72 this.hiddenView = new app.views.HiddenPage(this.el, this.entry);8 altC: "onAltC",
73 }9 altO: "onAltO",
74 10 };
75 setFaviconForDoc(this.entry.doc);
76 this.delay(this.polyfillMathML);
77 this.trigger("loaded");
78 }
79 11
80 addCopyButtons() {12 static routes = { before: "beforeRoute" };
81 if (!this.copyButton) {
82 this.copyButton = document.createElement("button");
83 this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>';
84 this.copyButton.type = "button";
85 this.copyButton.className = "_pre-clip";
86 this.copyButton.title = "Copy to clipboard";
87 this.copyButton.setAttribute("aria-label", "Copy to clipboard");
88 }
89 for (var el of Array.from(this.findAllByTag("pre"))) {
90 el.appendChild(this.copyButton.cloneNode(true));
91 }
92 }
93 13
94 polyfillMathML() {14 static LINKS = {
95 if (15 home: "Homepage",
96 window.supportsMathML !== false ||16 code: "Source code",
97 !!this.polyfilledMathML ||17 };
98 !this.findByTag("math")
99 ) {
100 return;
101 }
102 this.polyfilledMathML = true;
103 $.append(
104 document.head,
105 `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`,
106 );
107 }
108 18
109 prepareContent(content) {19 init() {
110 if (!this.entry.isIndex() || !this.entry.doc.links) {20 this.cacheMap = {};
111 return content;21 this.cacheStack = [];
112 }22 }
113 23
114 const links = (() => {24 deactivate() {
115 const result = [];25 if (super.deactivate(...arguments)) {
116 for (var link in this.entry.doc.links) {26 this.empty();
117 var url = this.entry.doc.links[link];27 this.entry = null;
118 result.push(
119 `<a href="${url}" class="_links-link">${LINKS[link]}</a>`,
120 );
121 }
122 return result;
123 })();
124
125 return `<p class="_links">${links.join("")}</p>${content}`;
126 }28 }
29 }
127 30
128 empty() {31 loading() {
129 if (this.subview != null) {32 this.empty();
130 this.subview.deactivate();33 this.trigger("loading");
131 }34 }
132 this.subview = null;
133
134 if (this.hiddenView != null) {
135 this.hiddenView.deactivate();
136 }
137 this.hiddenView = null;
138 35
139 this.resetClass();36 render(content, fromCache) {
140 super.empty(...arguments);37 if (content == null) {
38 content = "";
141 }39 }
142 40 if (fromCache == null) {
143 subViewClass() {41 fromCache = false;
144 return (
145 app.views[`${$.classify(this.entry.doc.type)}Page`] ||
146 app.views.BasePage
147 );
148 }
149
150 getTitle() {
151 return (
152 this.entry.doc.fullName +
153 (this.entry.isIndex() ? " documentation" : ` / ${this.entry.name}`)
154 );
155 }42 }
156 43 if (!this.activated) {
157 beforeRoute() {44 return;
158 this.cache();
159 this.abort();
160 }45 }
46 this.empty();
47 this.subview = new (this.subViewClass())(this.el, this.entry);
161 48
162 onRoute(context) {49 $.batchUpdate(this.el, () => {
163 const isSameFile =50 this.subview.render(content, fromCache);
164 context.entry.filePath() ===51 if (!fromCache) {
165 (this.entry != null ? this.entry.filePath() : undefined);52 this.addCopyButtons();
166 this.entry = context.entry;
167 if (!isSameFile) {
168 this.restore() || this.load();
169 }53 }
170 }54 });
171 55
172 load() {56 if (app.disabledDocs.findBy("slug", this.entry.doc.slug)) {
173 this.loading();57 this.hiddenView = new app.views.HiddenPage(this.el, this.entry);
174 this.xhr = this.entry.loadFile(
175 (response) => this.onSuccess(response),
176 () => this.onError(),
177 );
178 }58 }
179 59
180 abort() {60 setFaviconForDoc(this.entry.doc);
181 if (this.xhr) {61 this.delay(this.polyfillMathML);
182 this.xhr.abort();62 this.trigger("loaded");
183 this.xhr = this.entry = null;63 }
184 }
185 }
186 64
187 onSuccess(response) {65 addCopyButtons() {
188 if (!this.activated) {66 if (!this.copyButton) {
189 return;67 this.copyButton = document.createElement("button");
190 }68 this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>';
191 this.xhr = null;69 this.copyButton.type = "button";
192 this.render(this.prepareContent(response));70 this.copyButton.className = "_pre-clip";
71 this.copyButton.title = "Copy to clipboard";
72 this.copyButton.setAttribute("aria-label", "Copy to clipboard");
193 }73 }
194 74 for (var el of this.findAllByTag("pre")) {
195 onError() {75 el.appendChild(this.copyButton.cloneNode(true));
196 this.xhr = null;
197 this.render(this.tmpl("pageLoadError"));
198 this.resetClass();
199 this.addClass(this.constructor.errorClass);
200 if (app.serviceWorker != null) {
201 app.serviceWorker.update();
202 }
203 }76 }
77 }
204 78
205 cache() {79 polyfillMathML() {
206 let path;80 if (
207 if (81 window.supportsMathML !== false ||
208 this.xhr ||82 !!this.polyfilledMathML ||
209 !this.entry ||83 !this.findByTag("math")
210 this.cacheMap[(path = this.entry.filePath())]84 ) {
211 ) {85 return;
212 return;
213 }
214
215 this.cacheMap[path] = this.el.innerHTML;
216 this.cacheStack.push(path);
217
218 while (this.cacheStack.length > app.config.history_cache_size) {
219 delete this.cacheMap[this.cacheStack.shift()];
220 }
221 }86 }
87 this.polyfilledMathML = true;
88 $.append(
89 document.head,
90 `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`,
91 );
92 }
222 93
223 restore() {94 prepareContent(content) {
224 let path;95 if (!this.entry.isIndex() || !this.entry.doc.links) {
225 if (this.cacheMap[(path = this.entry.filePath())]) {96 return content;
226 this.render(this.cacheMap[path], true);
227 return true;
228 }
229 }97 }
230 98
231 onClick(event) {99 const links = (() => {
232 const target = $.eventTarget(event);100 const result = [];
233 if (target.hasAttribute("data-retry")) {101 for (var link in this.entry.doc.links) {
234 $.stopEvent(event);102 var url = this.entry.doc.links[link];
235 this.load();103 result.push(
236 } else if (target.classList.contains("_pre-clip")) {104 `<a href="${url}" class="_links-link">${EntryPage.LINKS[link]}</a>`,
237 $.stopEvent(event);
238 target.classList.add(
239 $.copyToClipboard(target.parentNode.textContent)
240 ? "_pre-clip-success"
241 : "_pre-clip-error",
242 );105 );
243 setTimeout(() => (target.className = "_pre-clip"), 2000);
244 }106 }
107 return result;
108 })();
109
110 return `<p class="_links">${links.join("")}</p>${content}`;
111 }
112
113 empty() {
114 if (this.subview != null) {
115 this.subview.deactivate();
116 }
117 this.subview = null;
118
119 if (this.hiddenView != null) {
120 this.hiddenView.deactivate();
121 }
122 this.hiddenView = null;
123
124 this.resetClass();
125 super.empty(...arguments);
126 }
127
128 subViewClass() {
129 return (
130 app.views[`${$.classify(this.entry.doc.type)}Page`] || app.views.BasePage
131 );
132 }
133
134 getTitle() {
135 return (
136 this.entry.doc.fullName +
137 (this.entry.isIndex() ? " documentation" : ` / ${this.entry.name}`)
138 );
139 }
140
141 beforeRoute() {
142 this.cache();
143 this.abort();
144 }
145
146 onRoute(context) {
147 const isSameFile =
148 context.entry.filePath() ===
149 (this.entry != null ? this.entry.filePath() : undefined);
150 this.entry = context.entry;
151 if (!isSameFile) {
152 this.restore() || this.load();
153 }
154 }
155
156 load() {
157 this.loading();
158 this.xhr = this.entry.loadFile(
159 (response) => this.onSuccess(response),
160 () => this.onError(),
161 );
162 }
163
164 abort() {
165 if (this.xhr) {
166 this.xhr.abort();
167 this.xhr = this.entry = null;
168 }
169 }
170
171 onSuccess(response) {
172 if (!this.activated) {
173 return;
174 }
175 this.xhr = null;
176 this.render(this.prepareContent(response));
177 }
178
179 onError() {
180 this.xhr = null;
181 this.render(this.tmpl("pageLoadError"));
182 this.resetClass();
183 this.addClass(this.constructor.errorClass);
184 if (app.serviceWorker != null) {
185 app.serviceWorker.update();
186 }
187 }
188
189 cache() {
190 let path;
191 if (
192 this.xhr ||
193 !this.entry ||
194 this.cacheMap[(path = this.entry.filePath())]
195 ) {
196 return;
197 }
198
199 this.cacheMap[path] = this.el.innerHTML;
200 this.cacheStack.push(path);
201
202 while (this.cacheStack.length > app.config.history_cache_size) {
203 delete this.cacheMap[this.cacheStack.shift()];
204 }
205 }
206
207 restore() {
208 let path;
209 if (this.cacheMap[(path = this.entry.filePath())]) {
210 this.render(this.cacheMap[path], true);
211 return true;
212 }
213 }
214
215 onClick(event) {
216 const target = $.eventTarget(event);
217 if (target.hasAttribute("data-retry")) {
218 $.stopEvent(event);
219 this.load();
220 } else if (target.classList.contains("_pre-clip")) {
221 $.stopEvent(event);
222 target.classList.add(
223 $.copyToClipboard(target.parentNode.textContent)
224 ? "_pre-clip-success"
225 : "_pre-clip-error",
226 );
227 setTimeout(() => (target.className = "_pre-clip"), 2000);
245 }228 }
229 }
246 230
247 onAltC() {231 onAltC() {
248 let link;232 let link;
249 if (!(link = this.find("._attribution:last-child ._attribution-link"))) {233 if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
250 return;234 return;
251 }
252 console.log(link.href + location.hash);
253 navigator.clipboard.writeText(link.href + location.hash);
254 }235 }
236 console.log(link.href + location.hash);
237 navigator.clipboard.writeText(link.href + location.hash);
238 }
255 239
256 onAltO() {240 onAltO() {
257 let link;241 let link;
258 if (!(link = this.find("._attribution:last-child ._attribution-link"))) {242 if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
259 return;243 return;
260 }
261 this.delay(() => $.popup(link.href + location.hash));
262 }244 }
263 };245 this.delay(() => $.popup(link.href + location.hash));
264 app.views.EntryPage.initClass();246 }
265 return app.views.EntryPage;247};
266})();