Unified · Split
| @@ -14,33 +14,41 @@ this.app = { · 13 unmodified lines | ||
| 14 | 14 | _$$: $$, |
| 15 | 15 | _page: page, |
| 16 | 16 | collections: {}, |
| 17 | − models: {}, | |
| 18 | − templates: {}, | |
| 19 | − views: {}, | |
| 17 | + models: {}, | |
| 18 | + templates: {}, | |
| 19 | + views: {}, | |
| 20 | 20 | |
| 21 | 21 | init() { |
| 22 | − try { this.initErrorTracking(); } catch (error) {} | |
| 23 | − if (!this.browserCheck()) { return; } | |
| 22 | + try { | |
| 23 | + this.initErrorTracking(); | |
| 24 | + } catch (error) {} | |
| 25 | + if (!this.browserCheck()) { | |
| 26 | + return; | |
| 27 | + } | |
| 24 | 28 | |
| 25 | − this.el = $('._app'); | |
| 26 | − this.localStorage = new LocalStorageStore; | |
| 27 | − if (app.ServiceWorker.isEnabled()) { this.serviceWorker = new app.ServiceWorker; } | |
| 28 | − this.settings = new app.Settings; | |
| 29 | + this.el = $("._app"); | |
| 30 | + this.localStorage = new LocalStorageStore(); | |
| 31 | + if (app.ServiceWorker.isEnabled()) { | |
| 32 | + this.serviceWorker = new app.ServiceWorker(); | |
| 33 | + } | |
| 34 | + this.settings = new app.Settings(); | |
| 29 | 35 | this.db = new app.DB(); |
| 30 | 36 | |
| 31 | 37 | this.settings.initLayout(); |
| 32 | 38 | |
| 33 | − this.docs = new app.collections.Docs; | |
| 34 | − this.disabledDocs = new app.collections.Docs; | |
| 35 | − this.entries = new app.collections.Entries; | |
| 39 | + this.docs = new app.collections.Docs(); | |
| 40 | + this.disabledDocs = new app.collections.Docs(); | |
| 41 | + this.entries = new app.collections.Entries(); | |
| 36 | 42 | |
| 37 | − this.router = new app.Router; | |
| 38 | − this.shortcuts = new app.Shortcuts; | |
| 39 | − this.document = new app.views.Document; | |
| 40 | − if (this.isMobile()) { this.mobile = new app.views.Mobile; } | |
| 43 | + this.router = new app.Router(); | |
| 44 | + this.shortcuts = new app.Shortcuts(); | |
| 45 | + this.document = new app.views.Document(); | |
| 46 | + if (this.isMobile()) { | |
| 47 | + this.mobile = new app.views.Mobile(); | |
| 48 | + } | |
| 41 | 49 | |
| 42 | − if (document.body.hasAttribute('data-doc')) { | |
| 43 | − this.DOC = JSON.parse(document.body.getAttribute('data-doc')); | |
| 50 | + if (document.body.hasAttribute("data-doc")) { | |
| 51 | + this.DOC = JSON.parse(document.body.getAttribute("data-doc")); | |
| 44 | 52 | this.bootOne(); |
| 45 | 53 | } else if (this.DOCS) { |
| 46 | 54 | this.bootAll(); |
| @@ -50,7 +58,9 @@ this.app = { · 3 unmodified lines | ||
| 50 | 58 | }, |
| 51 | 59 | |
| 52 | 60 | browserCheck() { |
| 53 | − if (this.isSupportedBrowser()) { return true; } | |
| 61 | + if (this.isSupportedBrowser()) { | |
| 62 | + return true; | |
| 63 | + } | |
| 54 | 64 | document.body.innerHTML = app.templates.unsupportedBrowser; |
| 55 | 65 | this.hideLoadingScreen(); |
| 56 | 66 | return false; |
| @@ -61,7 +71,7 @@ this.app = { · 4 unmodified lines | ||
| 61 | 71 | // from a domain other than our own, because things are likely to break. |
| 62 | 72 | // (e.g. cross-domain requests) |
| 63 | 73 | if (this.isInvalidLocation()) { |
| 64 | − new app.views.Notif('InvalidLocation'); | |
| 74 | + new app.views.Notif("InvalidLocation"); | |
| 65 | 75 | } else { |
| 66 | 76 | if (this.config.sentry_dsn) { |
| 67 | 77 | Raven.config(this.config.sentry_dsn, { |
| @@ -70,9 +80,12 @@ this.app = { · 2 unmodified lines | ||
| 70 | 80 | includePaths: [/devdocs/], |
| 71 | 81 | ignoreErrors: [/NPObject/, /NS_ERROR/, /^null$/, /EvalError/], |
| 72 | 82 | tags: { |
| 73 | − mode: this.isSingleDoc() ? 'single' : 'full', | |
| 83 | + mode: this.isSingleDoc() ? "single" : "full", | |
| 74 | 84 | iframe: (window.top !== window).toString(), |
| 75 | − electron: (!!__guard__(window.process != null ? window.process.versions : undefined, x => x.electron)).toString() | |
| 85 | + electron: (!!__guard__( | |
| 86 | + window.process != null ? window.process.versions : undefined, | |
| 87 | + (x) => x.electron, | |
| 88 | + )).toString(), | |
| 76 | 89 | }, |
| 77 | 90 | shouldSendCallback: () => { |
| 78 | 91 | try { |
| @@ -89,12 +102,16 @@ this.app = { · 10 unmodified lines | ||
| 89 | 102 | dataCallback(data) { |
| 90 | 103 | try { |
| 91 | 104 | $.extend(data.user || (data.user = {}), app.settings.dump()); |
| 92 | − if (data.user.docs) { data.user.docs = data.user.docs.split('/'); } | |
| 93 | − if (app.lastIDBTransaction) { data.user.lastIDBTransaction = app.lastIDBTransaction; } | |
| 105 | + if (data.user.docs) { | |
| 106 | + data.user.docs = data.user.docs.split("/"); | |
| 107 | + } | |
| 108 | + if (app.lastIDBTransaction) { | |
| 109 | + data.user.lastIDBTransaction = app.lastIDBTransaction; | |
| 110 | + } | |
| 94 | 111 | data.tags.scriptCount = document.scripts.length; |
| 95 | 112 | } catch (error) {} |
| 96 | 113 | return data; |
| 97 | − } | |
| 114 | + }, | |
| 98 | 115 | }).install(); |
| 99 | 116 | } |
| 100 | 117 | this.previousErrorHandler = onerror; |
| @@ -106,8 +123,10 @@ this.app = { · 5 unmodified lines | ||
| 106 | 123 | bootOne() { |
| 107 | 124 | this.doc = new app.models.Doc(this.DOC); |
| 108 | 125 | this.docs.reset([this.doc]); |
| 109 | − this.doc.load(this.start.bind(this), this.onBootError.bind(this), {readCache: true}); | |
| 110 | − new app.views.Notice('singleDoc', this.doc); | |
| 126 | + this.doc.load(this.start.bind(this), this.onBootError.bind(this), { | |
| 127 | + readCache: true, | |
| 128 | + }); | |
| 129 | + new app.views.Notice("singleDoc", this.doc); | |
| 111 | 130 | delete this.DOC; |
| 112 | 131 | }, |
| 113 | 132 | |
| @@ -117,40 +136,61 @@ this.app = { · 3 unmodified lines | ||
| 117 | 136 | (docs.indexOf(doc.slug) >= 0 ? this.docs : this.disabledDocs).add(doc); |
| 118 | 137 | } |
| 119 | 138 | this.migrateDocs(); |
| 120 | − this.docs.load(this.start.bind(this), this.onBootError.bind(this), {readCache: true, writeCache: true}); | |
| 139 | + this.docs.load(this.start.bind(this), this.onBootError.bind(this), { | |
| 140 | + readCache: true, | |
| 141 | + writeCache: true, | |
| 142 | + }); | |
| 121 | 143 | delete this.DOCS; |
| 122 | 144 | }, |
| 123 | 145 | |
| 124 | 146 | start() { |
| 125 | 147 | let doc; |
| 126 | − for (doc of Array.from(this.docs.all())) { this.entries.add(doc.toEntry()); } | |
| 127 | − for (doc of Array.from(this.disabledDocs.all())) { this.entries.add(doc.toEntry()); } | |
| 128 | − for (doc of Array.from(this.docs.all())) { this.initDoc(doc); } | |
| 129 | − this.trigger('ready'); | |
| 148 | + for (doc of Array.from(this.docs.all())) { | |
| 149 | + this.entries.add(doc.toEntry()); | |
| 150 | + } | |
| 151 | + for (doc of Array.from(this.disabledDocs.all())) { | |
| 152 | + this.entries.add(doc.toEntry()); | |
| 153 | + } | |
| 154 | + for (doc of Array.from(this.docs.all())) { | |
| 155 | + this.initDoc(doc); | |
| 156 | + } | |
| 157 | + this.trigger("ready"); | |
| 130 | 158 | this.router.start(); |
| 131 | 159 | this.hideLoadingScreen(); |
| 132 | 160 | setTimeout(() => { |
| 133 | − if (!this.doc) { this.welcomeBack(); } | |
| 134 | − return this.removeEvent('ready bootError'); | |
| 135 | − } | |
| 136 | − , 50); | |
| 161 | + if (!this.doc) { | |
| 162 | + this.welcomeBack(); | |
| 163 | + } | |
| 164 | + return this.removeEvent("ready bootError"); | |
| 165 | + }, 50); | |
| 137 | 166 | }, |
| 138 | 167 | |
| 139 | 168 | initDoc(doc) { |
| 140 | − for (var type of Array.from(doc.types.all())) { doc.entries.add(type.toEntry()); } | |
| 169 | + for (var type of Array.from(doc.types.all())) { | |
| 170 | + doc.entries.add(type.toEntry()); | |
| 171 | + } | |
| 141 | 172 | this.entries.add(doc.entries.all()); |
| 142 | 173 | }, |
| 143 | 174 | |
| 144 | 175 | migrateDocs() { |
| 145 | 176 | let needsSaving; |
| 146 | 177 | for (var slug of Array.from(this.settings.getDocs())) { |
| 147 | − if (!this.docs.findBy('slug', slug)) {var doc; | |
| 148 | − | |
| 178 | + if (!this.docs.findBy("slug", slug)) { | |
| 179 | + var doc; | |
| 180 | + | |
| 149 | 181 | needsSaving = true; |
| 150 | − if (slug === 'webpack~2') { doc = this.disabledDocs.findBy('slug', 'webpack'); } | |
| 151 | − if (slug === 'angular~4_typescript') { doc = this.disabledDocs.findBy('slug', 'angular'); } | |
| 152 | − if (slug === 'angular~2_typescript') { doc = this.disabledDocs.findBy('slug', 'angular~2'); } | |
| 153 | − if (!doc) { doc = this.disabledDocs.findBy('slug_without_version', slug); } | |
| 182 | + if (slug === "webpack~2") { | |
| 183 | + doc = this.disabledDocs.findBy("slug", "webpack"); | |
| 184 | + } | |
| 185 | + if (slug === "angular~4_typescript") { | |
| 186 | + doc = this.disabledDocs.findBy("slug", "angular"); | |
| 187 | + } | |
| 188 | + if (slug === "angular~2_typescript") { | |
| 189 | + doc = this.disabledDocs.findBy("slug", "angular~2"); | |
| 190 | + } | |
| 191 | + if (!doc) { | |
| 192 | + doc = this.disabledDocs.findBy("slug_without_version", slug); | |
| 193 | + } | |
| 154 | 194 | if (doc) { |
| 155 | 195 | this.disabledDocs.remove(doc); |
| 156 | 196 | this.docs.add(doc); |
| @@ -158,56 +198,70 @@ this.app = { · 1 unmodified line | ||
| 158 | 198 | } |
| 159 | 199 | } |
| 160 | 200 | |
| 161 | − if (needsSaving) { this.saveDocs(); } | |
| 201 | + if (needsSaving) { | |
| 202 | + this.saveDocs(); | |
| 203 | + } | |
| 162 | 204 | }, |
| 163 | 205 | |
| 164 | 206 | enableDoc(doc, _onSuccess, onError) { |
| 165 | − if (this.docs.contains(doc)) { return; } | |
| 207 | + if (this.docs.contains(doc)) { | |
| 208 | + return; | |
| 209 | + } | |
| 166 | 210 | |
| 167 | 211 | const onSuccess = () => { |
| 168 | − if (this.docs.contains(doc)) { return; } | |
| 212 | + if (this.docs.contains(doc)) { | |
| 213 | + return; | |
| 214 | + } | |
| 169 | 215 | this.disabledDocs.remove(doc); |
| 170 | 216 | this.docs.add(doc); |
| 171 | 217 | this.docs.sort(); |
| 172 | 218 | this.initDoc(doc); |
| 173 | 219 | this.saveDocs(); |
| 174 | − if (app.settings.get('autoInstall')) { | |
| 220 | + if (app.settings.get("autoInstall")) { | |
| 175 | 221 | doc.install(_onSuccess, onError); |
| 176 | 222 | } else { |
| 177 | 223 | _onSuccess(); |
| 178 | 224 | } |
| 179 | 225 | }; |
| 180 | 226 | |
| 181 | − doc.load(onSuccess, onError, {writeCache: true}); | |
| 227 | + doc.load(onSuccess, onError, { writeCache: true }); | |
| 182 | 228 | }, |
| 183 | 229 | |
| 184 | 230 | saveDocs() { |
| 185 | 231 | this.settings.setDocs(Array.from(this.docs.all()).map((doc) => doc.slug)); |
| 186 | 232 | this.db.migrate(); |
| 187 | − return (this.serviceWorker != null ? this.serviceWorker.updateInBackground() : undefined); | |
| 233 | + return this.serviceWorker != null | |
| 234 | + ? this.serviceWorker.updateInBackground() | |
| 235 | + : undefined; | |
| 188 | 236 | }, |
| 189 | 237 | |
| 190 | 238 | welcomeBack() { |
| 191 | − let visitCount = this.settings.get('count'); | |
| 192 | − this.settings.set('count', ++visitCount); | |
| 193 | − if (visitCount === 5) { new app.views.Notif('Share', {autoHide: null}); } | |
| 239 | + let visitCount = this.settings.get("count"); | |
| 240 | + this.settings.set("count", ++visitCount); | |
| 241 | + if (visitCount === 5) { | |
| 242 | + new app.views.Notif("Share", { autoHide: null }); | |
| 243 | + } | |
| 194 | 244 | new app.views.News(); |
| 195 | 245 | new app.views.Updates(); |
| 196 | − return this.updateChecker = new app.UpdateChecker(); | |
| 246 | + return (this.updateChecker = new app.UpdateChecker()); | |
| 197 | 247 | }, |
| 198 | 248 | |
| 199 | 249 | reboot() { |
| 200 | − if ((location.pathname !== '/') && (location.pathname !== '/settings')) { | |
| 250 | + if (location.pathname !== "/" && location.pathname !== "/settings") { | |
| 201 | 251 | window.location = `/#${location.pathname}`; |
| 202 | 252 | } else { |
| 203 | − window.location = '/'; | |
| 253 | + window.location = "/"; | |
| 204 | 254 | } |
| 205 | 255 | }, |
| 206 | 256 | |
| 207 | 257 | reload() { |
| 208 | 258 | this.docs.clearCache(); |
| 209 | 259 | this.disabledDocs.clearCache(); |
| 210 | − if (this.serviceWorker) { this.serviceWorker.reload(); } else { this.reboot(); } | |
| 260 | + if (this.serviceWorker) { | |
| 261 | + this.serviceWorker.reload(); | |
| 262 | + } else { | |
| 263 | + this.reboot(); | |
| 264 | + } | |
| 211 | 265 | }, |
| 212 | 266 | |
| 213 | 267 | reset() { |
| @@ -219,11 +273,13 @@ this.app = { · 5 unmodified lines | ||
| 219 | 273 | if (this.serviceWorker != null) { |
| 220 | 274 | this.serviceWorker.update(); |
| 221 | 275 | } |
| 222 | − window.location = '/'; | |
| 276 | + window.location = "/"; | |
| 223 | 277 | }, |
| 224 | 278 | |
| 225 | 279 | showTip(tip) { |
| 226 | − if (this.isSingleDoc()) { return; } | |
| 280 | + if (this.isSingleDoc()) { | |
| 281 | + return; | |
| 282 | + } | |
| 227 | 283 | const tips = this.settings.getTips(); |
| 228 | 284 | if (tips.indexOf(tip) === -1) { |
| 229 | 285 | tips.push(tip); |
| @@ -233,44 +289,61 @@ this.app = { · 3 unmodified lines | ||
| 233 | 289 | }, |
| 234 | 290 | |
| 235 | 291 | hideLoadingScreen() { |
| 236 | − if ($.overlayScrollbarsEnabled()) { document.body.classList.add('_overlay-scrollbars'); } | |
| 237 | − document.documentElement.classList.remove('_booting'); | |
| 292 | + if ($.overlayScrollbarsEnabled()) { | |
| 293 | + document.body.classList.add("_overlay-scrollbars"); | |
| 294 | + } | |
| 295 | + document.documentElement.classList.remove("_booting"); | |
| 238 | 296 | }, |
| 239 | 297 | |
| 240 | 298 | indexHost() { |
| 241 | 299 | // Can't load the index files from the host/CDN when service worker is |
| 242 | 300 | // enabled because it doesn't support caching URLs that use CORS. |
| 243 | − return this.config[this.serviceWorker && this.settings.hasDocs() ? 'index_path' : 'docs_origin']; | |
| 301 | + return this.config[ | |
| 302 | + this.serviceWorker && this.settings.hasDocs() | |
| 303 | + ? "index_path" | |
| 304 | + : "docs_origin" | |
| 305 | + ]; | |
| 244 | 306 | }, |
| 245 | 307 | |
| 246 | 308 | onBootError(...args) { |
| 247 | − this.trigger('bootError'); | |
| 309 | + this.trigger("bootError"); | |
| 248 | 310 | this.hideLoadingScreen(); |
| 249 | 311 | }, |
| 250 | 312 | |
| 251 | 313 | onQuotaExceeded() { |
| 252 | − if (this.quotaExceeded) { return; } | |
| 314 | + if (this.quotaExceeded) { | |
| 315 | + return; | |
| 316 | + } | |
| 253 | 317 | this.quotaExceeded = true; |
| 254 | − new app.views.Notif('QuotaExceeded', {autoHide: null}); | |
| 318 | + new app.views.Notif("QuotaExceeded", { autoHide: null }); | |
| 255 | 319 | }, |
| 256 | 320 | |
| 257 | 321 | onCookieBlocked(key, value, actual) { |
| 258 | − if (this.cookieBlocked) { return; } | |
| 322 | + if (this.cookieBlocked) { | |
| 323 | + return; | |
| 324 | + } | |
| 259 | 325 | this.cookieBlocked = true; |
| 260 | − new app.views.Notif('CookieBlocked', {autoHide: null}); | |
| 261 | − Raven.captureMessage(`CookieBlocked/${key}`, {level: 'warning', extra: {value, actual}}); | |
| 326 | + new app.views.Notif("CookieBlocked", { autoHide: null }); | |
| 327 | + Raven.captureMessage(`CookieBlocked/${key}`, { | |
| 328 | + level: "warning", | |
| 329 | + extra: { value, actual }, | |
| 330 | + }); | |
| 262 | 331 | }, |
| 263 | 332 | |
| 264 | 333 | onWindowError(...args) { |
| 265 | − if (this.cookieBlocked) { return; } | |
| 334 | + if (this.cookieBlocked) { | |
| 335 | + return; | |
| 336 | + } | |
| 266 | 337 | if (this.isInjectionError(...Array.from(args || []))) { |
| 267 | 338 | this.onInjectionError(); |
| 268 | 339 | } else if (this.isAppError(...Array.from(args || []))) { |
| 269 | − if (typeof this.previousErrorHandler === 'function') { | |
| 340 | + if (typeof this.previousErrorHandler === "function") { | |
| 270 | 341 | this.previousErrorHandler(...Array.from(args || [])); |
| 271 | 342 | } |
| 272 | 343 | this.hideLoadingScreen(); |
| 273 | − if (!this.errorNotif) { this.errorNotif = new app.views.Notif('Error'); } | |
| 344 | + if (!this.errorNotif) { | |
| 345 | + this.errorNotif = new app.views.Notif("Error"); | |
| 346 | + } | |
| 274 | 347 | this.errorNotif.show(); |
| 275 | 348 | } |
| 276 | 349 | }, |
| @@ -280,75 +353,103 @@ this.app = { · 3 unmodified lines | ||
| 280 | 353 | this.injectionError = true; |
| 281 | 354 | alert(`\ |
| 282 | 355 | JavaScript code has been injected in the page which prevents DevDocs from running correctly. |
| 283 | −Please check your browser extensions/addons. ` | |
| 284 | − ); | |
| 285 | − Raven.captureMessage('injection error', {level: 'info'}); | |
| 356 | +Please check your browser extensions/addons. `); | |
| 357 | + Raven.captureMessage("injection error", { level: "info" }); | |
| 286 | 358 | } |
| 287 | 359 | }, |
| 288 | 360 | |
| 289 | 361 | isInjectionError() { |
| 290 | 362 | // Some browser extensions expect the entire web to use jQuery. |
| 291 | 363 | // I gave up trying to fight back. |
| 292 | − return (window.$ !== app._$) || (window.$$ !== app._$$) || (window.page !== app._page) || (typeof $.empty !== 'function') || (typeof page.show !== 'function'); | |
| 364 | + return ( | |
| 365 | + window.$ !== app._$ || | |
| 366 | + window.$$ !== app._$$ || | |
| 367 | + window.page !== app._page || | |
| 368 | + typeof $.empty !== "function" || | |
| 369 | + typeof page.show !== "function" | |
| 370 | + ); | |
| 293 | 371 | }, |
| 294 | 372 | |
| 295 | 373 | isAppError(error, file) { |
| 296 | 374 | // Ignore errors from external scripts. |
| 297 | − return file && (file.indexOf('devdocs') !== -1) && (file.indexOf('.js') === (file.length - 3)); | |
| 375 | + return ( | |
| 376 | + file && | |
| 377 | + file.indexOf("devdocs") !== -1 && | |
| 378 | + file.indexOf(".js") === file.length - 3 | |
| 379 | + ); | |
| 298 | 380 | }, |
| 299 | 381 | |
| 300 | 382 | isSupportedBrowser() { |
| 301 | 383 | try { |
| 302 | 384 | const features = { |
| 303 | − bind: !!Function.prototype.bind, | |
| 304 | − pushState: !!history.pushState, | |
| 305 | − matchMedia: !!window.matchMedia, | |
| 385 | + bind: !!Function.prototype.bind, | |
| 386 | + pushState: !!history.pushState, | |
| 387 | + matchMedia: !!window.matchMedia, | |
| 306 | 388 | insertAdjacentHTML: !!document.body.insertAdjacentHTML, |
| 307 | − defaultPrevented: document.createEvent('CustomEvent').defaultPrevented === false, | |
| 308 | − cssVariables: !!__guardMethod__(CSS, 'supports', o => o.supports('(--t: 0)')) | |
| 389 | + defaultPrevented: | |
| 390 | + document.createEvent("CustomEvent").defaultPrevented === false, | |
| 391 | + cssVariables: !!__guardMethod__(CSS, "supports", (o) => | |
| 392 | + o.supports("(--t: 0)"), | |
| 393 | + ), | |
| 309 | 394 | }; |
| 310 | 395 | |
| 311 | 396 | for (var key in features) { |
| 312 | 397 | var value = features[key]; |
| 313 | 398 | if (!value) { |
| 314 | − Raven.captureMessage(`unsupported/${key}`, {level: 'info'}); | |
| 399 | + Raven.captureMessage(`unsupported/${key}`, { level: "info" }); | |
| 315 | 400 | return false; |
| 316 | 401 | } |
| 317 | 402 | } |
| 318 | 403 | |
| 319 | 404 | return true; |
| 320 | 405 | } catch (error) { |
| 321 | − Raven.captureMessage('unsupported/exception', {level: 'info', extra: { error }}); | |
| 406 | + Raven.captureMessage("unsupported/exception", { | |
| 407 | + level: "info", | |
| 408 | + extra: { error }, | |
| 409 | + }); | |
| 322 | 410 | return false; |
| 323 | 411 | } |
| 324 | 412 | }, |
| 325 | 413 | |
| 326 | 414 | isSingleDoc() { |
| 327 | − return document.body.hasAttribute('data-doc'); | |
| 415 | + return document.body.hasAttribute("data-doc"); | |
| 328 | 416 | }, |
| 329 | 417 | |
| 330 | 418 | isMobile() { |
| 331 | − return this._isMobile != null ? this._isMobile : (this._isMobile = app.views.Mobile.detect()); | |
| 419 | + return this._isMobile != null | |
| 420 | + ? this._isMobile | |
| 421 | + : (this._isMobile = app.views.Mobile.detect()); | |
| 332 | 422 | }, |
| 333 | 423 | |
| 334 | 424 | isAndroidWebview() { |
| 335 | − return this._isAndroidWebview != null ? this._isAndroidWebview : (this._isAndroidWebview = app.views.Mobile.detectAndroidWebview()); | |
| 425 | + return this._isAndroidWebview != null | |
| 426 | + ? this._isAndroidWebview | |
| 427 | + : (this._isAndroidWebview = app.views.Mobile.detectAndroidWebview()); | |
| 336 | 428 | }, |
| 337 | 429 | |
| 338 | 430 | isInvalidLocation() { |
| 339 | − return (this.config.env === 'production') && (location.host.indexOf(app.config.production_host) !== 0); | |
| 340 | − } | |
| 431 | + return ( | |
| 432 | + this.config.env === "production" && | |
| 433 | + location.host.indexOf(app.config.production_host) !== 0 | |
| 434 | + ); | |
| 435 | + }, | |
| 341 | 436 | }; |
| 342 | 437 | |
| 343 | 438 | $.extend(app, Events); |
| 344 | 439 | |
| 345 | 440 | function __guard__(value, transform) { |
| 346 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 441 | + return typeof value !== "undefined" && value !== null | |
| 442 | + ? transform(value) | |
| 443 | + : undefined; | |
| 347 | 444 | } |
| 348 | 445 | function __guardMethod__(obj, methodName, transform) { |
| 349 | − if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { | |
| 446 | + if ( | |
| 447 | + typeof obj !== "undefined" && | |
| 448 | + obj !== null && | |
| 449 | + typeof obj[methodName] === "function" | |
| 450 | + ) { | |
| 350 | 451 | return transform(obj, methodName); |
| 351 | 452 | } else { |
| 352 | 453 | return undefined; |
| 353 | 454 | } |
| 354 | −} | |
| 455 | +} | |
| @@ -9,12 +9,12 @@ · 8 unmodified lines | ||
| 9 | 9 | * DS207: Consider shorter variations of null checks |
| 10 | 10 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 11 | 11 | */ |
| 12 | −(function() { | |
| 12 | +(function () { | |
| 13 | 13 | let NAME = undefined; |
| 14 | 14 | let VERSION = undefined; |
| 15 | 15 | const Cls = (app.DB = class DB { |
| 16 | 16 | static initClass() { |
| 17 | − NAME = 'docs'; | |
| 17 | + NAME = "docs"; | |
| 18 | 18 | VERSION = 15; |
| 19 | 19 | } |
| 20 | 20 | |
| @@ -29,18 +29,27 @@ · 8 unmodified lines | ||
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | db(fn) { |
| 32 | − if (!this.useIndexedDB) { return fn(); } | |
| 33 | − if (fn) { this.callbacks.push(fn); } | |
| 34 | − if (this.open) { return; } | |
| 32 | + if (!this.useIndexedDB) { | |
| 33 | + return fn(); | |
| 34 | + } | |
| 35 | + if (fn) { | |
| 36 | + this.callbacks.push(fn); | |
| 37 | + } | |
| 38 | + if (this.open) { | |
| 39 | + return; | |
| 40 | + } | |
| 35 | 41 | |
| 36 | 42 | try { |
| 37 | 43 | this.open = true; |
| 38 | − const req = indexedDB.open(NAME, (VERSION * this.versionMultipler) + this.userVersion()); | |
| 44 | + const req = indexedDB.open( | |
| 45 | + NAME, | |
| 46 | + VERSION * this.versionMultipler + this.userVersion(), | |
| 47 | + ); | |
| 39 | 48 | req.onsuccess = this.onOpenSuccess; |
| 40 | 49 | req.onerror = this.onOpenError; |
| 41 | 50 | req.onupgradeneeded = this.onUpgradeNeeded; |
| 42 | 51 | } catch (error) { |
| 43 | − this.fail('exception', error); | |
| 52 | + this.fail("exception", error); | |
| 44 | 53 | } |
| 45 | 54 | } |
| 46 | 55 | |
| @@ -49,13 +58,17 @@ · 2 unmodified lines | ||
| 49 | 58 | const db = event.target.result; |
| 50 | 59 | |
| 51 | 60 | if (db.objectStoreNames.length === 0) { |
| 52 | − try { db.close(); } catch (error1) {} | |
| 61 | + try { | |
| 62 | + db.close(); | |
| 63 | + } catch (error1) {} | |
| 53 | 64 | this.open = false; |
| 54 | − this.fail('empty'); | |
| 55 | − } else if (error = this.buggyIDB(db)) { | |
| 56 | − try { db.close(); } catch (error2) {} | |
| 65 | + this.fail("empty"); | |
| 66 | + } else if ((error = this.buggyIDB(db))) { | |
| 67 | + try { | |
| 68 | + db.close(); | |
| 69 | + } catch (error2) {} | |
| 57 | 70 | this.open = false; |
| 58 | − this.fail('buggy', error); | |
| 71 | + this.fail("buggy", error); | |
| 59 | 72 | } else { |
| 60 | 73 | this.runCallbacks(db); |
| 61 | 74 | this.open = false; |
| @@ -66,36 +79,43 @@ · 4 unmodified lines | ||
| 66 | 79 | onOpenError(event) { |
| 67 | 80 | event.preventDefault(); |
| 68 | 81 | this.open = false; |
| 69 | − const { | |
| 70 | − error | |
| 71 | − } = event.target; | |
| 82 | + const { error } = event.target; | |
| 72 | 83 | |
| 73 | 84 | switch (error.name) { |
| 74 | − case 'QuotaExceededError': | |
| 85 | + case "QuotaExceededError": | |
| 75 | 86 | this.onQuotaExceededError(); |
| 76 | 87 | break; |
| 77 | − case 'VersionError': | |
| 88 | + case "VersionError": | |
| 78 | 89 | this.onVersionError(); |
| 79 | 90 | break; |
| 80 | − case 'InvalidStateError': | |
| 81 | − this.fail('private_mode'); | |
| 91 | + case "InvalidStateError": | |
| 92 | + this.fail("private_mode"); | |
| 82 | 93 | break; |
| 83 | 94 | default: |
| 84 | − this.fail('cant_open', error); | |
| 95 | + this.fail("cant_open", error); | |
| 85 | 96 | } |
| 86 | 97 | } |
| 87 | 98 | |
| 88 | 99 | fail(reason, error) { |
| 89 | 100 | this.cachedDocs = null; |
| 90 | 101 | this.useIndexedDB = false; |
| 91 | − if (!this.reason) { this.reason = reason; } | |
| 92 | − if (!this.error) { this.error = error; } | |
| 93 | − if (error) { if (typeof console.error === 'function') { | |
| 94 | − console.error('IDB error', error); | |
| 95 | − } } | |
| 102 | + if (!this.reason) { | |
| 103 | + this.reason = reason; | |
| 104 | + } | |
| 105 | + if (!this.error) { | |
| 106 | + this.error = error; | |
| 107 | + } | |
| 108 | + if (error) { | |
| 109 | + if (typeof console.error === "function") { | |
| 110 | + console.error("IDB error", error); | |
| 111 | + } | |
| 112 | + } | |
| 96 | 113 | this.runCallbacks(); |
| 97 | − if (error && (reason === 'cant_open')) { | |
| 98 | − Raven.captureMessage(`${error.name}: ${error.message}`, {level: 'warning', fingerprint: [error.name]}); | |
| 114 | + if (error && reason === "cant_open") { | |
| 115 | + Raven.captureMessage(`${error.name}: ${error.message}`, { | |
| 116 | + level: "warning", | |
| 117 | + fingerprint: [error.name], | |
| 118 | + }); | |
| 99 | 119 | } |
| 100 | 120 | } |
| 101 | 121 | |
| @@ -103,34 +123,39 @@ · 1 unmodified line | ||
| 103 | 123 | this.reset(); |
| 104 | 124 | this.db(); |
| 105 | 125 | app.onQuotaExceeded(); |
| 106 | − Raven.captureMessage('QuotaExceededError', {level: 'warning'}); | |
| 126 | + Raven.captureMessage("QuotaExceededError", { level: "warning" }); | |
| 107 | 127 | } |
| 108 | 128 | |
| 109 | 129 | onVersionError() { |
| 110 | 130 | const req = indexedDB.open(NAME); |
| 111 | − req.onsuccess = event => { | |
| 131 | + req.onsuccess = (event) => { | |
| 112 | 132 | return this.handleVersionMismatch(event.target.result.version); |
| 113 | 133 | }; |
| 114 | − req.onerror = function(event) { | |
| 134 | + req.onerror = function (event) { | |
| 115 | 135 | event.preventDefault(); |
| 116 | − return this.fail('cant_open', error); | |
| 136 | + return this.fail("cant_open", error); | |
| 117 | 137 | }; |
| 118 | 138 | } |
| 119 | 139 | |
| 120 | 140 | handleVersionMismatch(actualVersion) { |
| 121 | 141 | if (Math.floor(actualVersion / this.versionMultipler) !== VERSION) { |
| 122 | − this.fail('version'); | |
| 142 | + this.fail("version"); | |
| 123 | 143 | } else { |
| 124 | − this.setUserVersion(actualVersion - (VERSION * this.versionMultipler)); | |
| 144 | + this.setUserVersion(actualVersion - VERSION * this.versionMultipler); | |
| 125 | 145 | this.db(); |
| 126 | 146 | } |
| 127 | 147 | } |
| 128 | 148 | |
| 129 | 149 | buggyIDB(db) { |
| 130 | − if (this.checkedBuggyIDB) { return; } | |
| 150 | + if (this.checkedBuggyIDB) { | |
| 151 | + return; | |
| 152 | + } | |
| 131 | 153 | this.checkedBuggyIDB = true; |
| 132 | 154 | try { |
| 133 | − this.idbTransaction(db, {stores: $.makeArray(db.objectStoreNames).slice(0, 2), mode: 'readwrite'}).abort(); // https://bugs.webkit.org/show_bug.cgi?id=136937 | |
| 155 | + this.idbTransaction(db, { | |
| 156 | + stores: $.makeArray(db.objectStoreNames).slice(0, 2), | |
| 157 | + mode: "readwrite", | |
| 158 | + }).abort(); // https://bugs.webkit.org/show_bug.cgi?id=136937 | |
| 134 | 159 | return; |
| 135 | 160 | } catch (error) { |
| 136 | 161 | return error; |
| @@ -139,53 +164,72 @@ · 2 unmodified lines | ||
| 139 | 164 | |
| 140 | 165 | runCallbacks(db) { |
| 141 | 166 | let fn; |
| 142 | − while ((fn = this.callbacks.shift())) { fn(db); } | |
| 167 | + while ((fn = this.callbacks.shift())) { | |
| 168 | + fn(db); | |
| 169 | + } | |
| 143 | 170 | } |
| 144 | 171 | |
| 145 | 172 | onUpgradeNeeded(event) { |
| 146 | 173 | let db; |
| 147 | − if (!(db = event.target.result)) { return; } | |
| 174 | + if (!(db = event.target.result)) { | |
| 175 | + return; | |
| 176 | + } | |
| 148 | 177 | |
| 149 | 178 | const objectStoreNames = $.makeArray(db.objectStoreNames); |
| 150 | 179 | |
| 151 | − if (!$.arrayDelete(objectStoreNames, 'docs')) { | |
| 152 | − try { db.createObjectStore('docs'); } catch (error) {} | |
| 180 | + if (!$.arrayDelete(objectStoreNames, "docs")) { | |
| 181 | + try { | |
| 182 | + db.createObjectStore("docs"); | |
| 183 | + } catch (error) {} | |
| 153 | 184 | } |
| 154 | 185 | |
| 155 | 186 | for (var doc of Array.from(app.docs.all())) { |
| 156 | 187 | if (!$.arrayDelete(objectStoreNames, doc.slug)) { |
| 157 | − try { db.createObjectStore(doc.slug); } catch (error1) {} | |
| 188 | + try { | |
| 189 | + db.createObjectStore(doc.slug); | |
| 190 | + } catch (error1) {} | |
| 158 | 191 | } |
| 159 | 192 | } |
| 160 | 193 | |
| 161 | 194 | for (var name of Array.from(objectStoreNames)) { |
| 162 | − try { db.deleteObjectStore(name); } catch (error2) {} | |
| 195 | + try { | |
| 196 | + db.deleteObjectStore(name); | |
| 197 | + } catch (error2) {} | |
| 163 | 198 | } |
| 164 | 199 | } |
| 165 | 200 | |
| 166 | 201 | store(doc, data, onSuccess, onError, _retry) { |
| 167 | − if (_retry == null) { _retry = true; } | |
| 168 | − this.db(db => { | |
| 202 | + if (_retry == null) { | |
| 203 | + _retry = true; | |
| 204 | + } | |
| 205 | + this.db((db) => { | |
| 169 | 206 | if (!db) { |
| 170 | 207 | onError(); |
| 171 | 208 | return; |
| 172 | 209 | } |
| 173 | 210 | |
| 174 | − const txn = this.idbTransaction(db, {stores: ['docs', doc.slug], mode: 'readwrite', ignoreError: false}); | |
| 211 | + const txn = this.idbTransaction(db, { | |
| 212 | + stores: ["docs", doc.slug], | |
| 213 | + mode: "readwrite", | |
| 214 | + ignoreError: false, | |
| 215 | + }); | |
| 175 | 216 | txn.oncomplete = () => { |
| 176 | 217 | if (this.cachedDocs != null) { |
| 177 | 218 | this.cachedDocs[doc.slug] = doc.mtime; |
| 178 | 219 | } |
| 179 | 220 | onSuccess(); |
| 180 | 221 | }; |
| 181 | − txn.onerror = event => { | |
| 222 | + txn.onerror = (event) => { | |
| 182 | 223 | event.preventDefault(); |
| 183 | − if (((txn.error != null ? txn.error.name : undefined) === 'NotFoundError') && _retry) { | |
| 224 | + if ( | |
| 225 | + (txn.error != null ? txn.error.name : undefined) === | |
| 226 | + "NotFoundError" && | |
| 227 | + _retry | |
| 228 | + ) { | |
| 184 | 229 | this.migrate(); |
| 185 | 230 | setTimeout(() => { |
| 186 | 231 | return this.store(doc, data, onSuccess, onError, false); |
| 187 | − } | |
| 188 | − , 0); | |
| 232 | + }, 0); | |
| 189 | 233 | } else { |
| 190 | 234 | onError(event); |
| 191 | 235 | } |
| @@ -193,42 +237,54 @@ · 1 unmodified line | ||
| 193 | 237 | |
| 194 | 238 | let store = txn.objectStore(doc.slug); |
| 195 | 239 | store.clear(); |
| 196 | − for (var path in data) { var content = data[path]; store.add(content, path); } | |
| 240 | + for (var path in data) { | |
| 241 | + var content = data[path]; | |
| 242 | + store.add(content, path); | |
| 243 | + } | |
| 197 | 244 | |
| 198 | − store = txn.objectStore('docs'); | |
| 245 | + store = txn.objectStore("docs"); | |
| 199 | 246 | store.put(doc.mtime, doc.slug); |
| 200 | 247 | }); |
| 201 | 248 | } |
| 202 | 249 | |
| 203 | 250 | unstore(doc, onSuccess, onError, _retry) { |
| 204 | − if (_retry == null) { _retry = true; } | |
| 205 | − this.db(db => { | |
| 251 | + if (_retry == null) { | |
| 252 | + _retry = true; | |
| 253 | + } | |
| 254 | + this.db((db) => { | |
| 206 | 255 | if (!db) { |
| 207 | 256 | onError(); |
| 208 | 257 | return; |
| 209 | 258 | } |
| 210 | 259 | |
| 211 | − const txn = this.idbTransaction(db, {stores: ['docs', doc.slug], mode: 'readwrite', ignoreError: false}); | |
| 260 | + const txn = this.idbTransaction(db, { | |
| 261 | + stores: ["docs", doc.slug], | |
| 262 | + mode: "readwrite", | |
| 263 | + ignoreError: false, | |
| 264 | + }); | |
| 212 | 265 | txn.oncomplete = () => { |
| 213 | 266 | if (this.cachedDocs != null) { |
| 214 | 267 | delete this.cachedDocs[doc.slug]; |
| 215 | 268 | } |
| 216 | 269 | onSuccess(); |
| 217 | 270 | }; |
| 218 | − txn.onerror = function(event) { | |
| 271 | + txn.onerror = function (event) { | |
| 219 | 272 | event.preventDefault(); |
| 220 | − if (((txn.error != null ? txn.error.name : undefined) === 'NotFoundError') && _retry) { | |
| 273 | + if ( | |
| 274 | + (txn.error != null ? txn.error.name : undefined) === | |
| 275 | + "NotFoundError" && | |
| 276 | + _retry | |
| 277 | + ) { | |
| 221 | 278 | this.migrate(); |
| 222 | 279 | setTimeout(() => { |
| 223 | 280 | return this.unstore(doc, onSuccess, onError, false); |
| 224 | − } | |
| 225 | − , 0); | |
| 281 | + }, 0); | |
| 226 | 282 | } else { |
| 227 | 283 | onError(event); |
| 228 | 284 | } |
| 229 | 285 | }; |
| 230 | 286 | |
| 231 | − let store = txn.objectStore('docs'); | |
| 287 | + let store = txn.objectStore("docs"); | |
| 232 | 288 | store.delete(doc.slug); |
| 233 | 289 | |
| 234 | 290 | store = txn.objectStore(doc.slug); |
| @@ -243,20 +299,23 @@ · 8 unmodified lines | ||
| 243 | 299 | return; |
| 244 | 300 | } |
| 245 | 301 | |
| 246 | − this.db(db => { | |
| 302 | + this.db((db) => { | |
| 247 | 303 | if (!db) { |
| 248 | 304 | fn(false); |
| 249 | 305 | return; |
| 250 | 306 | } |
| 251 | 307 | |
| 252 | − const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); | |
| 253 | − const store = txn.objectStore('docs'); | |
| 308 | + const txn = this.idbTransaction(db, { | |
| 309 | + stores: ["docs"], | |
| 310 | + mode: "readonly", | |
| 311 | + }); | |
| 312 | + const store = txn.objectStore("docs"); | |
| 254 | 313 | |
| 255 | 314 | const req = store.get(doc.slug); |
| 256 | − req.onsuccess = function() { | |
| 315 | + req.onsuccess = function () { | |
| 257 | 316 | fn(req.result); |
| 258 | 317 | }; |
| 259 | − req.onerror = function(event) { | |
| 318 | + req.onerror = function (event) { | |
| 260 | 319 | event.preventDefault(); |
| 261 | 320 | fn(false); |
| 262 | 321 | }; |
| @@ -264,36 +323,41 @@ · 1 unmodified line | ||
| 264 | 323 | } |
| 265 | 324 | |
| 266 | 325 | cachedVersion(doc) { |
| 267 | − if (!this.cachedDocs) { return; } | |
| 326 | + if (!this.cachedDocs) { | |
| 327 | + return; | |
| 328 | + } | |
| 268 | 329 | return this.cachedDocs[doc.slug] || false; |
| 269 | 330 | } |
| 270 | 331 | |
| 271 | 332 | versions(docs, fn) { |
| 272 | 333 | let versions; |
| 273 | − if (versions = this.cachedVersions(docs)) { | |
| 334 | + if ((versions = this.cachedVersions(docs))) { | |
| 274 | 335 | fn(versions); |
| 275 | 336 | return; |
| 276 | 337 | } |
| 277 | 338 | |
| 278 | − return this.db(db => { | |
| 339 | + return this.db((db) => { | |
| 279 | 340 | if (!db) { |
| 280 | 341 | fn(false); |
| 281 | 342 | return; |
| 282 | 343 | } |
| 283 | 344 | |
| 284 | − const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); | |
| 285 | − txn.oncomplete = function() { | |
| 345 | + const txn = this.idbTransaction(db, { | |
| 346 | + stores: ["docs"], | |
| 347 | + mode: "readonly", | |
| 348 | + }); | |
| 349 | + txn.oncomplete = function () { | |
| 286 | 350 | fn(result); |
| 287 | 351 | }; |
| 288 | − const store = txn.objectStore('docs'); | |
| 352 | + const store = txn.objectStore("docs"); | |
| 289 | 353 | var result = {}; |
| 290 | 354 | |
| 291 | − docs.forEach(function(doc) { | |
| 355 | + docs.forEach(function (doc) { | |
| 292 | 356 | const req = store.get(doc.slug); |
| 293 | − req.onsuccess = function() { | |
| 357 | + req.onsuccess = function () { | |
| 294 | 358 | result[doc.slug] = req.result; |
| 295 | 359 | }; |
| 296 | − req.onerror = function(event) { | |
| 360 | + req.onerror = function (event) { | |
| 297 | 361 | event.preventDefault(); |
| 298 | 362 | result[doc.slug] = false; |
| 299 | 363 | }; |
| @@ -302,9 +366,13 @@ · 2 unmodified lines | ||
| 302 | 366 | } |
| 303 | 367 | |
| 304 | 368 | cachedVersions(docs) { |
| 305 | − if (!this.cachedDocs) { return; } | |
| 369 | + if (!this.cachedDocs) { | |
| 370 | + return; | |
| 371 | + } | |
| 306 | 372 | const result = {}; |
| 307 | − for (var doc of Array.from(docs)) { result[doc.slug] = this.cachedVersion(doc); } | |
| 373 | + for (var doc of Array.from(docs)) { | |
| 374 | + result[doc.slug] = this.cachedVersion(doc); | |
| 375 | + } | |
| 308 | 376 | return result; |
| 309 | 377 | } |
| 310 | 378 | |
| @@ -320,14 +388,14 @@ · 9 unmodified lines | ||
| 320 | 388 | loadWithXHR(entry, onSuccess, onError) { |
| 321 | 389 | return ajax({ |
| 322 | 390 | url: entry.fileUrl(), |
| 323 | − dataType: 'html', | |
| 391 | + dataType: "html", | |
| 324 | 392 | success: onSuccess, |
| 325 | − error: onError | |
| 393 | + error: onError, | |
| 326 | 394 | }); |
| 327 | 395 | } |
| 328 | 396 | |
| 329 | 397 | loadWithIDB(entry, onSuccess, onError) { |
| 330 | − return this.db(db => { | |
| 398 | + return this.db((db) => { | |
| 331 | 399 | if (!db) { |
| 332 | 400 | onError(); |
| 333 | 401 | return; |
| @@ -339,14 +407,21 @@ · 5 unmodified lines | ||
| 339 | 407 | return; |
| 340 | 408 | } |
| 341 | 409 | |
| 342 | − const txn = this.idbTransaction(db, {stores: [entry.doc.slug], mode: 'readonly'}); | |
| 410 | + const txn = this.idbTransaction(db, { | |
| 411 | + stores: [entry.doc.slug], | |
| 412 | + mode: "readonly", | |
| 413 | + }); | |
| 343 | 414 | const store = txn.objectStore(entry.doc.slug); |
| 344 | 415 | |
| 345 | 416 | const req = store.get(entry.dbPath()); |
| 346 | − req.onsuccess = function() { | |
| 347 | − if (req.result) { onSuccess(req.result); } else { onError(); } | |
| 417 | + req.onsuccess = function () { | |
| 418 | + if (req.result) { | |
| 419 | + onSuccess(req.result); | |
| 420 | + } else { | |
| 421 | + onError(); | |
| 422 | + } | |
| 348 | 423 | }; |
| 349 | − req.onerror = function(event) { | |
| 424 | + req.onerror = function (event) { | |
| 350 | 425 | event.preventDefault(); |
| 351 | 426 | onError(); |
| 352 | 427 | }; |
| @@ -355,31 +430,38 @@ · 2 unmodified lines | ||
| 355 | 430 | } |
| 356 | 431 | |
| 357 | 432 | loadDocsCache(db) { |
| 358 | − if (this.cachedDocs) { return; } | |
| 433 | + if (this.cachedDocs) { | |
| 434 | + return; | |
| 435 | + } | |
| 359 | 436 | this.cachedDocs = {}; |
| 360 | 437 | |
| 361 | − const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); | |
| 438 | + const txn = this.idbTransaction(db, { | |
| 439 | + stores: ["docs"], | |
| 440 | + mode: "readonly", | |
| 441 | + }); | |
| 362 | 442 | txn.oncomplete = () => { |
| 363 | 443 | setTimeout(this.checkForCorruptedDocs, 50); |
| 364 | 444 | }; |
| 365 | 445 | |
| 366 | − const req = txn.objectStore('docs').openCursor(); | |
| 367 | − req.onsuccess = event => { | |
| 446 | + const req = txn.objectStore("docs").openCursor(); | |
| 447 | + req.onsuccess = (event) => { | |
| 368 | 448 | let cursor; |
| 369 | − if (!(cursor = event.target.result)) { return; } | |
| 449 | + if (!(cursor = event.target.result)) { | |
| 450 | + return; | |
| 451 | + } | |
| 370 | 452 | this.cachedDocs[cursor.key] = cursor.value; |
| 371 | 453 | cursor.continue(); |
| 372 | 454 | }; |
| 373 | − req.onerror = function(event) { | |
| 455 | + req.onerror = function (event) { | |
| 374 | 456 | event.preventDefault(); |
| 375 | 457 | }; |
| 376 | 458 | } |
| 377 | 459 | |
| 378 | 460 | checkForCorruptedDocs() { |
| 379 | − this.db(db => { | |
| 461 | + this.db((db) => { | |
| 380 | 462 | let slug; |
| 381 | 463 | this.corruptedDocs = []; |
| 382 | − const docs = ((() => { | |
| 464 | + const docs = (() => { | |
| 383 | 465 | const result = []; |
| 384 | 466 | for (var key in this.cachedDocs) { |
| 385 | 467 | var value = this.cachedDocs[key]; |
| @@ -388,11 +470,13 @@ · 2 unmodified lines | ||
| 388 | 470 | } |
| 389 | 471 | } |
| 390 | 472 | return result; |
| 391 | − })()); | |
| 392 | − if (docs.length === 0) { return; } | |
| 473 | + })(); | |
| 474 | + if (docs.length === 0) { | |
| 475 | + return; | |
| 476 | + } | |
| 393 | 477 | |
| 394 | 478 | for (slug of Array.from(docs)) { |
| 395 | − if (!app.docs.findBy('slug', slug)) { | |
| 479 | + if (!app.docs.findBy("slug", slug)) { | |
| 396 | 480 | this.corruptedDocs.push(slug); |
| 397 | 481 | } |
| 398 | 482 | } |
| @@ -406,46 +490,64 @@ · 7 unmodified lines | ||
| 406 | 490 | return; |
| 407 | 491 | } |
| 408 | 492 | |
| 409 | − const txn = this.idbTransaction(db, {stores: docs, mode: 'readonly', ignoreError: false}); | |
| 493 | + const txn = this.idbTransaction(db, { | |
| 494 | + stores: docs, | |
| 495 | + mode: "readonly", | |
| 496 | + ignoreError: false, | |
| 497 | + }); | |
| 410 | 498 | txn.oncomplete = () => { |
| 411 | − if (this.corruptedDocs.length > 0) { setTimeout(this.deleteCorruptedDocs, 0); } | |
| 499 | + if (this.corruptedDocs.length > 0) { | |
| 500 | + setTimeout(this.deleteCorruptedDocs, 0); | |
| 501 | + } | |
| 412 | 502 | }; |
| 413 | 503 | |
| 414 | 504 | for (var doc of Array.from(docs)) { |
| 415 | − txn.objectStore(doc).get('index').onsuccess = event => { | |
| 416 | − if (!event.target.result) { this.corruptedDocs.push(event.target.source.name); } | |
| 505 | + txn.objectStore(doc).get("index").onsuccess = (event) => { | |
| 506 | + if (!event.target.result) { | |
| 507 | + this.corruptedDocs.push(event.target.source.name); | |
| 508 | + } | |
| 417 | 509 | }; |
| 418 | 510 | } |
| 419 | 511 | }); |
| 420 | 512 | } |
| 421 | 513 | |
| 422 | 514 | deleteCorruptedDocs() { |
| 423 | − this.db(db => { | |
| 515 | + this.db((db) => { | |
| 424 | 516 | let doc; |
| 425 | − const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readwrite', ignoreError: false}); | |
| 426 | − const store = txn.objectStore('docs'); | |
| 517 | + const txn = this.idbTransaction(db, { | |
| 518 | + stores: ["docs"], | |
| 519 | + mode: "readwrite", | |
| 520 | + ignoreError: false, | |
| 521 | + }); | |
| 522 | + const store = txn.objectStore("docs"); | |
| 427 | 523 | while ((doc = this.corruptedDocs.pop())) { |
| 428 | 524 | this.cachedDocs[doc] = false; |
| 429 | 525 | store.delete(doc); |
| 430 | 526 | } |
| 431 | 527 | }); |
| 432 | − Raven.captureMessage('corruptedDocs', {level: 'info', extra: { docs: this.corruptedDocs.join(',') }}); | |
| 528 | + Raven.captureMessage("corruptedDocs", { | |
| 529 | + level: "info", | |
| 530 | + extra: { docs: this.corruptedDocs.join(",") }, | |
| 531 | + }); | |
| 433 | 532 | } |
| 434 | 533 | |
| 435 | 534 | shouldLoadWithIDB(entry) { |
| 436 | − return this.useIndexedDB && (!this.cachedDocs || this.cachedDocs[entry.doc.slug]); | |
| 535 | + return ( | |
| 536 | + this.useIndexedDB && | |
| 537 | + (!this.cachedDocs || this.cachedDocs[entry.doc.slug]) | |
| 538 | + ); | |
| 437 | 539 | } |
| 438 | 540 | |
| 439 | 541 | idbTransaction(db, options) { |
| 440 | 542 | app.lastIDBTransaction = [options.stores, options.mode]; |
| 441 | 543 | const txn = db.transaction(options.stores, options.mode); |
| 442 | 544 | if (options.ignoreError !== false) { |
| 443 | − txn.onerror = function(event) { | |
| 545 | + txn.onerror = function (event) { | |
| 444 | 546 | event.preventDefault(); |
| 445 | 547 | }; |
| 446 | 548 | } |
| 447 | 549 | if (options.ignoreAbort !== false) { |
| 448 | − txn.onabort = function(event) { | |
| 550 | + txn.onabort = function (event) { | |
| 449 | 551 | event.preventDefault(); |
| 450 | 552 | }; |
| 451 | 553 | } |
| @@ -453,9 +555,11 @@ · 1 unmodified line | ||
| 453 | 555 | } |
| 454 | 556 | |
| 455 | 557 | reset() { |
| 456 | − try { if (typeof indexedDB !== 'undefined' && indexedDB !== null) { | |
| 457 | − indexedDB.deleteDatabase(NAME); | |
| 458 | − } } catch (error) {} | |
| 558 | + try { | |
| 559 | + if (typeof indexedDB !== "undefined" && indexedDB !== null) { | |
| 560 | + indexedDB.deleteDatabase(NAME); | |
| 561 | + } | |
| 562 | + } catch (error) {} | |
| 459 | 563 | } |
| 460 | 564 | |
| 461 | 565 | useIndexedDB() { |
| @@ -463,7 +567,7 @@ · 1 unmodified line | ||
| 463 | 567 | if (!app.isSingleDoc() && window.indexedDB) { |
| 464 | 568 | return true; |
| 465 | 569 | } else { |
| 466 | − this.reason = 'not_supported'; | |
| 570 | + this.reason = "not_supported"; | |
| 467 | 571 | return false; |
| 468 | 572 | } |
| 469 | 573 | } catch (error) { |
| @@ -472,15 +576,15 @@ · 2 unmodified lines | ||
| 472 | 576 | } |
| 473 | 577 | |
| 474 | 578 | migrate() { |
| 475 | − app.settings.set('schema', this.userVersion() + 1); | |
| 579 | + app.settings.set("schema", this.userVersion() + 1); | |
| 476 | 580 | } |
| 477 | 581 | |
| 478 | 582 | setUserVersion(version) { |
| 479 | − app.settings.set('schema', version); | |
| 583 | + app.settings.set("schema", version); | |
| 480 | 584 | } |
| 481 | 585 | |
| 482 | 586 | userVersion() { |
| 483 | − return app.settings.get('schema'); | |
| 587 | + return app.settings.get("schema"); | |
| 484 | 588 | } |
| 485 | 589 | }); |
| 486 | 590 | Cls.initClass(); |
| @@ -12,19 +12,19 @@ · 11 unmodified lines | ||
| 12 | 12 | const Cls = (app.Router = class Router { |
| 13 | 13 | static initClass() { |
| 14 | 14 | $.extend(this.prototype, Events); |
| 15 | − | |
| 15 | + | |
| 16 | 16 | this.routes = [ |
| 17 | − ['*', 'before' ], | |
| 18 | − ['/', 'root' ], | |
| 19 | − ['/settings', 'settings' ], | |
| 20 | − ['/offline', 'offline' ], | |
| 21 | − ['/about', 'about' ], | |
| 22 | − ['/news', 'news' ], | |
| 23 | − ['/help', 'help' ], | |
| 24 | − ['/:doc-:type/', 'type' ], | |
| 25 | − ['/:doc/', 'doc' ], | |
| 26 | − ['/:doc/:path(*)', 'entry' ], | |
| 27 | − ['*', 'notFound' ] | |
| 17 | + ["*", "before"], | |
| 18 | + ["/", "root"], | |
| 19 | + ["/settings", "settings"], | |
| 20 | + ["/offline", "offline"], | |
| 21 | + ["/about", "about"], | |
| 22 | + ["/news", "news"], | |
| 23 | + ["/help", "help"], | |
| 24 | + ["/:doc-:type/", "type"], | |
| 25 | + ["/:doc/", "doc"], | |
| 26 | + ["/:doc/:path(*)", "entry"], | |
| 27 | + ["*", "notFound"], | |
| 28 | 28 | ]; |
| 29 | 29 | } |
| 30 | 30 | |
| @@ -45,16 +45,16 @@ const Cls = (app.Router = class Router { · 14 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | triggerRoute(name) { |
| 47 | 47 | this.trigger(name, this.context); |
| 48 | − this.trigger('after', name, this.context); | |
| 48 | + this.trigger("after", name, this.context); | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | before(context, next) { |
| 52 | 52 | let res; |
| 53 | 53 | const previousContext = this.context; |
| 54 | 54 | this.context = context; |
| 55 | − this.trigger('before', context); | |
| 55 | + this.trigger("before", context); | |
| 56 | 56 | |
| 57 | − if (res = next()) { | |
| 57 | + if ((res = next())) { | |
| 58 | 58 | this.context = previousContext; |
| 59 | 59 | return res; |
| 60 | 60 | } else { |
| @@ -64,10 +64,14 @@ const Cls = (app.Router = class Router { · 3 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | doc(context, next) { |
| 66 | 66 | let doc; |
| 67 | − if (doc = app.docs.findBySlug(context.params.doc) || app.disabledDocs.findBySlug(context.params.doc)) { | |
| 67 | + if ( | |
| 68 | + (doc = | |
| 69 | + app.docs.findBySlug(context.params.doc) || | |
| 70 | + app.disabledDocs.findBySlug(context.params.doc)) | |
| 71 | + ) { | |
| 68 | 72 | context.doc = doc; |
| 69 | 73 | context.entry = doc.toEntry(); |
| 70 | − this.triggerRoute('entry'); | |
| 74 | + this.triggerRoute("entry"); | |
| 71 | 75 | return; |
| 72 | 76 | } else { |
| 73 | 77 | return next(); |
| @@ -78,10 +82,13 @@ const Cls = (app.Router = class Router { · 4 unmodified lines | ||
| 78 | 82 | let type; |
| 79 | 83 | const doc = app.docs.findBySlug(context.params.doc); |
| 80 | 84 | |
| 81 | − if (type = doc != null ? doc.types.findBy('slug', context.params.type) : undefined) { | |
| 85 | + if ( | |
| 86 | + (type = | |
| 87 | + doc != null ? doc.types.findBy("slug", context.params.type) : undefined) | |
| 88 | + ) { | |
| 82 | 89 | context.doc = doc; |
| 83 | 90 | context.type = type; |
| 84 | − this.triggerRoute('type'); | |
| 91 | + this.triggerRoute("type"); | |
| 85 | 92 | return; |
| 86 | 93 | } else { |
| 87 | 94 | return next(); |
| @@ -91,86 +98,110 @@ const Cls = (app.Router = class Router { · 3 unmodified lines | ||
| 91 | 98 | entry(context, next) { |
| 92 | 99 | let entry; |
| 93 | 100 | const doc = app.docs.findBySlug(context.params.doc); |
| 94 | − if (!doc) { return next(); } | |
| 95 | − let { | |
| 96 | − path | |
| 97 | − } = context.params; | |
| 98 | − const { | |
| 99 | − hash | |
| 100 | − } = context; | |
| 101 | − | |
| 102 | − if (entry = doc.findEntryByPathAndHash(path, hash)) { | |
| 101 | + if (!doc) { | |
| 102 | + return next(); | |
| 103 | + } | |
| 104 | + let { path } = context.params; | |
| 105 | + const { hash } = context; | |
| 106 | + | |
| 107 | + if ((entry = doc.findEntryByPathAndHash(path, hash))) { | |
| 103 | 108 | context.doc = doc; |
| 104 | 109 | context.entry = entry; |
| 105 | − this.triggerRoute('entry'); | |
| 110 | + this.triggerRoute("entry"); | |
| 106 | 111 | return; |
| 107 | − } else if (path.slice(-6) === '/index') { | |
| 112 | + } else if (path.slice(-6) === "/index") { | |
| 108 | 113 | path = path.substr(0, path.length - 6); |
| 109 | − if (entry = doc.findEntryByPathAndHash(path, hash)) { return entry.fullPath(); } | |
| 114 | + if ((entry = doc.findEntryByPathAndHash(path, hash))) { | |
| 115 | + return entry.fullPath(); | |
| 116 | + } | |
| 110 | 117 | } else { |
| 111 | 118 | path = `${path}/index`; |
| 112 | − if (entry = doc.findEntryByPathAndHash(path, hash)) { return entry.fullPath(); } | |
| 119 | + if ((entry = doc.findEntryByPathAndHash(path, hash))) { | |
| 120 | + return entry.fullPath(); | |
| 121 | + } | |
| 113 | 122 | } |
| 114 | 123 | |
| 115 | 124 | return next(); |
| 116 | 125 | } |
| 117 | 126 | |
| 118 | 127 | root() { |
| 119 | − if (app.isSingleDoc()) { return '/'; } | |
| 120 | − this.triggerRoute('root'); | |
| 128 | + if (app.isSingleDoc()) { | |
| 129 | + return "/"; | |
| 130 | + } | |
| 131 | + this.triggerRoute("root"); | |
| 121 | 132 | } |
| 122 | 133 | |
| 123 | 134 | settings(context) { |
| 124 | − if (app.isSingleDoc()) { return `/#/${context.path}`; } | |
| 125 | − this.triggerRoute('settings'); | |
| 135 | + if (app.isSingleDoc()) { | |
| 136 | + return `/#/${context.path}`; | |
| 137 | + } | |
| 138 | + this.triggerRoute("settings"); | |
| 126 | 139 | } |
| 127 | 140 | |
| 128 | − offline(context){ | |
| 129 | − if (app.isSingleDoc()) { return `/#/${context.path}`; } | |
| 130 | − this.triggerRoute('offline'); | |
| 141 | + offline(context) { | |
| 142 | + if (app.isSingleDoc()) { | |
| 143 | + return `/#/${context.path}`; | |
| 144 | + } | |
| 145 | + this.triggerRoute("offline"); | |
| 131 | 146 | } |
| 132 | 147 | |
| 133 | 148 | about(context) { |
| 134 | − if (app.isSingleDoc()) { return `/#/${context.path}`; } | |
| 135 | − context.page = 'about'; | |
| 136 | − this.triggerRoute('page'); | |
| 149 | + if (app.isSingleDoc()) { | |
| 150 | + return `/#/${context.path}`; | |
| 151 | + } | |
| 152 | + context.page = "about"; | |
| 153 | + this.triggerRoute("page"); | |
| 137 | 154 | } |
| 138 | 155 | |
| 139 | 156 | news(context) { |
| 140 | − if (app.isSingleDoc()) { return `/#/${context.path}`; } | |
| 141 | − context.page = 'news'; | |
| 142 | − this.triggerRoute('page'); | |
| 157 | + if (app.isSingleDoc()) { | |
| 158 | + return `/#/${context.path}`; | |
| 159 | + } | |
| 160 | + context.page = "news"; | |
| 161 | + this.triggerRoute("page"); | |
| 143 | 162 | } |
| 144 | 163 | |
| 145 | 164 | help(context) { |
| 146 | − if (app.isSingleDoc()) { return `/#/${context.path}`; } | |
| 147 | − context.page = 'help'; | |
| 148 | − this.triggerRoute('page'); | |
| 165 | + if (app.isSingleDoc()) { | |
| 166 | + return `/#/${context.path}`; | |
| 167 | + } | |
| 168 | + context.page = "help"; | |
| 169 | + this.triggerRoute("page"); | |
| 149 | 170 | } |
| 150 | 171 | |
| 151 | 172 | notFound(context) { |
| 152 | − this.triggerRoute('notFound'); | |
| 173 | + this.triggerRoute("notFound"); | |
| 153 | 174 | } |
| 154 | 175 | |
| 155 | 176 | isIndex() { |
| 156 | − return ((this.context != null ? this.context.path : undefined) === '/') || (app.isSingleDoc() && __guard__(this.context != null ? this.context.entry : undefined, x => x.isIndex())); | |
| 177 | + return ( | |
| 178 | + (this.context != null ? this.context.path : undefined) === "/" || | |
| 179 | + (app.isSingleDoc() && | |
| 180 | + __guard__(this.context != null ? this.context.entry : undefined, (x) => | |
| 181 | + x.isIndex(), | |
| 182 | + )) | |
| 183 | + ); | |
| 157 | 184 | } |
| 158 | 185 | |
| 159 | 186 | isSettings() { |
| 160 | − return (this.context != null ? this.context.path : undefined) === '/settings'; | |
| 187 | + return ( | |
| 188 | + (this.context != null ? this.context.path : undefined) === "/settings" | |
| 189 | + ); | |
| 161 | 190 | } |
| 162 | 191 | |
| 163 | 192 | setInitialPath() { |
| 164 | 193 | // Remove superfluous forward slashes at the beginning of the path |
| 165 | 194 | let path; |
| 166 | − if ((path = location.pathname.replace(/^\/{2,}/g, '/')) !== location.pathname) { | |
| 195 | + if ( | |
| 196 | + (path = location.pathname.replace(/^\/{2,}/g, "/")) !== location.pathname | |
| 197 | + ) { | |
| 167 | 198 | page.replace(path + location.search + location.hash, null, true); |
| 168 | 199 | } |
| 169 | 200 | |
| 170 | − if (location.pathname === '/') { | |
| 171 | − if (path = this.getInitialPathFromHash()) { | |
| 201 | + if (location.pathname === "/") { | |
| 202 | + if ((path = this.getInitialPathFromHash())) { | |
| 172 | 203 | page.replace(path + location.search, null, true); |
| 173 | − } else if (path = this.getInitialPathFromCookie()) { | |
| 204 | + } else if ((path = this.getInitialPathFromCookie())) { | |
| 174 | 205 | page.replace(path + location.search + location.hash, null, true); |
| 175 | 206 | } |
| 176 | 207 | } |
| @@ -178,24 +209,33 @@ const Cls = (app.Router = class Router { · 1 unmodified line | ||
| 178 | 209 | |
| 179 | 210 | getInitialPathFromHash() { |
| 180 | 211 | try { |
| 181 | − return __guard__((new RegExp("#/(.+)")).exec(decodeURIComponent(location.hash)), x => x[1]); | |
| 212 | + return __guard__( | |
| 213 | + new RegExp("#/(.+)").exec(decodeURIComponent(location.hash)), | |
| 214 | + (x) => x[1], | |
| 215 | + ); | |
| 182 | 216 | } catch (error) {} |
| 183 | 217 | } |
| 184 | 218 | |
| 185 | 219 | getInitialPathFromCookie() { |
| 186 | 220 | let path; |
| 187 | − if (path = Cookies.get('initial_path')) { | |
| 188 | − Cookies.expire('initial_path'); | |
| 221 | + if ((path = Cookies.get("initial_path"))) { | |
| 222 | + Cookies.expire("initial_path"); | |
| 189 | 223 | return path; |
| 190 | 224 | } |
| 191 | 225 | } |
| 192 | 226 | |
| 193 | 227 | replaceHash(hash) { |
| 194 | − page.replace(location.pathname + location.search + (hash || ''), null, true); | |
| 228 | + page.replace( | |
| 229 | + location.pathname + location.search + (hash || ""), | |
| 230 | + null, | |
| 231 | + true, | |
| 232 | + ); | |
| 195 | 233 | } |
| 196 | 234 | }); |
| 197 | 235 | Cls.initClass(); |
| 198 | 236 | |
| 199 | 237 | function __guard__(value, transform) { |
| 200 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 201 | −} | |
| 238 | + return typeof value !== "undefined" && value !== null | |
| 239 | + ? transform(value) | |
| 240 | + : undefined; | |
| 241 | +} | |
| @@ -16,116 +16,150 @@ · 15 unmodified lines | ||
| 16 | 16 | // Match functions |
| 17 | 17 | // |
| 18 | 18 | |
| 19 | −let fuzzyRegexp, i, index, lastIndex, match, matcher, matchIndex, matchLength, queryLength, score, separators, value, valueLength; | |
| 20 | −const SEPARATOR = '.'; | |
| 19 | +let fuzzyRegexp, | |
| 20 | + i, | |
| 21 | + index, | |
| 22 | + lastIndex, | |
| 23 | + match, | |
| 24 | + matcher, | |
| 25 | + matchIndex, | |
| 26 | + matchLength, | |
| 27 | + queryLength, | |
| 28 | + score, | |
| 29 | + separators, | |
| 30 | + value, | |
| 31 | + valueLength; | |
| 32 | +const SEPARATOR = "."; | |
| 21 | 33 | |
| 22 | 34 | let query = |
| 23 | −(queryLength = | |
| 24 | −(value = | |
| 25 | −(valueLength = | |
| 26 | −(matcher = // current match function | |
| 27 | −(fuzzyRegexp = // query fuzzy regexp | |
| 28 | −(index = // position of the query in the string being matched | |
| 29 | −(lastIndex = // last position of the query in the string being matched | |
| 30 | −(match = // regexp match data | |
| 31 | −(matchIndex = | |
| 32 | −(matchLength = | |
| 33 | −(score = // score for the current match | |
| 34 | −(separators = // counter | |
| 35 | −(i = null))))))))))))); // cursor | |
| 35 | + (queryLength = | |
| 36 | + value = | |
| 37 | + valueLength = | |
| 38 | + matcher = // current match function | |
| 39 | + fuzzyRegexp = // query fuzzy regexp | |
| 40 | + index = // position of the query in the string being matched | |
| 41 | + lastIndex = // last position of the query in the string being matched | |
| 42 | + match = // regexp match data | |
| 43 | + matchIndex = | |
| 44 | + matchLength = | |
| 45 | + score = // score for the current match | |
| 46 | + separators = // counter | |
| 47 | + i = | |
| 48 | + null); // cursor | |
| 36 | 49 | |
| 37 | 50 | function exactMatch() { |
| 38 | −index = value.indexOf(query); | |
| 39 | −if (!(index >= 0)) { return; } | |
| 51 | + index = value.indexOf(query); | |
| 52 | + if (!(index >= 0)) { | |
| 53 | + return; | |
| 54 | + } | |
| 40 | 55 | |
| 41 | −lastIndex = value.lastIndexOf(query); | |
| 56 | + lastIndex = value.lastIndexOf(query); | |
| 42 | 57 | |
| 43 | −if (index !== lastIndex) { | |
| 44 | − return Math.max(scoreExactMatch(), ((index = lastIndex) && scoreExactMatch()) || 0); | |
| 45 | −} else { | |
| 46 | − return scoreExactMatch(); | |
| 47 | −} | |
| 58 | + if (index !== lastIndex) { | |
| 59 | + return Math.max( | |
| 60 | + scoreExactMatch(), | |
| 61 | + ((index = lastIndex) && scoreExactMatch()) || 0, | |
| 62 | + ); | |
| 63 | + } else { | |
| 64 | + return scoreExactMatch(); | |
| 65 | + } | |
| 48 | 66 | } |
| 49 | 67 | |
| 50 | 68 | function scoreExactMatch() { |
| 51 | −// Remove one point for each unmatched character. | |
| 52 | −score = 100 - (valueLength - queryLength); | |
| 53 | − | |
| 54 | −if (index > 0) { | |
| 55 | − // If the character preceding the query is a dot, assign the same score | |
| 56 | − // as if the query was found at the beginning of the string, minus one. | |
| 57 | − if (value.charAt(index - 1) === SEPARATOR) { | |
| 58 | − score += index - 1; | |
| 59 | − // Don't match a single-character query unless it's found at the beginning | |
| 60 | − // of the string or is preceded by a dot. | |
| 61 | − } else if (queryLength === 1) { | |
| 62 | − return; | |
| 63 | − // (1) Remove one point for each unmatched character up to the nearest | |
| 64 | − // preceding dot or the beginning of the string. | |
| 65 | − // (2) Remove one point for each unmatched character following the query. | |
| 66 | − } else { | |
| 69 | + // Remove one point for each unmatched character. | |
| 70 | + score = 100 - (valueLength - queryLength); | |
| 71 | + | |
| 72 | + if (index > 0) { | |
| 73 | + // If the character preceding the query is a dot, assign the same score | |
| 74 | + // as if the query was found at the beginning of the string, minus one. | |
| 75 | + if (value.charAt(index - 1) === SEPARATOR) { | |
| 76 | + score += index - 1; | |
| 77 | + // Don't match a single-character query unless it's found at the beginning | |
| 78 | + // of the string or is preceded by a dot. | |
| 79 | + } else if (queryLength === 1) { | |
| 80 | + return; | |
| 81 | + // (1) Remove one point for each unmatched character up to the nearest | |
| 82 | + // preceding dot or the beginning of the string. | |
| 83 | + // (2) Remove one point for each unmatched character following the query. | |
| 84 | + } else { | |
| 85 | + i = index - 2; | |
| 86 | + while (i >= 0 && value.charAt(i) !== SEPARATOR) { | |
| 87 | + i--; | |
| 88 | + } | |
| 89 | + score -= | |
| 90 | + index - | |
| 91 | + i + // (1) | |
| 92 | + (valueLength - queryLength - index); // (2) | |
| 93 | + } | |
| 94 | + | |
| 95 | + // Remove one point for each dot preceding the query, except for the one | |
| 96 | + // immediately before the query. | |
| 97 | + separators = 0; | |
| 67 | 98 | i = index - 2; |
| 68 | − while ((i >= 0) && (value.charAt(i) !== SEPARATOR)) { i--; } | |
| 69 | − score -= (index - i) + // (1) | |
| 70 | − (valueLength - queryLength - index); // (2) | |
| 99 | + while (i >= 0) { | |
| 100 | + if (value.charAt(i) === SEPARATOR) { | |
| 101 | + separators++; | |
| 102 | + } | |
| 103 | + i--; | |
| 104 | + } | |
| 105 | + score -= separators; | |
| 71 | 106 | } |
| 72 | 107 | |
| 73 | − // Remove one point for each dot preceding the query, except for the one | |
| 74 | − // immediately before the query. | |
| 108 | + // Remove five points for each dot following the query. | |
| 75 | 109 | separators = 0; |
| 76 | − i = index - 2; | |
| 110 | + i = valueLength - queryLength - index - 1; | |
| 77 | 111 | while (i >= 0) { |
| 78 | − if (value.charAt(i) === SEPARATOR) { separators++; } | |
| 112 | + if (value.charAt(index + queryLength + i) === SEPARATOR) { | |
| 113 | + separators++; | |
| 114 | + } | |
| 79 | 115 | i--; |
| 80 | 116 | } |
| 81 | − score -= separators; | |
| 82 | −} | |
| 83 | − | |
| 84 | −// Remove five points for each dot following the query. | |
| 85 | −separators = 0; | |
| 86 | −i = valueLength - queryLength - index - 1; | |
| 87 | −while (i >= 0) { | |
| 88 | − if (value.charAt(index + queryLength + i) === SEPARATOR) { separators++; } | |
| 89 | − i--; | |
| 90 | −} | |
| 91 | −score -= separators * 5; | |
| 117 | + score -= separators * 5; | |
| 92 | 118 | |
| 93 | −return Math.max(1, score); | |
| 119 | + return Math.max(1, score); | |
| 94 | 120 | } |
| 95 | 121 | |
| 96 | 122 | function fuzzyMatch() { |
| 97 | −if ((valueLength <= queryLength) || (value.indexOf(query) >= 0)) { return; } | |
| 98 | −if (!(match = fuzzyRegexp.exec(value))) { return; } | |
| 99 | −matchIndex = match.index; | |
| 100 | −matchLength = match[0].length; | |
| 101 | −score = scoreFuzzyMatch(); | |
| 102 | −if (match = fuzzyRegexp.exec(value.slice(i = value.lastIndexOf(SEPARATOR) + 1))) { | |
| 103 | − matchIndex = i + match.index; | |
| 123 | + if (valueLength <= queryLength || value.indexOf(query) >= 0) { | |
| 124 | + return; | |
| 125 | + } | |
| 126 | + if (!(match = fuzzyRegexp.exec(value))) { | |
| 127 | + return; | |
| 128 | + } | |
| 129 | + matchIndex = match.index; | |
| 104 | 130 | matchLength = match[0].length; |
| 105 | − return Math.max(score, scoreFuzzyMatch()); | |
| 106 | −} else { | |
| 107 | − return score; | |
| 108 | −} | |
| 131 | + score = scoreFuzzyMatch(); | |
| 132 | + if ( | |
| 133 | + (match = fuzzyRegexp.exec( | |
| 134 | + value.slice((i = value.lastIndexOf(SEPARATOR) + 1)), | |
| 135 | + )) | |
| 136 | + ) { | |
| 137 | + matchIndex = i + match.index; | |
| 138 | + matchLength = match[0].length; | |
| 139 | + return Math.max(score, scoreFuzzyMatch()); | |
| 140 | + } else { | |
| 141 | + return score; | |
| 142 | + } | |
| 109 | 143 | } |
| 110 | 144 | |
| 111 | 145 | function scoreFuzzyMatch() { |
| 112 | −// When the match is at the beginning of the string or preceded by a dot. | |
| 113 | −if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { | |
| 114 | − return Math.max(66, 100 - matchLength); | |
| 115 | −// When the match is at the end of the string. | |
| 116 | −} else if ((matchIndex + matchLength) === valueLength) { | |
| 117 | − return Math.max(33, 67 - matchLength); | |
| 118 | −// When the match is in the middle of the string. | |
| 119 | −} else { | |
| 120 | − return Math.max(1, 34 - matchLength); | |
| 121 | −} | |
| 146 | + // When the match is at the beginning of the string or preceded by a dot. | |
| 147 | + if (matchIndex === 0 || value.charAt(matchIndex - 1) === SEPARATOR) { | |
| 148 | + return Math.max(66, 100 - matchLength); | |
| 149 | + // When the match is at the end of the string. | |
| 150 | + } else if (matchIndex + matchLength === valueLength) { | |
| 151 | + return Math.max(33, 67 - matchLength); | |
| 152 | + // When the match is in the middle of the string. | |
| 153 | + } else { | |
| 154 | + return Math.max(1, 34 - matchLength); | |
| 155 | + } | |
| 122 | 156 | } |
| 123 | 157 | |
| 124 | 158 | // |
| 125 | 159 | // Searchers |
| 126 | 160 | // |
| 127 | 161 | |
| 128 | −(function() { | |
| 162 | +(function () { | |
| 129 | 163 | let CHUNK_SIZE = undefined; |
| 130 | 164 | let DEFAULTS = undefined; |
| 131 | 165 | let SEPARATORS_REGEXP = undefined; |
| @@ -141,25 +175,26 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 9 unmodified lines | ||
| 141 | 175 | const Cls = (app.Searcher = class Searcher { |
| 142 | 176 | static initClass() { |
| 143 | 177 | $.extend(this.prototype, Events); |
| 144 | − | |
| 178 | + | |
| 145 | 179 | CHUNK_SIZE = 20000; |
| 146 | − | |
| 180 | + | |
| 147 | 181 | DEFAULTS = { |
| 148 | 182 | max_results: app.config.max_results, |
| 149 | − fuzzy_min_length: 3 | |
| 183 | + fuzzy_min_length: 3, | |
| 150 | 184 | }; |
| 151 | − | |
| 152 | − SEPARATORS_REGEXP = /#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g; | |
| 185 | + | |
| 186 | + SEPARATORS_REGEXP = | |
| 187 | + /#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g; | |
| 153 | 188 | EOS_SEPARATORS_REGEXP = /(\w)[\-:]$/; |
| 154 | 189 | INFO_PARANTHESES_REGEXP = /\ \(\w+?\)$/; |
| 155 | 190 | EMPTY_PARANTHESES_REGEXP = /\(\)/; |
| 156 | 191 | EVENT_REGEXP = /\ event$/; |
| 157 | 192 | DOT_REGEXP = /\.+/g; |
| 158 | 193 | WHITESPACE_REGEXP = /\s/g; |
| 159 | − | |
| 160 | − EMPTY_STRING = ''; | |
| 161 | − ELLIPSIS = '...'; | |
| 162 | − STRING = 'string'; | |
| 194 | + | |
| 195 | + EMPTY_STRING = ""; | |
| 196 | + ELLIPSIS = "..."; | |
| 197 | + STRING = "string"; | |
| 163 | 198 | } |
| 164 | 199 | |
| 165 | 200 | static normalizeString(string) { |
| @@ -176,13 +211,15 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 10 unmodified lines | ||
| 176 | 211 | |
| 177 | 212 | static normalizeQuery(string) { |
| 178 | 213 | string = this.normalizeString(string); |
| 179 | − return string.replace(EOS_SEPARATORS_REGEXP, '$1.'); | |
| 214 | + return string.replace(EOS_SEPARATORS_REGEXP, "$1."); | |
| 180 | 215 | } |
| 181 | 216 | |
| 182 | 217 | constructor(options) { |
| 183 | 218 | this.match = this.match.bind(this); |
| 184 | 219 | this.matchChunks = this.matchChunks.bind(this); |
| 185 | − if (options == null) { options = {}; } | |
| 220 | + if (options == null) { | |
| 221 | + options = {}; | |
| 222 | + } | |
| 186 | 223 | this.options = $.extend({}, DEFAULTS, options); |
| 187 | 224 | } |
| 188 | 225 | |
| @@ -194,11 +231,15 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 5 unmodified lines | ||
| 194 | 231 | this.query = q; |
| 195 | 232 | this.setup(); |
| 196 | 233 | |
| 197 | − if (this.isValid()) { this.match(); } else { this.end(); } | |
| 234 | + if (this.isValid()) { | |
| 235 | + this.match(); | |
| 236 | + } else { | |
| 237 | + this.end(); | |
| 238 | + } | |
| 198 | 239 | } |
| 199 | 240 | |
| 200 | 241 | setup() { |
| 201 | − query = (this.query = this.constructor.normalizeQuery(this.query)); | |
| 242 | + query = this.query = this.constructor.normalizeQuery(this.query); | |
| 202 | 243 | queryLength = query.length; |
| 203 | 244 | this.dataLength = this.data.length; |
| 204 | 245 | this.matchers = [exactMatch]; |
| @@ -216,12 +257,14 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 11 unmodified lines | ||
| 216 | 257 | } |
| 217 | 258 | |
| 218 | 259 | isValid() { |
| 219 | − return (queryLength > 0) && (query !== SEPARATOR); | |
| 260 | + return queryLength > 0 && query !== SEPARATOR; | |
| 220 | 261 | } |
| 221 | 262 | |
| 222 | 263 | end() { |
| 223 | − if (!this.totalResults) { this.triggerResults([]); } | |
| 224 | − this.trigger('end'); | |
| 264 | + if (!this.totalResults) { | |
| 265 | + this.triggerResults([]); | |
| 266 | + } | |
| 267 | + this.trigger("end"); | |
| 225 | 268 | this.free(); |
| 226 | 269 | } |
| 227 | 270 | |
| @@ -233,8 +276,17 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 5 unmodified lines | ||
| 233 | 276 | } |
| 234 | 277 | |
| 235 | 278 | free() { |
| 236 | − this.data = (this.attr = (this.dataLength = (this.matchers = (this.matcher = (this.query = | |
| 237 | − (this.totalResults = (this.scoreMap = (this.cursor = (this.timeout = null))))))))); | |
| 279 | + this.data = | |
| 280 | + this.attr = | |
| 281 | + this.dataLength = | |
| 282 | + this.matchers = | |
| 283 | + this.matcher = | |
| 284 | + this.query = | |
| 285 | + this.totalResults = | |
| 286 | + this.scoreMap = | |
| 287 | + this.cursor = | |
| 288 | + this.timeout = | |
| 289 | + null; | |
| 238 | 290 | } |
| 239 | 291 | |
| 240 | 292 | match() { |
| @@ -254,7 +306,7 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 13 unmodified lines | ||
| 254 | 306 | matchChunks() { |
| 255 | 307 | this.matchChunk(); |
| 256 | 308 | |
| 257 | − if ((this.cursor === this.dataLength) || this.scoredEnough()) { | |
| 309 | + if (this.cursor === this.dataLength || this.scoredEnough()) { | |
| 258 | 310 | this.delay(this.match); |
| 259 | 311 | this.sendResults(); |
| 260 | 312 | } else { |
| @@ -263,28 +315,36 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 2 unmodified lines | ||
| 263 | 315 | } |
| 264 | 316 | |
| 265 | 317 | matchChunk() { |
| 266 | − ({ | |
| 267 | − matcher | |
| 268 | − } = this); | |
| 269 | − for (let j = 0, end = this.chunkSize(), asc = 0 <= end; asc ? j < end : j > end; asc ? j++ : j--) { | |
| 318 | + ({ matcher } = this); | |
| 319 | + for ( | |
| 320 | + let j = 0, end = this.chunkSize(), asc = 0 <= end; | |
| 321 | + asc ? j < end : j > end; | |
| 322 | + asc ? j++ : j-- | |
| 323 | + ) { | |
| 270 | 324 | value = this.data[this.cursor][this.attr]; |
| 271 | − if (value.split) { // string | |
| 325 | + if (value.split) { | |
| 326 | + // string | |
| 272 | 327 | valueLength = value.length; |
| 273 | − if (score = matcher()) { this.addResult(this.data[this.cursor], score); } | |
| 274 | − } else { // array | |
| 328 | + if ((score = matcher())) { | |
| 329 | + this.addResult(this.data[this.cursor], score); | |
| 330 | + } | |
| 331 | + } else { | |
| 332 | + // array | |
| 275 | 333 | score = 0; |
| 276 | 334 | for (value of Array.from(this.data[this.cursor][this.attr])) { |
| 277 | 335 | valueLength = value.length; |
| 278 | 336 | score = Math.max(score, matcher() || 0); |
| 279 | 337 | } |
| 280 | − if (score > 0) { this.addResult(this.data[this.cursor], score); } | |
| 338 | + if (score > 0) { | |
| 339 | + this.addResult(this.data[this.cursor], score); | |
| 340 | + } | |
| 281 | 341 | } |
| 282 | 342 | this.cursor++; |
| 283 | 343 | } |
| 284 | 344 | } |
| 285 | 345 | |
| 286 | 346 | chunkSize() { |
| 287 | − if ((this.cursor + CHUNK_SIZE) > this.dataLength) { | |
| 347 | + if (this.cursor + CHUNK_SIZE > this.dataLength) { | |
| 288 | 348 | return this.dataLength % CHUNK_SIZE; |
| 289 | 349 | } else { |
| 290 | 350 | return CHUNK_SIZE; |
| @@ -292,8 +352,11 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 1 unmodified line | ||
| 292 | 352 | } |
| 293 | 353 | |
| 294 | 354 | scoredEnough() { |
| 295 | − return (this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >= this.options.max_results; | |
| 296 | − } | |
| 355 | + return ( | |
| 356 | + (this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >= | |
| 357 | + this.options.max_results | |
| 358 | + ); | |
| 359 | + } | |
| 297 | 360 | |
| 298 | 361 | foundEnough() { |
| 299 | 362 | return this.totalResults >= this.options.max_results; |
| @@ -301,7 +364,9 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 1 unmodified line | ||
| 301 | 364 | |
| 302 | 365 | addResult(object, score) { |
| 303 | 366 | let name; |
| 304 | − (this.scoreMap[name = Math.round(score)] || (this.scoreMap[name] = [])).push(object); | |
| 367 | + ( | |
| 368 | + this.scoreMap[(name = Math.round(score))] || (this.scoreMap[name] = []) | |
| 369 | + ).push(object); | |
| 305 | 370 | this.totalResults++; |
| 306 | 371 | } |
| 307 | 372 | |
| @@ -318,21 +383,26 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { · 10 unmodified lines | ||
| 318 | 383 | |
| 319 | 384 | sendResults() { |
| 320 | 385 | const results = this.getResults(); |
| 321 | − if (results.length) { this.triggerResults(results); } | |
| 386 | + if (results.length) { | |
| 387 | + this.triggerResults(results); | |
| 388 | + } | |
| 322 | 389 | } |
| 323 | 390 | |
| 324 | 391 | triggerResults(results) { |
| 325 | − this.trigger('results', results); | |
| 392 | + this.trigger("results", results); | |
| 326 | 393 | } |
| 327 | 394 | |
| 328 | 395 | delay(fn) { |
| 329 | − return this.timeout = setTimeout(fn, 1); | |
| 396 | + return (this.timeout = setTimeout(fn, 1)); | |
| 330 | 397 | } |
| 331 | 398 | |
| 332 | 399 | queryToFuzzyRegexp(string) { |
| 333 | − const chars = string.split(''); | |
| 334 | − for (i = 0; i < chars.length; i++) { var char = chars[i]; chars[i] = $.escapeRegexp(char); } | |
| 335 | − return new RegExp(chars.join('.*?')); | |
| 400 | + const chars = string.split(""); | |
| 401 | + for (i = 0; i < chars.length; i++) { | |
| 402 | + var char = chars[i]; | |
| 403 | + chars[i] = $.escapeRegexp(char); | |
| 404 | + } | |
| 405 | + return new RegExp(chars.join(".*?")); | |
| 336 | 406 | } |
| 337 | 407 | }); |
| 338 | 408 | Cls.initClass(); |
| @@ -347,7 +417,9 @@ app.SynchronousSearcher = class SynchronousSearcher extends app.Searcher { · 8 unmodified lines | ||
| 347 | 417 | |
| 348 | 418 | match() { |
| 349 | 419 | if (this.matcher) { |
| 350 | − if (!this.allResults) { this.allResults = []; } | |
| 420 | + if (!this.allResults) { | |
| 421 | + this.allResults = []; | |
| 422 | + } | |
| 351 | 423 | this.allResults.push.apply(this.allResults, this.getResults()); |
| 352 | 424 | } |
| 353 | 425 | return super.match(...arguments); |
| @@ -21,22 +21,28 @@ const Cls = (app.ServiceWorker = class ServiceWorker { · 20 unmodified lines | ||
| 21 | 21 | this.registration = null; |
| 22 | 22 | this.notifyUpdate = true; |
| 23 | 23 | |
| 24 | − navigator.serviceWorker.register(app.config.service_worker_path, {scope: '/'}) | |
| 24 | + navigator.serviceWorker | |
| 25 | + .register(app.config.service_worker_path, { scope: "/" }) | |
| 25 | 26 | .then( |
| 26 | − registration => this.updateRegistration(registration), | |
| 27 | − error => console.error('Could not register service worker:', error)); | |
| 27 | + (registration) => this.updateRegistration(registration), | |
| 28 | + (error) => console.error("Could not register service worker:", error), | |
| 29 | + ); | |
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 32 | update() { |
| 31 | − if (!this.registration) { return; } | |
| 33 | + if (!this.registration) { | |
| 34 | + return; | |
| 35 | + } | |
| 32 | 36 | this.notifyUpdate = true; |
| 33 | − return this.registration.update().catch(function() {}); | |
| 37 | + return this.registration.update().catch(function () {}); | |
| 34 | 38 | } |
| 35 | 39 | |
| 36 | 40 | updateInBackground() { |
| 37 | − if (!this.registration) { return; } | |
| 41 | + if (!this.registration) { | |
| 42 | + return; | |
| 43 | + } | |
| 38 | 44 | this.notifyUpdate = false; |
| 39 | − return this.registration.update().catch(function() {}); | |
| 45 | + return this.registration.update().catch(function () {}); | |
| 40 | 46 | } |
| 41 | 47 | |
| 42 | 48 | reload() { |
| @@ -45,24 +51,32 @@ const Cls = (app.ServiceWorker = class ServiceWorker { · 2 unmodified lines | ||
| 45 | 51 | |
| 46 | 52 | updateRegistration(registration) { |
| 47 | 53 | this.registration = registration; |
| 48 | − $.on(this.registration, 'updatefound', this.onUpdateFound); | |
| 54 | + $.on(this.registration, "updatefound", this.onUpdateFound); | |
| 49 | 55 | } |
| 50 | 56 | |
| 51 | 57 | onUpdateFound() { |
| 52 | − if (this.installingRegistration) { $.off(this.installingRegistration, 'statechange', this.onStateChange()); } | |
| 58 | + if (this.installingRegistration) { | |
| 59 | + $.off(this.installingRegistration, "statechange", this.onStateChange()); | |
| 60 | + } | |
| 53 | 61 | this.installingRegistration = this.registration.installing; |
| 54 | − $.on(this.installingRegistration, 'statechange', this.onStateChange); | |
| 62 | + $.on(this.installingRegistration, "statechange", this.onStateChange); | |
| 55 | 63 | } |
| 56 | 64 | |
| 57 | 65 | onStateChange() { |
| 58 | − if (this.installingRegistration && (this.installingRegistration.state === 'installed') && navigator.serviceWorker.controller) { | |
| 66 | + if ( | |
| 67 | + this.installingRegistration && | |
| 68 | + this.installingRegistration.state === "installed" && | |
| 69 | + navigator.serviceWorker.controller | |
| 70 | + ) { | |
| 59 | 71 | this.installingRegistration = null; |
| 60 | 72 | this.onUpdateReady(); |
| 61 | 73 | } |
| 62 | 74 | } |
| 63 | 75 | |
| 64 | 76 | onUpdateReady() { |
| 65 | − if (this.notifyUpdate) { this.trigger('updateready'); } | |
| 77 | + if (this.notifyUpdate) { | |
| 78 | + this.trigger("updateready"); | |
| 79 | + } | |
| 66 | 80 | } |
| 67 | 81 | }); |
| 68 | 82 | Cls.initClass(); |
| @@ -10,44 +10,39 @@ · 9 unmodified lines | ||
| 10 | 10 | * DS207: Consider shorter variations of null checks |
| 11 | 11 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 12 | 12 | */ |
| 13 | −(function() { | |
| 13 | +(function () { | |
| 14 | 14 | let PREFERENCE_KEYS = undefined; |
| 15 | 15 | let INTERNAL_KEYS = undefined; |
| 16 | 16 | const Cls = (app.Settings = class Settings { |
| 17 | 17 | static initClass() { |
| 18 | 18 | PREFERENCE_KEYS = [ |
| 19 | − 'hideDisabled', | |
| 20 | − 'hideIntro', | |
| 21 | − 'manualUpdate', | |
| 22 | − 'fastScroll', | |
| 23 | − 'arrowScroll', | |
| 24 | − 'analyticsConsent', | |
| 25 | − 'docs', | |
| 26 | − 'dark', // legacy | |
| 27 | − 'theme', | |
| 28 | − 'layout', | |
| 29 | − 'size', | |
| 30 | − 'tips', | |
| 31 | − 'noAutofocus', | |
| 32 | − 'autoInstall', | |
| 33 | − 'spaceScroll', | |
| 34 | − 'spaceTimeout' | |
| 19 | + "hideDisabled", | |
| 20 | + "hideIntro", | |
| 21 | + "manualUpdate", | |
| 22 | + "fastScroll", | |
| 23 | + "arrowScroll", | |
| 24 | + "analyticsConsent", | |
| 25 | + "docs", | |
| 26 | + "dark", // legacy | |
| 27 | + "theme", | |
| 28 | + "layout", | |
| 29 | + "size", | |
| 30 | + "tips", | |
| 31 | + "noAutofocus", | |
| 32 | + "autoInstall", | |
| 33 | + "spaceScroll", | |
| 34 | + "spaceTimeout", | |
| 35 | 35 | ]; |
| 36 | − | |
| 37 | − INTERNAL_KEYS = [ | |
| 38 | − 'count', | |
| 39 | − 'schema', | |
| 40 | − 'version', | |
| 41 | − 'news' | |
| 42 | − ]; | |
| 43 | − | |
| 36 | + | |
| 37 | + INTERNAL_KEYS = ["count", "schema", "version", "news"]; | |
| 38 | + | |
| 44 | 39 | this.prototype.LAYOUTS = [ |
| 45 | − '_max-width', | |
| 46 | − '_sidebar-hidden', | |
| 47 | − '_native-scrollbars', | |
| 48 | − '_text-justify-hyphenate' | |
| 40 | + "_max-width", | |
| 41 | + "_sidebar-hidden", | |
| 42 | + "_native-scrollbars", | |
| 43 | + "_text-justify-hyphenate", | |
| 49 | 44 | ]; |
| 50 | − | |
| 45 | + | |
| 51 | 46 | this.defaults = { |
| 52 | 47 | count: 0, |
| 53 | 48 | hideDisabled: false, |
| @@ -56,29 +51,38 @@ · 2 unmodified lines | ||
| 56 | 51 | manualUpdate: false, |
| 57 | 52 | schema: 1, |
| 58 | 53 | analyticsConsent: false, |
| 59 | − theme: 'auto', | |
| 54 | + theme: "auto", | |
| 60 | 55 | spaceScroll: 1, |
| 61 | − spaceTimeout: 0.5 | |
| 56 | + spaceTimeout: 0.5, | |
| 62 | 57 | }; |
| 63 | 58 | } |
| 64 | 59 | |
| 65 | 60 | constructor() { |
| 66 | − this.store = new CookiesStore; | |
| 61 | + this.store = new CookiesStore(); | |
| 67 | 62 | this.cache = {}; |
| 68 | − this.autoSupported = window.matchMedia('(prefers-color-scheme)').media !== 'not all'; | |
| 63 | + this.autoSupported = | |
| 64 | + window.matchMedia("(prefers-color-scheme)").media !== "not all"; | |
| 69 | 65 | if (this.autoSupported) { |
| 70 | − this.darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); | |
| 71 | − this.darkModeQuery.addListener(() => this.setTheme(this.get('theme'))); | |
| 66 | + this.darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)"); | |
| 67 | + this.darkModeQuery.addListener(() => this.setTheme(this.get("theme"))); | |
| 72 | 68 | } |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | − | |
| 76 | 71 | get(key) { |
| 77 | 72 | let left; |
| 78 | − if (this.cache.hasOwnProperty(key)) { return this.cache[key]; } | |
| 79 | − this.cache[key] = (left = this.store.get(key)) != null ? left : this.constructor.defaults[key]; | |
| 80 | − if ((key === 'theme') && (this.cache[key] === 'auto') && !this.darkModeQuery) { | |
| 81 | − return this.cache[key] = 'default'; | |
| 73 | + if (this.cache.hasOwnProperty(key)) { | |
| 74 | + return this.cache[key]; | |
| 75 | + } | |
| 76 | + this.cache[key] = | |
| 77 | + (left = this.store.get(key)) != null | |
| 78 | + ? left | |
| 79 | + : this.constructor.defaults[key]; | |
| 80 | + if ( | |
| 81 | + key === "theme" && | |
| 82 | + this.cache[key] === "auto" && | |
| 83 | + !this.darkModeQuery | |
| 84 | + ) { | |
| 85 | + return (this.cache[key] = "default"); | |
| 82 | 86 | } else { |
| 83 | 87 | return this.cache[key]; |
| 84 | 88 | } |
| @@ -87,7 +91,9 @@ · 2 unmodified lines | ||
| 87 | 91 | set(key, value) { |
| 88 | 92 | this.store.set(key, value); |
| 89 | 93 | delete this.cache[key]; |
| 90 | − if (key === 'theme') { this.setTheme(value); } | |
| 94 | + if (key === "theme") { | |
| 95 | + this.setTheme(value); | |
| 96 | + } | |
| 91 | 97 | } |
| 92 | 98 | |
| 93 | 99 | del(key) { |
| @@ -96,51 +102,58 @@ · 2 unmodified lines | ||
| 96 | 102 | } |
| 97 | 103 | |
| 98 | 104 | hasDocs() { |
| 99 | − try { return !!this.store.get('docs'); } catch (error) {} | |
| 105 | + try { | |
| 106 | + return !!this.store.get("docs"); | |
| 107 | + } catch (error) {} | |
| 100 | 108 | } |
| 101 | 109 | |
| 102 | 110 | getDocs() { |
| 103 | − return __guard__(this.store.get('docs'), x => x.split('/')) || app.config.default_docs; | |
| 111 | + return ( | |
| 112 | + __guard__(this.store.get("docs"), (x) => x.split("/")) || | |
| 113 | + app.config.default_docs | |
| 114 | + ); | |
| 104 | 115 | } |
| 105 | 116 | |
| 106 | 117 | setDocs(docs) { |
| 107 | − this.set('docs', docs.join('/')); | |
| 118 | + this.set("docs", docs.join("/")); | |
| 108 | 119 | } |
| 109 | 120 | |
| 110 | 121 | getTips() { |
| 111 | − return __guard__(this.store.get('tips'), x => x.split('/')) || []; | |
| 122 | + return __guard__(this.store.get("tips"), (x) => x.split("/")) || []; | |
| 112 | 123 | } |
| 113 | 124 | |
| 114 | 125 | setTips(tips) { |
| 115 | − this.set('tips', tips.join('/')); | |
| 126 | + this.set("tips", tips.join("/")); | |
| 116 | 127 | } |
| 117 | 128 | |
| 118 | 129 | setLayout(name, enable) { |
| 119 | 130 | this.toggleLayout(name, enable); |
| 120 | 131 | |
| 121 | − const layout = (this.store.get('layout') || '').split(' '); | |
| 122 | − $.arrayDelete(layout, ''); | |
| 132 | + const layout = (this.store.get("layout") || "").split(" "); | |
| 133 | + $.arrayDelete(layout, ""); | |
| 123 | 134 | |
| 124 | 135 | if (enable) { |
| 125 | − if (layout.indexOf(name) === -1) { layout.push(name); } | |
| 136 | + if (layout.indexOf(name) === -1) { | |
| 137 | + layout.push(name); | |
| 138 | + } | |
| 126 | 139 | } else { |
| 127 | 140 | $.arrayDelete(layout, name); |
| 128 | 141 | } |
| 129 | 142 | |
| 130 | 143 | if (layout.length > 0) { |
| 131 | − this.set('layout', layout.join(' ')); | |
| 144 | + this.set("layout", layout.join(" ")); | |
| 132 | 145 | } else { |
| 133 | − this.del('layout'); | |
| 146 | + this.del("layout"); | |
| 134 | 147 | } |
| 135 | 148 | } |
| 136 | 149 | |
| 137 | 150 | hasLayout(name) { |
| 138 | − const layout = (this.store.get('layout') || '').split(' '); | |
| 151 | + const layout = (this.store.get("layout") || "").split(" "); | |
| 139 | 152 | return layout.indexOf(name) !== -1; |
| 140 | 153 | } |
| 141 | 154 | |
| 142 | 155 | setSize(value) { |
| 143 | − this.set('size', value); | |
| 156 | + this.set("size", value); | |
| 144 | 157 | } |
| 145 | 158 | |
| 146 | 159 | dump() { |
| @@ -149,7 +162,9 @@ · 2 unmodified lines | ||
| 149 | 162 | |
| 150 | 163 | export() { |
| 151 | 164 | const data = this.dump(); |
| 152 | − for (var key of Array.from(INTERNAL_KEYS)) { delete data[key]; } | |
| 165 | + for (var key of Array.from(INTERNAL_KEYS)) { | |
| 166 | + delete data[key]; | |
| 167 | + } | |
| 153 | 168 | return data; |
| 154 | 169 | } |
| 155 | 170 | |
| @@ -158,11 +173,15 @@ · 2 unmodified lines | ||
| 158 | 173 | const object = this.export(); |
| 159 | 174 | for (key in object) { |
| 160 | 175 | value = object[key]; |
| 161 | − if (!data.hasOwnProperty(key)) { this.del(key); } | |
| 176 | + if (!data.hasOwnProperty(key)) { | |
| 177 | + this.del(key); | |
| 178 | + } | |
| 162 | 179 | } |
| 163 | 180 | for (key in data) { |
| 164 | 181 | value = data[key]; |
| 165 | − if (PREFERENCE_KEYS.indexOf(key) !== -1) { this.set(key, value); } | |
| 182 | + if (PREFERENCE_KEYS.indexOf(key) !== -1) { | |
| 183 | + this.set(key, value); | |
| 184 | + } | |
| 166 | 185 | } |
| 167 | 186 | } |
| 168 | 187 | |
| @@ -172,44 +191,54 @@ · 3 unmodified lines | ||
| 172 | 191 | } |
| 173 | 192 | |
| 174 | 193 | initLayout() { |
| 175 | − if (this.get('dark') === 1) { | |
| 176 | − this.set('theme', 'dark'); | |
| 177 | − this.del('dark'); | |
| 194 | + if (this.get("dark") === 1) { | |
| 195 | + this.set("theme", "dark"); | |
| 196 | + this.del("dark"); | |
| 197 | + } | |
| 198 | + this.setTheme(this.get("theme")); | |
| 199 | + for (var layout of Array.from(this.LAYOUTS)) { | |
| 200 | + this.toggleLayout(layout, this.hasLayout(layout)); | |
| 178 | 201 | } |
| 179 | − this.setTheme(this.get('theme')); | |
| 180 | − for (var layout of Array.from(this.LAYOUTS)) { this.toggleLayout(layout, this.hasLayout(layout)); } | |
| 181 | 202 | this.initSidebarWidth(); |
| 182 | 203 | } |
| 183 | 204 | |
| 184 | 205 | setTheme(theme) { |
| 185 | − if (theme === 'auto') { | |
| 186 | − theme = this.darkModeQuery.matches ? 'dark' : 'default'; | |
| 206 | + if (theme === "auto") { | |
| 207 | + theme = this.darkModeQuery.matches ? "dark" : "default"; | |
| 187 | 208 | } |
| 188 | − const { | |
| 189 | − classList | |
| 190 | − } = document.documentElement; | |
| 191 | − classList.remove('_theme-default', '_theme-dark'); | |
| 192 | − classList.add('_theme-' + theme); | |
| 209 | + const { classList } = document.documentElement; | |
| 210 | + classList.remove("_theme-default", "_theme-dark"); | |
| 211 | + classList.add("_theme-" + theme); | |
| 193 | 212 | this.updateColorMeta(); |
| 194 | 213 | } |
| 195 | 214 | |
| 196 | 215 | updateColorMeta() { |
| 197 | − const color = getComputedStyle(document.documentElement).getPropertyValue('--headerBackground').trim(); | |
| 198 | − $('meta[name=theme-color]').setAttribute('content', color); | |
| 216 | + const color = getComputedStyle(document.documentElement) | |
| 217 | + .getPropertyValue("--headerBackground") | |
| 218 | + .trim(); | |
| 219 | + $("meta[name=theme-color]").setAttribute("content", color); | |
| 199 | 220 | } |
| 200 | 221 | |
| 201 | 222 | toggleLayout(layout, enable) { |
| 202 | − const { | |
| 203 | − classList | |
| 204 | − } = document.body; | |
| 223 | + const { classList } = document.body; | |
| 205 | 224 | // sidebar is always shown for settings; its state is updated in app.views.Settings |
| 206 | − if ((layout !== '_sidebar-hidden') || !(app.router != null ? app.router.isSettings : undefined)) { classList.toggle(layout, enable); } | |
| 207 | − classList.toggle('_overlay-scrollbars', $.overlayScrollbarsEnabled()); | |
| 225 | + if ( | |
| 226 | + layout !== "_sidebar-hidden" || | |
| 227 | + !(app.router != null ? app.router.isSettings : undefined) | |
| 228 | + ) { | |
| 229 | + classList.toggle(layout, enable); | |
| 230 | + } | |
| 231 | + classList.toggle("_overlay-scrollbars", $.overlayScrollbarsEnabled()); | |
| 208 | 232 | } |
| 209 | 233 | |
| 210 | 234 | initSidebarWidth() { |
| 211 | − const size = this.get('size'); | |
| 212 | − if (size) { document.documentElement.style.setProperty('--sidebarWidth', size + 'px'); } | |
| 235 | + const size = this.get("size"); | |
| 236 | + if (size) { | |
| 237 | + document.documentElement.style.setProperty( | |
| 238 | + "--sidebarWidth", | |
| 239 | + size + "px", | |
| 240 | + ); | |
| 241 | + } | |
| 213 | 242 | } |
| 214 | 243 | }); |
| 215 | 244 | Cls.initClass(); |
| @@ -217,5 +246,7 @@ · 1 unmodified line | ||
| 217 | 246 | })(); |
| 218 | 247 | |
| 219 | 248 | function __guard__(value, transform) { |
| 220 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 221 | −} | |
| 249 | + return typeof value !== "undefined" && value !== null | |
| 250 | + ? transform(value) | |
| 251 | + : undefined; | |
| 252 | +} | |
| @@ -21,111 +21,151 @@ const Cls = (app.Shortcuts = class Shortcuts { · 20 unmodified lines | ||
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | start() { |
| 24 | − $.on(document, 'keydown', this.onKeydown); | |
| 25 | − $.on(document, 'keypress', this.onKeypress); | |
| 24 | + $.on(document, "keydown", this.onKeydown); | |
| 25 | + $.on(document, "keypress", this.onKeypress); | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | stop() { |
| 29 | − $.off(document, 'keydown', this.onKeydown); | |
| 30 | − $.off(document, 'keypress', this.onKeypress); | |
| 29 | + $.off(document, "keydown", this.onKeydown); | |
| 30 | + $.off(document, "keypress", this.onKeypress); | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | swapArrowKeysBehavior() { |
| 34 | − return app.settings.get('arrowScroll'); | |
| 34 | + return app.settings.get("arrowScroll"); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | spaceScroll() { |
| 38 | − return app.settings.get('spaceScroll'); | |
| 38 | + return app.settings.get("spaceScroll"); | |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | showTip() { |
| 42 | − app.showTip('KeyNav'); | |
| 43 | − return this.showTip = null; | |
| 42 | + app.showTip("KeyNav"); | |
| 43 | + return (this.showTip = null); | |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | spaceTimeout() { |
| 47 | − return app.settings.get('spaceTimeout'); | |
| 47 | + return app.settings.get("spaceTimeout"); | |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | onKeydown(event) { |
| 51 | − if (this.buggyEvent(event)) { return; } | |
| 51 | + if (this.buggyEvent(event)) { | |
| 52 | + return; | |
| 53 | + } | |
| 52 | 54 | const result = (() => { |
| 53 | 55 | if (event.ctrlKey || event.metaKey) { |
| 54 | − if (!event.altKey && !event.shiftKey) { return this.handleKeydownSuperEvent(event); } | |
| 55 | − } else if (event.shiftKey) { | |
| 56 | − if (!event.altKey) { return this.handleKeydownShiftEvent(event); } | |
| 57 | − } else if (event.altKey) { | |
| 58 | − return this.handleKeydownAltEvent(event); | |
| 59 | − } else { | |
| 60 | − return this.handleKeydownEvent(event); | |
| 61 | − } | |
| 56 | + if (!event.altKey && !event.shiftKey) { | |
| 57 | + return this.handleKeydownSuperEvent(event); | |
| 58 | + } | |
| 59 | + } else if (event.shiftKey) { | |
| 60 | + if (!event.altKey) { | |
| 61 | + return this.handleKeydownShiftEvent(event); | |
| 62 | + } | |
| 63 | + } else if (event.altKey) { | |
| 64 | + return this.handleKeydownAltEvent(event); | |
| 65 | + } else { | |
| 66 | + return this.handleKeydownEvent(event); | |
| 67 | + } | |
| 62 | 68 | })(); |
| 63 | 69 | |
| 64 | − if (result === false) { event.preventDefault(); } | |
| 70 | + if (result === false) { | |
| 71 | + event.preventDefault(); | |
| 72 | + } | |
| 65 | 73 | } |
| 66 | 74 | |
| 67 | 75 | onKeypress(event) { |
| 68 | − if (this.buggyEvent(event) || ((event.charCode === 63) && (document.activeElement.tagName === 'INPUT'))) { return; } | |
| 76 | + if ( | |
| 77 | + this.buggyEvent(event) || | |
| 78 | + (event.charCode === 63 && document.activeElement.tagName === "INPUT") | |
| 79 | + ) { | |
| 80 | + return; | |
| 81 | + } | |
| 69 | 82 | if (!event.ctrlKey && !event.metaKey) { |
| 70 | 83 | const result = this.handleKeypressEvent(event); |
| 71 | − if (result === false) { event.preventDefault(); } | |
| 84 | + if (result === false) { | |
| 85 | + event.preventDefault(); | |
| 86 | + } | |
| 72 | 87 | } |
| 73 | 88 | } |
| 74 | 89 | |
| 75 | 90 | handleKeydownEvent(event, _force) { |
| 76 | − if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownAltEvent(event, true); } | |
| 91 | + if ( | |
| 92 | + !_force && | |
| 93 | + [37, 38, 39, 40].includes(event.which) && | |
| 94 | + this.swapArrowKeysBehavior() | |
| 95 | + ) { | |
| 96 | + return this.handleKeydownAltEvent(event, true); | |
| 97 | + } | |
| 77 | 98 | |
| 78 | − if (!event.target.form && ((48 <= event.which && event.which <= 57) || (65 <= event.which && event.which <= 90))) { | |
| 79 | − this.trigger('typing'); | |
| 99 | + if ( | |
| 100 | + !event.target.form && | |
| 101 | + ((48 <= event.which && event.which <= 57) || | |
| 102 | + (65 <= event.which && event.which <= 90)) | |
| 103 | + ) { | |
| 104 | + this.trigger("typing"); | |
| 80 | 105 | return; |
| 81 | 106 | } |
| 82 | 107 | |
| 83 | 108 | switch (event.which) { |
| 84 | 109 | case 8: |
| 85 | − if (!event.target.form) { return this.trigger('typing'); } | |
| 110 | + if (!event.target.form) { | |
| 111 | + return this.trigger("typing"); | |
| 112 | + } | |
| 86 | 113 | break; |
| 87 | 114 | case 13: |
| 88 | − return this.trigger('enter'); | |
| 115 | + return this.trigger("enter"); | |
| 89 | 116 | case 27: |
| 90 | − this.trigger('escape'); | |
| 117 | + this.trigger("escape"); | |
| 91 | 118 | return false; |
| 92 | 119 | case 32: |
| 93 | − if ((event.target.type === 'search') && this.spaceScroll() && (!this.lastKeypress || (this.lastKeypress < (Date.now() - (this.spaceTimeout() * 1000))))) { | |
| 94 | − this.trigger('pageDown'); | |
| 120 | + if ( | |
| 121 | + event.target.type === "search" && | |
| 122 | + this.spaceScroll() && | |
| 123 | + (!this.lastKeypress || | |
| 124 | + this.lastKeypress < Date.now() - this.spaceTimeout() * 1000) | |
| 125 | + ) { | |
| 126 | + this.trigger("pageDown"); | |
| 95 | 127 | return false; |
| 96 | 128 | } |
| 97 | 129 | break; |
| 98 | 130 | case 33: |
| 99 | − return this.trigger('pageUp'); | |
| 131 | + return this.trigger("pageUp"); | |
| 100 | 132 | case 34: |
| 101 | − return this.trigger('pageDown'); | |
| 133 | + return this.trigger("pageDown"); | |
| 102 | 134 | case 35: |
| 103 | − if (!event.target.form) { return this.trigger('pageBottom'); } | |
| 135 | + if (!event.target.form) { | |
| 136 | + return this.trigger("pageBottom"); | |
| 137 | + } | |
| 104 | 138 | break; |
| 105 | 139 | case 36: |
| 106 | − if (!event.target.form) { return this.trigger('pageTop'); } | |
| 140 | + if (!event.target.form) { | |
| 141 | + return this.trigger("pageTop"); | |
| 142 | + } | |
| 107 | 143 | break; |
| 108 | 144 | case 37: |
| 109 | − if (!event.target.value) { return this.trigger('left'); } | |
| 145 | + if (!event.target.value) { | |
| 146 | + return this.trigger("left"); | |
| 147 | + } | |
| 110 | 148 | break; |
| 111 | 149 | case 38: |
| 112 | − this.trigger('up'); | |
| 113 | − if (typeof this.showTip === 'function') { | |
| 150 | + this.trigger("up"); | |
| 151 | + if (typeof this.showTip === "function") { | |
| 114 | 152 | this.showTip(); |
| 115 | 153 | } |
| 116 | 154 | return false; |
| 117 | 155 | case 39: |
| 118 | − if (!event.target.value) { return this.trigger('right'); } | |
| 156 | + if (!event.target.value) { | |
| 157 | + return this.trigger("right"); | |
| 158 | + } | |
| 119 | 159 | break; |
| 120 | 160 | case 40: |
| 121 | − this.trigger('down'); | |
| 122 | − if (typeof this.showTip === 'function') { | |
| 161 | + this.trigger("down"); | |
| 162 | + if (typeof this.showTip === "function") { | |
| 123 | 163 | this.showTip(); |
| 124 | 164 | } |
| 125 | 165 | return false; |
| 126 | 166 | case 191: |
| 127 | 167 | if (!event.target.form) { |
| 128 | − this.trigger('typing'); | |
| 168 | + this.trigger("typing"); | |
| 129 | 169 | return false; |
| 130 | 170 | } |
| 131 | 171 | break; |
| @@ -135,52 +175,58 @@ const Cls = (app.Shortcuts = class Shortcuts { · 3 unmodified lines | ||
| 135 | 175 | handleKeydownSuperEvent(event) { |
| 136 | 176 | switch (event.which) { |
| 137 | 177 | case 13: |
| 138 | − return this.trigger('superEnter'); | |
| 178 | + return this.trigger("superEnter"); | |
| 139 | 179 | case 37: |
| 140 | 180 | if (this.isMac) { |
| 141 | − this.trigger('superLeft'); | |
| 181 | + this.trigger("superLeft"); | |
| 142 | 182 | return false; |
| 143 | 183 | } |
| 144 | 184 | break; |
| 145 | 185 | case 38: |
| 146 | − this.trigger('pageTop'); | |
| 186 | + this.trigger("pageTop"); | |
| 147 | 187 | return false; |
| 148 | 188 | case 39: |
| 149 | 189 | if (this.isMac) { |
| 150 | − this.trigger('superRight'); | |
| 190 | + this.trigger("superRight"); | |
| 151 | 191 | return false; |
| 152 | 192 | } |
| 153 | 193 | break; |
| 154 | 194 | case 40: |
| 155 | − this.trigger('pageBottom'); | |
| 195 | + this.trigger("pageBottom"); | |
| 156 | 196 | return false; |
| 157 | 197 | case 188: |
| 158 | − this.trigger('preferences'); | |
| 198 | + this.trigger("preferences"); | |
| 159 | 199 | return false; |
| 160 | 200 | } |
| 161 | 201 | } |
| 162 | 202 | |
| 163 | 203 | handleKeydownShiftEvent(event, _force) { |
| 164 | − if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownEvent(event, true); } | |
| 204 | + if ( | |
| 205 | + !_force && | |
| 206 | + [37, 38, 39, 40].includes(event.which) && | |
| 207 | + this.swapArrowKeysBehavior() | |
| 208 | + ) { | |
| 209 | + return this.handleKeydownEvent(event, true); | |
| 210 | + } | |
| 165 | 211 | |
| 166 | − if (!event.target.form && (65 <= event.which && event.which <= 90)) { | |
| 167 | − this.trigger('typing'); | |
| 212 | + if (!event.target.form && 65 <= event.which && event.which <= 90) { | |
| 213 | + this.trigger("typing"); | |
| 168 | 214 | return; |
| 169 | 215 | } |
| 170 | 216 | |
| 171 | 217 | switch (event.which) { |
| 172 | 218 | case 32: |
| 173 | − this.trigger('pageUp'); | |
| 219 | + this.trigger("pageUp"); | |
| 174 | 220 | return false; |
| 175 | 221 | case 38: |
| 176 | − if (!__guard__(getSelection(), x => x.toString())) { | |
| 177 | − this.trigger('altUp'); | |
| 222 | + if (!__guard__(getSelection(), (x) => x.toString())) { | |
| 223 | + this.trigger("altUp"); | |
| 178 | 224 | return false; |
| 179 | 225 | } |
| 180 | 226 | break; |
| 181 | 227 | case 40: |
| 182 | − if (!__guard__(getSelection(), x1 => x1.toString())) { | |
| 183 | − this.trigger('altDown'); | |
| 228 | + if (!__guard__(getSelection(), (x1) => x1.toString())) { | |
| 229 | + this.trigger("altDown"); | |
| 184 | 230 | return false; |
| 185 | 231 | } |
| 186 | 232 | break; |
| @@ -188,58 +234,64 @@ const Cls = (app.Shortcuts = class Shortcuts { · 1 unmodified line | ||
| 188 | 234 | } |
| 189 | 235 | |
| 190 | 236 | handleKeydownAltEvent(event, _force) { |
| 191 | − if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownEvent(event, true); } | |
| 237 | + if ( | |
| 238 | + !_force && | |
| 239 | + [37, 38, 39, 40].includes(event.which) && | |
| 240 | + this.swapArrowKeysBehavior() | |
| 241 | + ) { | |
| 242 | + return this.handleKeydownEvent(event, true); | |
| 243 | + } | |
| 192 | 244 | |
| 193 | 245 | switch (event.which) { |
| 194 | 246 | case 9: |
| 195 | − return this.trigger('altRight', event); | |
| 247 | + return this.trigger("altRight", event); | |
| 196 | 248 | case 37: |
| 197 | 249 | if (!this.isMac) { |
| 198 | − this.trigger('superLeft'); | |
| 250 | + this.trigger("superLeft"); | |
| 199 | 251 | return false; |
| 200 | 252 | } |
| 201 | 253 | break; |
| 202 | 254 | case 38: |
| 203 | − this.trigger('altUp'); | |
| 255 | + this.trigger("altUp"); | |
| 204 | 256 | return false; |
| 205 | 257 | case 39: |
| 206 | 258 | if (!this.isMac) { |
| 207 | − this.trigger('superRight'); | |
| 259 | + this.trigger("superRight"); | |
| 208 | 260 | return false; |
| 209 | 261 | } |
| 210 | 262 | break; |
| 211 | 263 | case 40: |
| 212 | − this.trigger('altDown'); | |
| 264 | + this.trigger("altDown"); | |
| 213 | 265 | return false; |
| 214 | 266 | case 67: |
| 215 | − this.trigger('altC'); | |
| 267 | + this.trigger("altC"); | |
| 216 | 268 | return false; |
| 217 | 269 | case 68: |
| 218 | − this.trigger('altD'); | |
| 270 | + this.trigger("altD"); | |
| 219 | 271 | return false; |
| 220 | 272 | case 70: |
| 221 | − return this.trigger('altF', event); | |
| 273 | + return this.trigger("altF", event); | |
| 222 | 274 | case 71: |
| 223 | − this.trigger('altG'); | |
| 275 | + this.trigger("altG"); | |
| 224 | 276 | return false; |
| 225 | 277 | case 79: |
| 226 | − this.trigger('altO'); | |
| 278 | + this.trigger("altO"); | |
| 227 | 279 | return false; |
| 228 | 280 | case 82: |
| 229 | − this.trigger('altR'); | |
| 281 | + this.trigger("altR"); | |
| 230 | 282 | return false; |
| 231 | 283 | case 83: |
| 232 | − this.trigger('altS'); | |
| 284 | + this.trigger("altS"); | |
| 233 | 285 | return false; |
| 234 | 286 | } |
| 235 | 287 | } |
| 236 | 288 | |
| 237 | 289 | handleKeypressEvent(event) { |
| 238 | − if ((event.which === 63) && !event.target.value) { | |
| 239 | − this.trigger('help'); | |
| 290 | + if (event.which === 63 && !event.target.value) { | |
| 291 | + this.trigger("help"); | |
| 240 | 292 | return false; |
| 241 | 293 | } else { |
| 242 | − return this.lastKeypress = Date.now(); | |
| 294 | + return (this.lastKeypress = Date.now()); | |
| 243 | 295 | } |
| 244 | 296 | } |
| 245 | 297 | |
| @@ -257,5 +309,7 @@ const Cls = (app.Shortcuts = class Shortcuts { · 11 unmodified lines | ||
| 257 | 309 | Cls.initClass(); |
| 258 | 310 | |
| 259 | 311 | function __guard__(value, transform) { |
| 260 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 261 | −} | |
| 312 | + return typeof value !== "undefined" && value !== null | |
| 313 | + ? transform(value) | |
| 314 | + : undefined; | |
| 315 | +} | |
| @@ -11,9 +11,9 @@ app.UpdateChecker = class UpdateChecker { · 10 unmodified lines | ||
| 11 | 11 | this.onFocus = this.onFocus.bind(this); |
| 12 | 12 | this.lastCheck = Date.now(); |
| 13 | 13 | |
| 14 | − $.on(window, 'focus', this.onFocus); | |
| 14 | + $.on(window, "focus", this.onFocus); | |
| 15 | 15 | if (app.serviceWorker != null) { |
| 16 | − app.serviceWorker.on('updateready', this.onUpdateReady); | |
| 16 | + app.serviceWorker.on("updateready", this.onUpdateReady); | |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | setTimeout(this.checkDocs, 0); |
| @@ -24,31 +24,39 @@ app.UpdateChecker = class UpdateChecker { · 4 unmodified lines | ||
| 24 | 24 | app.serviceWorker.update(); |
| 25 | 25 | } else { |
| 26 | 26 | ajax({ |
| 27 | − url: $('script[src*="application"]').getAttribute('src'), | |
| 28 | − dataType: 'application/javascript', | |
| 29 | − error: (_, xhr) => { if (xhr.status === 404) { return this.onUpdateReady(); } } | |
| 27 | + url: $('script[src*="application"]').getAttribute("src"), | |
| 28 | + dataType: "application/javascript", | |
| 29 | + error: (_, xhr) => { | |
| 30 | + if (xhr.status === 404) { | |
| 31 | + return this.onUpdateReady(); | |
| 32 | + } | |
| 33 | + }, | |
| 30 | 34 | }); |
| 31 | 35 | } |
| 32 | 36 | } |
| 33 | 37 | |
| 34 | 38 | onUpdateReady() { |
| 35 | − new app.views.Notif('UpdateReady', {autoHide: null}); | |
| 39 | + new app.views.Notif("UpdateReady", { autoHide: null }); | |
| 36 | 40 | } |
| 37 | 41 | |
| 38 | 42 | checkDocs() { |
| 39 | − if (!app.settings.get('manualUpdate')) { | |
| 43 | + if (!app.settings.get("manualUpdate")) { | |
| 40 | 44 | app.docs.updateInBackground(); |
| 41 | 45 | } else { |
| 42 | − app.docs.checkForUpdates(i => { if (i > 0) { return this.onDocsUpdateReady(); } }); | |
| 46 | + app.docs.checkForUpdates((i) => { | |
| 47 | + if (i > 0) { | |
| 48 | + return this.onDocsUpdateReady(); | |
| 49 | + } | |
| 50 | + }); | |
| 43 | 51 | } |
| 44 | 52 | } |
| 45 | 53 | |
| 46 | 54 | onDocsUpdateReady() { |
| 47 | − new app.views.Notif('UpdateDocs', {autoHide: null}); | |
| 55 | + new app.views.Notif("UpdateDocs", { autoHide: null }); | |
| 48 | 56 | } |
| 49 | 57 | |
| 50 | 58 | onFocus() { |
| 51 | − if ((Date.now() - this.lastCheck) > 21600e3) { | |
| 59 | + if (Date.now() - this.lastCheck > 21600e3) { | |
| 52 | 60 | this.lastCheck = Date.now(); |
| 53 | 61 | this.check(); |
| 54 | 62 | } |
| @@ -27,8 +27,8 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | //= require tracking |
| 29 | 29 | |
| 30 | −var init = function() { | |
| 31 | − document.removeEventListener('DOMContentLoaded', init, false); | |
| 30 | +var init = function () { | |
| 31 | + document.removeEventListener("DOMContentLoaded", init, false); | |
| 32 | 32 | |
| 33 | 33 | if (document.body) { |
| 34 | 34 | return app.init(); |
| @@ -37,4 +37,4 @@ var init = function() { · 2 unmodified lines | ||
| 37 | 37 | } |
| 38 | 38 | }; |
| 39 | 39 | |
| 40 | −document.addEventListener('DOMContentLoaded', init, false); | |
| 40 | +document.addEventListener("DOMContentLoaded", init, false); | |
| @@ -9,7 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | app.Collection = class Collection { |
| 11 | 11 | constructor(objects) { |
| 12 | − if (objects == null) { objects = []; } | |
| 12 | + if (objects == null) { | |
| 13 | + objects = []; | |
| 14 | + } | |
| 13 | 15 | this.reset(objects); |
| 14 | 16 | } |
| 15 | 17 | |
| @@ -18,16 +20,22 @@ app.Collection = class Collection { · 2 unmodified lines | ||
| 18 | 20 | } |
| 19 | 21 | |
| 20 | 22 | reset(objects) { |
| 21 | − if (objects == null) { objects = []; } | |
| 23 | + if (objects == null) { | |
| 24 | + objects = []; | |
| 25 | + } | |
| 22 | 26 | this.models = []; |
| 23 | − for (var object of Array.from(objects)) { this.add(object); } | |
| 27 | + for (var object of Array.from(objects)) { | |
| 28 | + this.add(object); | |
| 29 | + } | |
| 24 | 30 | } |
| 25 | 31 | |
| 26 | 32 | add(object) { |
| 27 | 33 | if (object instanceof app.Model) { |
| 28 | 34 | this.models.push(object); |
| 29 | 35 | } else if (object instanceof Array) { |
| 30 | − for (var obj of Array.from(object)) { this.add(obj); } | |
| 36 | + for (var obj of Array.from(object)) { | |
| 37 | + this.add(obj); | |
| 38 | + } | |
| 31 | 39 | } else if (object instanceof app.Collection) { |
| 32 | 40 | this.models.push(...Array.from(object.all() || [])); |
| 33 | 41 | } else { |
| @@ -48,7 +56,9 @@ app.Collection = class Collection { · 14 unmodified lines | ||
| 48 | 56 | } |
| 49 | 57 | |
| 50 | 58 | each(fn) { |
| 51 | − for (var model of Array.from(this.models)) { fn(model); } | |
| 59 | + for (var model of Array.from(this.models)) { | |
| 60 | + fn(model); | |
| 61 | + } | |
| 52 | 62 | } |
| 53 | 63 | |
| 54 | 64 | all() { |
| @@ -61,7 +71,9 @@ app.Collection = class Collection { · 6 unmodified lines | ||
| 61 | 71 | |
| 62 | 72 | findBy(attr, value) { |
| 63 | 73 | for (var model of Array.from(this.models)) { |
| 64 | − if (model[attr] === value) { return model; } | |
| 74 | + if (model[attr] === value) { | |
| 75 | + return model; | |
| 76 | + } | |
| 65 | 77 | } |
| 66 | 78 | } |
| 67 | 79 | |
| @@ -71,7 +83,11 @@ app.Collection = class Collection { · 3 unmodified lines | ||
| 71 | 83 | |
| 72 | 84 | countAllBy(attr, value) { |
| 73 | 85 | let i = 0; |
| 74 | − for (var model of Array.from(this.models)) { if (model[attr] === value) { i += 1; } } | |
| 86 | + for (var model of Array.from(this.models)) { | |
| 87 | + if (model[attr] === value) { | |
| 88 | + i += 1; | |
| 89 | + } | |
| 90 | + } | |
| 75 | 91 | return i; |
| 76 | 92 | } |
| 77 | 93 | }; |
| @@ -8,29 +8,35 @@ · 7 unmodified lines | ||
| 8 | 8 | * DS206: Consider reworking classes to avoid initClass |
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | −(function() { | |
| 11 | +(function () { | |
| 12 | 12 | let NORMALIZE_VERSION_RGX = undefined; |
| 13 | 13 | let NORMALIZE_VERSION_SUB = undefined; |
| 14 | 14 | let CONCURRENCY = undefined; |
| 15 | 15 | const Cls = (app.collections.Docs = class Docs extends app.Collection { |
| 16 | 16 | static initClass() { |
| 17 | − this.model = 'Doc'; | |
| 18 | − | |
| 17 | + this.model = "Doc"; | |
| 18 | + | |
| 19 | 19 | NORMALIZE_VERSION_RGX = /\.(\d)$/; |
| 20 | − NORMALIZE_VERSION_SUB = '.0$1'; | |
| 21 | − | |
| 20 | + NORMALIZE_VERSION_SUB = ".0$1"; | |
| 21 | + | |
| 22 | 22 | // Load models concurrently. |
| 23 | 23 | // It's not pretty but I didn't want to import a promise library only for this. |
| 24 | 24 | CONCURRENCY = 3; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | findBySlug(slug) { |
| 28 | − return this.findBy('slug', slug) || this.findBy('slug_without_version', slug); | |
| 28 | + return ( | |
| 29 | + this.findBy("slug", slug) || this.findBy("slug_without_version", slug) | |
| 30 | + ); | |
| 29 | 31 | } |
| 30 | 32 | sort() { |
| 31 | − return this.models.sort(function(a, b) { | |
| 33 | + return this.models.sort(function (a, b) { | |
| 32 | 34 | if (a.name === b.name) { |
| 33 | − if (!a.version || (a.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB) > b.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB))) { | |
| 35 | + if ( | |
| 36 | + !a.version || | |
| 37 | + a.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB) > | |
| 38 | + b.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB) | |
| 39 | + ) { | |
| 34 | 40 | return -1; |
| 35 | 41 | } else { |
| 36 | 42 | return 1; |
| @@ -48,13 +54,13 @@ · 11 unmodified lines | ||
| 48 | 54 | var next = () => { |
| 49 | 55 | if (i < this.models.length) { |
| 50 | 56 | this.models[i].load(next, fail, options); |
| 51 | − } else if (i === ((this.models.length + CONCURRENCY) - 1)) { | |
| 57 | + } else if (i === this.models.length + CONCURRENCY - 1) { | |
| 52 | 58 | onComplete(); |
| 53 | 59 | } |
| 54 | 60 | i++; |
| 55 | 61 | }; |
| 56 | 62 | |
| 57 | − var fail = function(...args) { | |
| 63 | + var fail = function (...args) { | |
| 58 | 64 | if (onError) { |
| 59 | 65 | onError(...Array.from(args || [])); |
| 60 | 66 | onError = null; |
| @@ -62,11 +68,19 @@ · 1 unmodified line | ||
| 62 | 68 | next(); |
| 63 | 69 | }; |
| 64 | 70 | |
| 65 | − for (let j = 0, end = CONCURRENCY, asc = 0 <= end; asc ? j < end : j > end; asc ? j++ : j--) { next(); } | |
| 71 | + for ( | |
| 72 | + let j = 0, end = CONCURRENCY, asc = 0 <= end; | |
| 73 | + asc ? j < end : j > end; | |
| 74 | + asc ? j++ : j-- | |
| 75 | + ) { | |
| 76 | + next(); | |
| 77 | + } | |
| 66 | 78 | } |
| 67 | 79 | |
| 68 | 80 | clearCache() { |
| 69 | − for (var doc of Array.from(this.models)) { doc.clearCache(); } | |
| 81 | + for (var doc of Array.from(this.models)) { | |
| 82 | + doc.clearCache(); | |
| 83 | + } | |
| 70 | 84 | } |
| 71 | 85 | |
| 72 | 86 | uninstall(callback) { |
| @@ -82,11 +96,11 @@ · 9 unmodified lines | ||
| 82 | 96 | } |
| 83 | 97 | |
| 84 | 98 | getInstallStatuses(callback) { |
| 85 | − app.db.versions(this.models, function(statuses) { | |
| 99 | + app.db.versions(this.models, function (statuses) { | |
| 86 | 100 | if (statuses) { |
| 87 | 101 | for (var key in statuses) { |
| 88 | 102 | var value = statuses[key]; |
| 89 | − statuses[key] = {installed: !!value, mtime: value}; | |
| 103 | + statuses[key] = { installed: !!value, mtime: value }; | |
| 90 | 104 | } |
| 91 | 105 | } |
| 92 | 106 | callback(statuses); |
| @@ -94,22 +108,31 @@ · 1 unmodified line | ||
| 94 | 108 | } |
| 95 | 109 | |
| 96 | 110 | checkForUpdates(callback) { |
| 97 | − this.getInstallStatuses(statuses => { | |
| 111 | + this.getInstallStatuses((statuses) => { | |
| 98 | 112 | let i = 0; |
| 99 | 113 | if (statuses) { |
| 100 | − for (var slug in statuses) { var status = statuses[slug]; if (this.findBy('slug', slug).isOutdated(status)) { i += 1; } } | |
| 114 | + for (var slug in statuses) { | |
| 115 | + var status = statuses[slug]; | |
| 116 | + if (this.findBy("slug", slug).isOutdated(status)) { | |
| 117 | + i += 1; | |
| 118 | + } | |
| 119 | + } | |
| 101 | 120 | } |
| 102 | 121 | callback(i); |
| 103 | 122 | }); |
| 104 | 123 | } |
| 105 | 124 | |
| 106 | 125 | updateInBackground() { |
| 107 | − this.getInstallStatuses(statuses => { | |
| 108 | − if (!statuses) { return; } | |
| 126 | + this.getInstallStatuses((statuses) => { | |
| 127 | + if (!statuses) { | |
| 128 | + return; | |
| 129 | + } | |
| 109 | 130 | for (var slug in statuses) { |
| 110 | 131 | var status = statuses[slug]; |
| 111 | − var doc = this.findBy('slug', slug); | |
| 112 | − if (doc.isOutdated(status)) { doc.install($.noop, $.noop); } | |
| 132 | + var doc = this.findBy("slug", slug); | |
| 133 | + if (doc.isOutdated(status)) { | |
| 134 | + doc.install($.noop, $.noop); | |
| 135 | + } | |
| 113 | 136 | } |
| 114 | 137 | }); |
| 115 | 138 | } |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | */ |
| 8 | 8 | const Cls = (app.collections.Entries = class Entries extends app.Collection { |
| 9 | 9 | static initClass() { |
| 10 | − this.model = 'Entry'; | |
| 10 | + this.model = "Entry"; | |
| 11 | 11 | } |
| 12 | 12 | }); |
| 13 | 13 | Cls.initClass(); |
| @@ -8,14 +8,15 @@ · 7 unmodified lines | ||
| 8 | 8 | * DS206: Consider reworking classes to avoid initClass |
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | −(function() { | |
| 11 | +(function () { | |
| 12 | 12 | let GUIDES_RGX = undefined; |
| 13 | 13 | let APPENDIX_RGX = undefined; |
| 14 | 14 | const Cls = (app.collections.Types = class Types extends app.Collection { |
| 15 | 15 | static initClass() { |
| 16 | − this.model = 'Type'; | |
| 17 | − | |
| 18 | − GUIDES_RGX = /(^|\()(guides?|tutorials?|reference|book|getting\ started|manual|examples)($|[\):])/i; | |
| 16 | + this.model = "Type"; | |
| 17 | + | |
| 18 | + GUIDES_RGX = | |
| 19 | + /(^|\()(guides?|tutorials?|reference|book|getting\ started|manual|examples)($|[\):])/i; | |
| 19 | 20 | APPENDIX_RGX = /appendix/i; |
| 20 | 21 | } |
| 21 | 22 | |
| @@ -23,9 +24,11 @@ · 1 unmodified line | ||
| 23 | 24 | const result = []; |
| 24 | 25 | for (var type of Array.from(this.models)) { |
| 25 | 26 | var name; |
| 26 | − (result[name = this._groupFor(type)] || (result[name] = [])).push(type); | |
| 27 | + (result[(name = this._groupFor(type))] || (result[name] = [])).push( | |
| 28 | + type, | |
| 29 | + ); | |
| 27 | 30 | } |
| 28 | − return result.filter(e => e.length > 0); | |
| 31 | + return result.filter((e) => e.length > 0); | |
| 29 | 32 | } |
| 30 | 33 | |
| 31 | 34 | _groupFor(type) { |
| @@ -9,26 +9,33 @@ · 8 unmodified lines | ||
| 9 | 9 | * DS209: Avoid top-level return |
| 10 | 10 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 11 | 11 | */ |
| 12 | −if (!(typeof console !== 'undefined' && console !== null ? console.time : undefined) || !console.groupCollapsed) { return; } | |
| 12 | +if ( | |
| 13 | + !(typeof console !== "undefined" && console !== null | |
| 14 | + ? console.time | |
| 15 | + : undefined) || | |
| 16 | + !console.groupCollapsed | |
| 17 | +) { | |
| 18 | + return; | |
| 19 | +} | |
| 13 | 20 | |
| 14 | 21 | // |
| 15 | 22 | // App |
| 16 | 23 | // |
| 17 | 24 | |
| 18 | 25 | const _init = app.init; |
| 19 | −app.init = function() { | |
| 20 | − console.time('Init'); | |
| 26 | +app.init = function () { | |
| 27 | + console.time("Init"); | |
| 21 | 28 | _init.call(app); |
| 22 | − console.timeEnd('Init'); | |
| 23 | − return console.time('Load'); | |
| 29 | + console.timeEnd("Init"); | |
| 30 | + return console.time("Load"); | |
| 24 | 31 | }; |
| 25 | 32 | |
| 26 | 33 | const _start = app.start; |
| 27 | −app.start = function() { | |
| 28 | − console.timeEnd('Load'); | |
| 29 | − console.time('Start'); | |
| 34 | +app.start = function () { | |
| 35 | + console.timeEnd("Load"); | |
| 36 | + console.time("Start"); | |
| 30 | 37 | _start.call(app, ...arguments); |
| 31 | − return console.timeEnd('Start'); | |
| 38 | + return console.timeEnd("Start"); | |
| 32 | 39 | }; |
| 33 | 40 | |
| 34 | 41 | // |
| @@ -38,47 +45,50 @@ app.start = function() { · 3 unmodified lines | ||
| 38 | 45 | const _super = app.Searcher; |
| 39 | 46 | const _proto = app.Searcher.prototype; |
| 40 | 47 | |
| 41 | −app.Searcher = function() { | |
| 48 | +app.Searcher = function () { | |
| 42 | 49 | _super.apply(this, arguments); |
| 43 | 50 | |
| 44 | 51 | const _setup = this.setup.bind(this); |
| 45 | − this.setup = function() { | |
| 52 | + this.setup = function () { | |
| 46 | 53 | console.groupCollapsed(`Search: ${this.query}`); |
| 47 | − console.time('Total'); | |
| 54 | + console.time("Total"); | |
| 48 | 55 | return _setup(); |
| 49 | 56 | }; |
| 50 | 57 | |
| 51 | 58 | const _match = this.match.bind(this); |
| 52 | 59 | this.match = () => { |
| 53 | − if (this.matcher) { console.timeEnd(this.matcher.name); } | |
| 60 | + if (this.matcher) { | |
| 61 | + console.timeEnd(this.matcher.name); | |
| 62 | + } | |
| 54 | 63 | return _match(); |
| 55 | 64 | }; |
| 56 | 65 | |
| 57 | 66 | const _setupMatcher = this.setupMatcher.bind(this); |
| 58 | − this.setupMatcher = function() { | |
| 67 | + this.setupMatcher = function () { | |
| 59 | 68 | console.time(this.matcher.name); |
| 60 | 69 | return _setupMatcher(); |
| 61 | 70 | }; |
| 62 | 71 | |
| 63 | 72 | const _end = this.end.bind(this); |
| 64 | − this.end = function() { | |
| 73 | + this.end = function () { | |
| 65 | 74 | console.log(`Results: ${this.totalResults}`); |
| 66 | − console.timeEnd('Total'); | |
| 75 | + console.timeEnd("Total"); | |
| 67 | 76 | console.groupEnd(); |
| 68 | 77 | return _end(); |
| 69 | 78 | }; |
| 70 | 79 | |
| 71 | 80 | const _kill = this.kill.bind(this); |
| 72 | − this.kill = function() { | |
| 81 | + this.kill = function () { | |
| 73 | 82 | if (this.timeout) { |
| 74 | − if (this.matcher) { console.timeEnd(this.matcher.name); } | |
| 83 | + if (this.matcher) { | |
| 84 | + console.timeEnd(this.matcher.name); | |
| 85 | + } | |
| 75 | 86 | console.groupEnd(); |
| 76 | − console.timeEnd('Total'); | |
| 77 | − console.warn('Killed'); | |
| 87 | + console.timeEnd("Total"); | |
| 88 | + console.warn("Killed"); | |
| 78 | 89 | } |
| 79 | 90 | return _kill(); |
| 80 | 91 | }; |
| 81 | − | |
| 82 | 92 | }; |
| 83 | 93 | |
| 84 | 94 | $.extend(app.Searcher, _super); |
| @@ -89,23 +99,40 @@ app.Searcher.prototype = _proto; · 4 unmodified lines | ||
| 89 | 99 | // View tree |
| 90 | 100 | // |
| 91 | 101 | |
| 92 | −this.viewTree = function(view, level, visited) { | |
| 93 | − if (view == null) { view = app.document; } | |
| 94 | − if (level == null) { level = 0; } | |
| 95 | − if (visited == null) { visited = []; } | |
| 96 | − if (visited.indexOf(view) >= 0) { return; } | |
| 102 | +this.viewTree = function (view, level, visited) { | |
| 103 | + if (view == null) { | |
| 104 | + view = app.document; | |
| 105 | + } | |
| 106 | + if (level == null) { | |
| 107 | + level = 0; | |
| 108 | + } | |
| 109 | + if (visited == null) { | |
| 110 | + visited = []; | |
| 111 | + } | |
| 112 | + if (visited.indexOf(view) >= 0) { | |
| 113 | + return; | |
| 114 | + } | |
| 97 | 115 | visited.push(view); |
| 98 | 116 | |
| 99 | − console.log(`%c ${Array(level + 1).join(' ')}${view.constructor.name}: ${!!view.activated}`, | |
| 100 | − 'color:' + ((view.activated && 'green') || 'red')); | |
| 117 | + console.log( | |
| 118 | + `%c ${Array(level + 1).join(" ")}${ | |
| 119 | + view.constructor.name | |
| 120 | + }: ${!!view.activated}`, | |
| 121 | + "color:" + ((view.activated && "green") || "red"), | |
| 122 | + ); | |
| 101 | 123 | |
| 102 | 124 | for (var key of Object.keys(view || {})) { |
| 103 | 125 | var value = view[key]; |
| 104 | − if ((key !== 'view') && value) { | |
| 105 | − if ((typeof value === 'object') && value.setupElement) { | |
| 126 | + if (key !== "view" && value) { | |
| 127 | + if (typeof value === "object" && value.setupElement) { | |
| 106 | 128 | this.viewTree(value, level + 1, visited); |
| 107 | 129 | } else if (value.constructor.toString().match(/Object\(\)/)) { |
| 108 | − for (var k of Object.keys(value || {})) { var v = value[k]; if (v && (typeof v === 'object') && v.setupElement) { this.viewTree(v, level + 1, visited); } } | |
| 130 | + for (var k of Object.keys(value || {})) { | |
| 131 | + var v = value[k]; | |
| 132 | + if (v && typeof v === "object" && v.setupElement) { | |
| 133 | + this.viewTree(v, level + 1, visited); | |
| 134 | + } | |
| 135 | + } | |
| 109 | 136 | } |
| 110 | 137 | } |
| 111 | 138 | } |
| @@ -9,11 +9,11 @@ · 8 unmodified lines | ||
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | 11 | const MIME_TYPES = { |
| 12 | − json: 'application/json', | |
| 13 | − html: 'text/html' | |
| 12 | + json: "application/json", | |
| 13 | + html: "text/html", | |
| 14 | 14 | }; |
| 15 | 15 | |
| 16 | −this.ajax = function(options) { | |
| 16 | +this.ajax = function (options) { | |
| 17 | 17 | applyDefaults(options); |
| 18 | 18 | serializeData(options); |
| 19 | 19 | |
| @@ -26,7 +26,7 @@ this.ajax = function(options) { · 6 unmodified lines | ||
| 26 | 26 | xhr.send(options.data); |
| 27 | 27 | |
| 28 | 28 | if (options.async) { |
| 29 | − return {abort: abort.bind(undefined, xhr)}; | |
| 29 | + return { abort: abort.bind(undefined, xhr) }; | |
| 30 | 30 | } else { |
| 31 | 31 | return parseResponse(xhr, options); |
| 32 | 32 | } |
| @@ -34,51 +34,63 @@ this.ajax = function(options) { · 1 unmodified line | ||
| 34 | 34 | |
| 35 | 35 | ajax.defaults = { |
| 36 | 36 | async: true, |
| 37 | − dataType: 'json', | |
| 37 | + dataType: "json", | |
| 38 | 38 | timeout: 30, |
| 39 | − type: 'GET' | |
| 39 | + type: "GET", | |
| 40 | 40 | }; |
| 41 | − // contentType | |
| 42 | − // context | |
| 43 | − // data | |
| 44 | − // error | |
| 45 | − // headers | |
| 46 | − // progress | |
| 47 | − // success | |
| 48 | − // url | |
| 49 | − | |
| 50 | −var applyDefaults = function(options) { | |
| 41 | +// contentType | |
| 42 | +// context | |
| 43 | +// data | |
| 44 | +// error | |
| 45 | +// headers | |
| 46 | +// progress | |
| 47 | +// success | |
| 48 | +// url | |
| 49 | + | |
| 50 | +var applyDefaults = function (options) { | |
| 51 | 51 | for (var key in ajax.defaults) { |
| 52 | − if (options[key] == null) { options[key] = ajax.defaults[key]; } | |
| 52 | + if (options[key] == null) { | |
| 53 | + options[key] = ajax.defaults[key]; | |
| 54 | + } | |
| 53 | 55 | } |
| 54 | 56 | }; |
| 55 | 57 | |
| 56 | −var serializeData = function(options) { | |
| 57 | − if (!options.data) { return; } | |
| 58 | +var serializeData = function (options) { | |
| 59 | + if (!options.data) { | |
| 60 | + return; | |
| 61 | + } | |
| 58 | 62 | |
| 59 | − if (options.type === 'GET') { | |
| 60 | − options.url += '?' + serializeParams(options.data); | |
| 63 | + if (options.type === "GET") { | |
| 64 | + options.url += "?" + serializeParams(options.data); | |
| 61 | 65 | options.data = null; |
| 62 | 66 | } else { |
| 63 | 67 | options.data = serializeParams(options.data); |
| 64 | 68 | } |
| 65 | 69 | }; |
| 66 | 70 | |
| 67 | −var serializeParams = params => ((() => { | |
| 68 | − const result = []; | |
| 69 | − for (var key in params) { | |
| 70 | − var value = params[key]; | |
| 71 | − result.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); | |
| 72 | − } | |
| 73 | − return result; | |
| 74 | −})()).join('&'); | |
| 71 | +var serializeParams = (params) => | |
| 72 | + (() => { | |
| 73 | + const result = []; | |
| 74 | + for (var key in params) { | |
| 75 | + var value = params[key]; | |
| 76 | + result.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); | |
| 77 | + } | |
| 78 | + return result; | |
| 79 | + })().join("&"); | |
| 75 | 80 | |
| 76 | −var applyCallbacks = function(xhr, options) { | |
| 77 | − if (!options.async) { return; } | |
| 81 | +var applyCallbacks = function (xhr, options) { | |
| 82 | + if (!options.async) { | |
| 83 | + return; | |
| 84 | + } | |
| 78 | 85 | |
| 79 | − xhr.timer = setTimeout(onTimeout.bind(undefined, xhr, options), options.timeout * 1000); | |
| 80 | − if (options.progress) { xhr.onprogress = options.progress; } | |
| 81 | − xhr.onreadystatechange = function() { | |
| 86 | + xhr.timer = setTimeout( | |
| 87 | + onTimeout.bind(undefined, xhr, options), | |
| 88 | + options.timeout * 1000, | |
| 89 | + ); | |
| 90 | + if (options.progress) { | |
| 91 | + xhr.onprogress = options.progress; | |
| 92 | + } | |
| 93 | + xhr.onreadystatechange = function () { | |
| 82 | 94 | if (xhr.readyState === 4) { |
| 83 | 95 | clearTimeout(xhr.timer); |
| 84 | 96 | onComplete(xhr, options); |
| @@ -86,19 +98,26 @@ var applyCallbacks = function(xhr, options) { · 1 unmodified line | ||
| 86 | 98 | }; |
| 87 | 99 | }; |
| 88 | 100 | |
| 89 | −var applyHeaders = function(xhr, options) { | |
| 90 | − if (!options.headers) { options.headers = {}; } | |
| 101 | +var applyHeaders = function (xhr, options) { | |
| 102 | + if (!options.headers) { | |
| 103 | + options.headers = {}; | |
| 104 | + } | |
| 91 | 105 | |
| 92 | 106 | if (options.contentType) { |
| 93 | − options.headers['Content-Type'] = options.contentType; | |
| 107 | + options.headers["Content-Type"] = options.contentType; | |
| 94 | 108 | } |
| 95 | 109 | |
| 96 | − if (!options.headers['Content-Type'] && options.data && (options.type !== 'GET')) { | |
| 97 | − options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; | |
| 110 | + if ( | |
| 111 | + !options.headers["Content-Type"] && | |
| 112 | + options.data && | |
| 113 | + options.type !== "GET" | |
| 114 | + ) { | |
| 115 | + options.headers["Content-Type"] = "application/x-www-form-urlencoded"; | |
| 98 | 116 | } |
| 99 | 117 | |
| 100 | 118 | if (options.dataType) { |
| 101 | − options.headers['Accept'] = MIME_TYPES[options.dataType] || options.dataType; | |
| 119 | + options.headers["Accept"] = | |
| 120 | + MIME_TYPES[options.dataType] || options.dataType; | |
| 102 | 121 | } |
| 103 | 122 | |
| 104 | 123 | for (var key in options.headers) { |
| @@ -107,50 +126,52 @@ var applyHeaders = function(xhr, options) { · 2 unmodified lines | ||
| 107 | 126 | } |
| 108 | 127 | }; |
| 109 | 128 | |
| 110 | −var onComplete = function(xhr, options) { | |
| 129 | +var onComplete = function (xhr, options) { | |
| 111 | 130 | if (200 <= xhr.status && xhr.status < 300) { |
| 112 | 131 | let response; |
| 113 | 132 | if ((response = parseResponse(xhr, options)) != null) { |
| 114 | 133 | onSuccess(response, xhr, options); |
| 115 | 134 | } else { |
| 116 | − onError('invalid', xhr, options); | |
| 135 | + onError("invalid", xhr, options); | |
| 117 | 136 | } |
| 118 | 137 | } else { |
| 119 | − onError('error', xhr, options); | |
| 138 | + onError("error", xhr, options); | |
| 120 | 139 | } |
| 121 | 140 | }; |
| 122 | 141 | |
| 123 | −var onSuccess = function(response, xhr, options) { | |
| 142 | +var onSuccess = function (response, xhr, options) { | |
| 124 | 143 | if (options.success != null) { |
| 125 | 144 | options.success.call(options.context, response, xhr, options); |
| 126 | 145 | } |
| 127 | 146 | }; |
| 128 | 147 | |
| 129 | −var onError = function(type, xhr, options) { | |
| 148 | +var onError = function (type, xhr, options) { | |
| 130 | 149 | if (options.error != null) { |
| 131 | 150 | options.error.call(options.context, type, xhr, options); |
| 132 | 151 | } |
| 133 | 152 | }; |
| 134 | 153 | |
| 135 | −var onTimeout = function(xhr, options) { | |
| 154 | +var onTimeout = function (xhr, options) { | |
| 136 | 155 | xhr.abort(); |
| 137 | − onError('timeout', xhr, options); | |
| 156 | + onError("timeout", xhr, options); | |
| 138 | 157 | }; |
| 139 | 158 | |
| 140 | −var abort = function(xhr) { | |
| 159 | +var abort = function (xhr) { | |
| 141 | 160 | clearTimeout(xhr.timer); |
| 142 | 161 | xhr.onreadystatechange = null; |
| 143 | 162 | xhr.abort(); |
| 144 | 163 | }; |
| 145 | 164 | |
| 146 | −var parseResponse = function(xhr, options) { | |
| 147 | − if (options.dataType === 'json') { | |
| 165 | +var parseResponse = function (xhr, options) { | |
| 166 | + if (options.dataType === "json") { | |
| 148 | 167 | return parseJSON(xhr.responseText); |
| 149 | 168 | } else { |
| 150 | 169 | return xhr.responseText; |
| 151 | 170 | } |
| 152 | 171 | }; |
| 153 | 172 | |
| 154 | −var parseJSON = function(json) { | |
| 155 | − try { return JSON.parse(json); } catch (error) {} | |
| 173 | +var parseJSON = function (json) { | |
| 174 | + try { | |
| 175 | + return JSON.parse(json); | |
| 176 | + } catch (error) {} | |
| 156 | 177 | }; |
| @@ -8,14 +8,14 @@ · 7 unmodified lines | ||
| 8 | 8 | * DS207: Consider shorter variations of null checks |
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | −(function() { | |
| 11 | +(function () { | |
| 12 | 12 | let INT = undefined; |
| 13 | 13 | const Cls = (this.CookiesStore = class CookiesStore { |
| 14 | 14 | static initClass() { |
| 15 | 15 | // Intentionally called CookiesStore instead of CookieStore |
| 16 | 16 | // Calling it CookieStore causes issues when the Experimental Web Platform features flag is enabled in Chrome |
| 17 | 17 | // Related issue: https://github.com/freeCodeCamp/devdocs/issues/932 |
| 18 | − | |
| 18 | + | |
| 19 | 19 | INT = /^\d+$/; |
| 20 | 20 | } |
| 21 | 21 | |
| @@ -23,7 +23,9 @@ · 1 unmodified line | ||
| 23 | 23 | |
| 24 | 24 | get(key) { |
| 25 | 25 | let value = Cookies.get(key); |
| 26 | − if ((value != null) && INT.test(value)) { value = parseInt(value, 10); } | |
| 26 | + if (value != null && INT.test(value)) { | |
| 27 | + value = parseInt(value, 10); | |
| 28 | + } | |
| 27 | 29 | return value; |
| 28 | 30 | } |
| 29 | 31 | |
| @@ -33,10 +35,19 @@ · 3 unmodified lines | ||
| 33 | 35 | return; |
| 34 | 36 | } |
| 35 | 37 | |
| 36 | − if (value === true) { value = 1; } | |
| 37 | − if (value && (typeof INT.test === 'function' ? INT.test(value) : undefined)) { value = parseInt(value, 10); } | |
| 38 | − Cookies.set(key, '' + value, {path: '/', expires: 1e8}); | |
| 39 | − if (this.get(key) !== value) { this.constructor.onBlocked(key, value, this.get(key)); } | |
| 38 | + if (value === true) { | |
| 39 | + value = 1; | |
| 40 | + } | |
| 41 | + if ( | |
| 42 | + value && | |
| 43 | + (typeof INT.test === "function" ? INT.test(value) : undefined) | |
| 44 | + ) { | |
| 45 | + value = parseInt(value, 10); | |
| 46 | + } | |
| 47 | + Cookies.set(key, "" + value, { path: "/", expires: 1e8 }); | |
| 48 | + if (this.get(key) !== value) { | |
| 49 | + this.constructor.onBlocked(key, value, this.get(key)); | |
| 50 | + } | |
| 40 | 51 | } |
| 41 | 52 | |
| 42 | 53 | del(key) { |
| @@ -46,7 +57,7 @@ · 3 unmodified lines | ||
| 46 | 57 | reset() { |
| 47 | 58 | try { |
| 48 | 59 | for (var cookie of Array.from(document.cookie.split(/;\s?/))) { |
| 49 | − Cookies.expire(cookie.split('=')[0]); | |
| 60 | + Cookies.expire(cookie.split("=")[0]); | |
| 50 | 61 | } |
| 51 | 62 | return; |
| 52 | 63 | } catch (error) {} |
| @@ -55,8 +66,8 @@ · 2 unmodified lines | ||
| 55 | 66 | dump() { |
| 56 | 67 | const result = {}; |
| 57 | 68 | for (var cookie of Array.from(document.cookie.split(/;\s?/))) { |
| 58 | − if (cookie[0] !== '_') { | |
| 59 | − cookie = cookie.split('='); | |
| 69 | + if (cookie[0] !== "_") { | |
| 70 | + cookie = cookie.split("="); | |
| 60 | 71 | result[cookie[0]] = cookie[1]; |
| 61 | 72 | } |
| 62 | 73 | } |
| @@ -11,22 +11,38 @@ · 10 unmodified lines | ||
| 11 | 11 | */ |
| 12 | 12 | this.Events = { |
| 13 | 13 | on(event, callback) { |
| 14 | − if (event.indexOf(' ') >= 0) { | |
| 15 | − for (var name of Array.from(event.split(' '))) { this.on(name, callback); } | |
| 14 | + if (event.indexOf(" ") >= 0) { | |
| 15 | + for (var name of Array.from(event.split(" "))) { | |
| 16 | + this.on(name, callback); | |
| 17 | + } | |
| 16 | 18 | } else { |
| 17 | 19 | let base; |
| 18 | − (((base = this._callbacks != null ? this._callbacks : (this._callbacks = {})))[event] != null ? base[event] : (base[event] = [])).push(callback); | |
| 20 | + ((base = | |
| 21 | + this._callbacks != null ? this._callbacks : (this._callbacks = {}))[ | |
| 22 | + event | |
| 23 | + ] != null | |
| 24 | + ? base[event] | |
| 25 | + : (base[event] = []) | |
| 26 | + ).push(callback); | |
| 19 | 27 | } |
| 20 | 28 | return this; |
| 21 | 29 | }, |
| 22 | 30 | |
| 23 | 31 | off(event, callback) { |
| 24 | 32 | let callbacks, index; |
| 25 | − if (event.indexOf(' ') >= 0) { | |
| 26 | − for (var name of Array.from(event.split(' '))) { this.off(name, callback); } | |
| 27 | − } else if ((callbacks = this._callbacks != null ? this._callbacks[event] : undefined) && ((index = callbacks.indexOf(callback)) >= 0)) { | |
| 33 | + if (event.indexOf(" ") >= 0) { | |
| 34 | + for (var name of Array.from(event.split(" "))) { | |
| 35 | + this.off(name, callback); | |
| 36 | + } | |
| 37 | + } else if ( | |
| 38 | + (callbacks = | |
| 39 | + this._callbacks != null ? this._callbacks[event] : undefined) && | |
| 40 | + (index = callbacks.indexOf(callback)) >= 0 | |
| 41 | + ) { | |
| 28 | 42 | callbacks.splice(index, 1); |
| 29 | − if (!callbacks.length) { delete this._callbacks[event]; } | |
| 43 | + if (!callbacks.length) { | |
| 44 | + delete this._callbacks[event]; | |
| 45 | + } | |
| 30 | 46 | } |
| 31 | 47 | return this; |
| 32 | 48 | }, |
| @@ -34,20 +50,28 @@ this.Events = { · 1 unmodified line | ||
| 34 | 50 | trigger(event, ...args) { |
| 35 | 51 | let callbacks; |
| 36 | 52 | this.eventInProgress = { name: event, args }; |
| 37 | − if (callbacks = this._callbacks != null ? this._callbacks[event] : undefined) { | |
| 38 | − for (var callback of Array.from(callbacks.slice(0))) { if (typeof callback === 'function') { | |
| 39 | − callback(...Array.from(args || [])); | |
| 40 | − } } | |
| 53 | + if ( | |
| 54 | + (callbacks = this._callbacks != null ? this._callbacks[event] : undefined) | |
| 55 | + ) { | |
| 56 | + for (var callback of Array.from(callbacks.slice(0))) { | |
| 57 | + if (typeof callback === "function") { | |
| 58 | + callback(...Array.from(args || [])); | |
| 59 | + } | |
| 60 | + } | |
| 41 | 61 | } |
| 42 | 62 | this.eventInProgress = null; |
| 43 | − if (event !== 'all') { this.trigger('all', event, ...Array.from(args)); } | |
| 63 | + if (event !== "all") { | |
| 64 | + this.trigger("all", event, ...Array.from(args)); | |
| 65 | + } | |
| 44 | 66 | return this; |
| 45 | 67 | }, |
| 46 | 68 | |
| 47 | 69 | removeEvent(event) { |
| 48 | 70 | if (this._callbacks != null) { |
| 49 | − for (var name of Array.from(event.split(' '))) { delete this._callbacks[name]; } | |
| 71 | + for (var name of Array.from(event.split(" "))) { | |
| 72 | + delete this._callbacks[name]; | |
| 73 | + } | |
| 50 | 74 | } |
| 51 | 75 | return this; |
| 52 | − } | |
| 76 | + }, | |
| 53 | 77 | }; |
| @@ -12,22 +12,24 @@ let currentSlug = null; · 11 unmodified lines | ||
| 12 | 12 | const imageCache = {}; |
| 13 | 13 | const urlCache = {}; |
| 14 | 14 | |
| 15 | −const withImage = function(url, action) { | |
| 15 | +const withImage = function (url, action) { | |
| 16 | 16 | if (imageCache[url]) { |
| 17 | 17 | return action(imageCache[url]); |
| 18 | 18 | } else { |
| 19 | 19 | const img = new Image(); |
| 20 | − img.crossOrigin = 'anonymous'; | |
| 20 | + img.crossOrigin = "anonymous"; | |
| 21 | 21 | img.src = url; |
| 22 | − return img.onload = () => { | |
| 22 | + return (img.onload = () => { | |
| 23 | 23 | imageCache[url] = img; |
| 24 | 24 | return action(img); |
| 25 | − }; | |
| 25 | + }); | |
| 26 | 26 | } |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | −this.setFaviconForDoc = function(doc) { | |
| 30 | − if (currentSlug === doc.slug) { return; } | |
| 29 | +this.setFaviconForDoc = function (doc) { | |
| 30 | + if (currentSlug === doc.slug) { | |
| 31 | + return; | |
| 32 | + } | |
| 31 | 33 | |
| 32 | 34 | const favicon = $('link[rel="icon"]'); |
| 33 | 35 | |
| @@ -41,51 +43,67 @@ this.setFaviconForDoc = function(doc) { · 7 unmodified lines | ||
| 41 | 43 | return; |
| 42 | 44 | } |
| 43 | 45 | |
| 44 | − const iconEl = $(`._icon-${doc.slug.split('~')[0]}`); | |
| 45 | − if (iconEl === null) { return; } | |
| 46 | + const iconEl = $(`._icon-${doc.slug.split("~")[0]}`); | |
| 47 | + if (iconEl === null) { | |
| 48 | + return; | |
| 49 | + } | |
| 46 | 50 | |
| 47 | − const styles = window.getComputedStyle(iconEl, ':before'); | |
| 51 | + const styles = window.getComputedStyle(iconEl, ":before"); | |
| 48 | 52 | |
| 49 | − const backgroundPositionX = styles['background-position-x']; | |
| 50 | − const backgroundPositionY = styles['background-position-y']; | |
| 51 | − if ((backgroundPositionX === undefined) || (backgroundPositionY === undefined)) { return; } | |
| 53 | + const backgroundPositionX = styles["background-position-x"]; | |
| 54 | + const backgroundPositionY = styles["background-position-y"]; | |
| 55 | + if (backgroundPositionX === undefined || backgroundPositionY === undefined) { | |
| 56 | + return; | |
| 57 | + } | |
| 52 | 58 | |
| 53 | 59 | const bgUrl = app.config.favicon_spritesheet; |
| 54 | 60 | const sourceSize = 16; |
| 55 | 61 | const sourceX = Math.abs(parseInt(backgroundPositionX.slice(0, -2))); |
| 56 | 62 | const sourceY = Math.abs(parseInt(backgroundPositionY.slice(0, -2))); |
| 57 | 63 | |
| 58 | − return withImage(bgUrl, docImg => withImage(defaultUrl, function(defaultImg) { | |
| 59 | − const size = defaultImg.width; | |
| 60 | − | |
| 61 | − const canvas = document.createElement('canvas'); | |
| 62 | − const ctx = canvas.getContext('2d'); | |
| 63 | − | |
| 64 | − canvas.width = size; | |
| 65 | − canvas.height = size; | |
| 66 | − ctx.drawImage(defaultImg, 0, 0); | |
| 67 | − | |
| 68 | − const docIconPercentage = 65; | |
| 69 | − const destinationCoords = (size / 100) * (100 - docIconPercentage); | |
| 70 | − const destinationSize = (size / 100) * docIconPercentage; | |
| 71 | − | |
| 72 | − ctx.drawImage(docImg, sourceX, sourceY, sourceSize, sourceSize, destinationCoords, destinationCoords, destinationSize, destinationSize); | |
| 73 | − | |
| 74 | − try { | |
| 75 | − urlCache[doc.slug] = canvas.toDataURL(); | |
| 76 | − favicon.href = urlCache[doc.slug]; | |
| 77 | − | |
| 78 | − return currentSlug = doc.slug; | |
| 79 | − } catch (error) { | |
| 80 | − Raven.captureException(error, { level: 'info' }); | |
| 81 | − return this.resetFavicon(); | |
| 82 | − } | |
| 83 | − })); | |
| 64 | + return withImage(bgUrl, (docImg) => | |
| 65 | + withImage(defaultUrl, function (defaultImg) { | |
| 66 | + const size = defaultImg.width; | |
| 67 | + | |
| 68 | + const canvas = document.createElement("canvas"); | |
| 69 | + const ctx = canvas.getContext("2d"); | |
| 70 | + | |
| 71 | + canvas.width = size; | |
| 72 | + canvas.height = size; | |
| 73 | + ctx.drawImage(defaultImg, 0, 0); | |
| 74 | + | |
| 75 | + const docIconPercentage = 65; | |
| 76 | + const destinationCoords = (size / 100) * (100 - docIconPercentage); | |
| 77 | + const destinationSize = (size / 100) * docIconPercentage; | |
| 78 | + | |
| 79 | + ctx.drawImage( | |
| 80 | + docImg, | |
| 81 | + sourceX, | |
| 82 | + sourceY, | |
| 83 | + sourceSize, | |
| 84 | + sourceSize, | |
| 85 | + destinationCoords, | |
| 86 | + destinationCoords, | |
| 87 | + destinationSize, | |
| 88 | + destinationSize, | |
| 89 | + ); | |
| 90 | + | |
| 91 | + try { | |
| 92 | + urlCache[doc.slug] = canvas.toDataURL(); | |
| 93 | + favicon.href = urlCache[doc.slug]; | |
| 94 | + | |
| 95 | + return (currentSlug = doc.slug); | |
| 96 | + } catch (error) { | |
| 97 | + Raven.captureException(error, { level: "info" }); | |
| 98 | + return this.resetFavicon(); | |
| 99 | + } | |
| 100 | + }), | |
| 101 | + ); | |
| 84 | 102 | }; |
| 85 | 103 | |
| 86 | −this.resetFavicon = function() { | |
| 87 | − if ((defaultUrl !== null) && (currentSlug !== null)) { | |
| 104 | +this.resetFavicon = function () { | |
| 105 | + if (defaultUrl !== null && currentSlug !== null) { | |
| 88 | 106 | $('link[rel="icon"]').href = defaultUrl; |
| 89 | − return currentSlug = null; | |
| 107 | + return (currentSlug = null); | |
| 90 | 108 | } |
| 91 | 109 | }; |
| @@ -6,4 +6,4 @@ · 5 unmodified lines | ||
| 6 | 6 | * This source code is licensed under the terms of the Mozilla |
| 7 | 7 | * Public License, v. 2.0, a copy of which may be obtained at: |
| 8 | 8 | * http://mozilla.org/MPL/2.0/ |
| 9 | −*/ | |
| 9 | + */ | |
| @@ -13,50 +13,54 @@ · 12 unmodified lines | ||
| 13 | 13 | * Based on github.com/visionmedia/page.js |
| 14 | 14 | * Licensed under the MIT license |
| 15 | 15 | * Copyright 2012 TJ Holowaychuk <tj@vision-media.ca> |
| 16 | −*/ | |
| 16 | + */ | |
| 17 | 17 | |
| 18 | 18 | let running = false; |
| 19 | 19 | let currentState = null; |
| 20 | 20 | const callbacks = []; |
| 21 | 21 | |
| 22 | −this.page = function(value, fn) { | |
| 23 | − if (typeof value === 'function') { | |
| 24 | − page('*', value); | |
| 25 | − } else if (typeof fn === 'function') { | |
| 22 | +this.page = function (value, fn) { | |
| 23 | + if (typeof value === "function") { | |
| 24 | + page("*", value); | |
| 25 | + } else if (typeof fn === "function") { | |
| 26 | 26 | const route = new Route(value); |
| 27 | 27 | callbacks.push(route.middleware(fn)); |
| 28 | − } else if (typeof value === 'string') { | |
| 28 | + } else if (typeof value === "string") { | |
| 29 | 29 | page.show(value, fn); |
| 30 | 30 | } else { |
| 31 | 31 | page.start(value); |
| 32 | 32 | } |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | −page.start = function(options) { | |
| 36 | − if (options == null) { options = {}; } | |
| 35 | +page.start = function (options) { | |
| 36 | + if (options == null) { | |
| 37 | + options = {}; | |
| 38 | + } | |
| 37 | 39 | if (!running) { |
| 38 | 40 | running = true; |
| 39 | − addEventListener('popstate', onpopstate); | |
| 40 | − addEventListener('click', onclick); | |
| 41 | + addEventListener("popstate", onpopstate); | |
| 42 | + addEventListener("click", onclick); | |
| 41 | 43 | page.replace(currentPath(), null, null, true); |
| 42 | 44 | } |
| 43 | 45 | }; |
| 44 | 46 | |
| 45 | −page.stop = function() { | |
| 47 | +page.stop = function () { | |
| 46 | 48 | if (running) { |
| 47 | 49 | running = false; |
| 48 | − removeEventListener('click', onclick); | |
| 49 | − removeEventListener('popstate', onpopstate); | |
| 50 | + removeEventListener("click", onclick); | |
| 51 | + removeEventListener("popstate", onpopstate); | |
| 50 | 52 | } |
| 51 | 53 | }; |
| 52 | 54 | |
| 53 | −page.show = function(path, state) { | |
| 55 | +page.show = function (path, state) { | |
| 54 | 56 | let res; |
| 55 | − if (path === (currentState != null ? currentState.path : undefined)) { return; } | |
| 57 | + if (path === (currentState != null ? currentState.path : undefined)) { | |
| 58 | + return; | |
| 59 | + } | |
| 56 | 60 | const context = new Context(path, state); |
| 57 | 61 | const previousState = currentState; |
| 58 | 62 | currentState = context.state; |
| 59 | − if (res = page.dispatch(context)) { | |
| 63 | + if ((res = page.dispatch(context))) { | |
| 60 | 64 | currentState = previousState; |
| 61 | 65 | location.assign(res); |
| 62 | 66 | } else { |
| @@ -67,12 +71,14 @@ page.show = function(path, state) { · 4 unmodified lines | ||
| 67 | 71 | return context; |
| 68 | 72 | }; |
| 69 | 73 | |
| 70 | −page.replace = function(path, state, skipDispatch, init) { | |
| 74 | +page.replace = function (path, state, skipDispatch, init) { | |
| 71 | 75 | let result; |
| 72 | 76 | let context = new Context(path, state || currentState); |
| 73 | 77 | context.init = init; |
| 74 | 78 | currentState = context.state; |
| 75 | − if (!skipDispatch) { result = page.dispatch(context); } | |
| 79 | + if (!skipDispatch) { | |
| 80 | + result = page.dispatch(context); | |
| 81 | + } | |
| 76 | 82 | if (result) { |
| 77 | 83 | context = new Context(result); |
| 78 | 84 | context.init = init; |
| @@ -81,15 +87,19 @@ page.replace = function(path, state, skipDispatch, init) { · 2 unmodified lines | ||
| 81 | 87 | } |
| 82 | 88 | context.replaceState(); |
| 83 | 89 | updateCanonicalLink(); |
| 84 | − if (!skipDispatch) { track(); } | |
| 90 | + if (!skipDispatch) { | |
| 91 | + track(); | |
| 92 | + } | |
| 85 | 93 | return context; |
| 86 | 94 | }; |
| 87 | 95 | |
| 88 | −page.dispatch = function(context) { | |
| 96 | +page.dispatch = function (context) { | |
| 89 | 97 | let i = 0; |
| 90 | − var next = function() { | |
| 98 | + var next = function () { | |
| 91 | 99 | let fn, res; |
| 92 | − if (fn = callbacks[i++]) { res = fn(context, next); } | |
| 100 | + if ((fn = callbacks[i++])) { | |
| 101 | + res = fn(context, next); | |
| 102 | + } | |
| 93 | 103 | return res; |
| 94 | 104 | }; |
| 95 | 105 | return next(); |
| @@ -113,11 +123,11 @@ class Context { · 17 unmodified lines | ||
| 113 | 123 | } |
| 114 | 124 | |
| 115 | 125 | static isLastState(state) { |
| 116 | − return state.id === (this.stateId - 1); | |
| 126 | + return state.id === this.stateId - 1; | |
| 117 | 127 | } |
| 118 | 128 | |
| 119 | 129 | static isInitialPopState(state) { |
| 120 | − return (state.path === this.initialPath) && (this.stateId === 1); | |
| 130 | + return state.path === this.initialPath && this.stateId === 1; | |
| 121 | 131 | } |
| 122 | 132 | |
| 123 | 133 | static isSameSession(state) { |
| @@ -125,27 +135,40 @@ class Context { · 1 unmodified line | ||
| 125 | 135 | } |
| 126 | 136 | |
| 127 | 137 | constructor(path, state) { |
| 128 | − if (path == null) { path = '/'; } | |
| 138 | + if (path == null) { | |
| 139 | + path = "/"; | |
| 140 | + } | |
| 129 | 141 | this.path = path; |
| 130 | − if (state == null) { state = {}; } | |
| 142 | + if (state == null) { | |
| 143 | + state = {}; | |
| 144 | + } | |
| 131 | 145 | this.state = state; |
| 132 | − this.pathname = this.path.replace(/(?:\?([^#]*))?(?:#(.*))?$/, (_, query, hash) => { | |
| 133 | − this.query = query; | |
| 134 | − this.hash = hash; | |
| 135 | − return ''; | |
| 136 | − }); | |
| 137 | − | |
| 138 | − if (this.state.id == null) { this.state.id = this.constructor.stateId++; } | |
| 139 | − if (this.state.sessionId == null) { this.state.sessionId = this.constructor.sessionId; } | |
| 146 | + this.pathname = this.path.replace( | |
| 147 | + /(?:\?([^#]*))?(?:#(.*))?$/, | |
| 148 | + (_, query, hash) => { | |
| 149 | + this.query = query; | |
| 150 | + this.hash = hash; | |
| 151 | + return ""; | |
| 152 | + }, | |
| 153 | + ); | |
| 154 | + | |
| 155 | + if (this.state.id == null) { | |
| 156 | + this.state.id = this.constructor.stateId++; | |
| 157 | + } | |
| 158 | + if (this.state.sessionId == null) { | |
| 159 | + this.state.sessionId = this.constructor.sessionId; | |
| 160 | + } | |
| 140 | 161 | this.state.path = this.path; |
| 141 | 162 | } |
| 142 | 163 | |
| 143 | 164 | pushState() { |
| 144 | − history.pushState(this.state, '', this.path); | |
| 165 | + history.pushState(this.state, "", this.path); | |
| 145 | 166 | } |
| 146 | 167 | |
| 147 | 168 | replaceState() { |
| 148 | − try { history.replaceState(this.state, '', this.path); } catch (error) {} // NS_ERROR_FAILURE in Firefox | |
| 169 | + try { | |
| 170 | + history.replaceState(this.state, "", this.path); | |
| 171 | + } catch (error) {} // NS_ERROR_FAILURE in Firefox | |
| 149 | 172 | } |
| 150 | 173 | } |
| 151 | 174 | Context.initClass(); |
| @@ -153,7 +176,9 @@ Context.initClass(); · 1 unmodified line | ||
| 153 | 176 | class Route { |
| 154 | 177 | constructor(path, options) { |
| 155 | 178 | this.path = path; |
| 156 | − if (options == null) { options = {}; } | |
| 179 | + if (options == null) { | |
| 180 | + options = {}; | |
| 181 | + } | |
| 157 | 182 | this.keys = []; |
| 158 | 183 | this.regexp = pathtoRegexp(this.path, this.keys); |
| 159 | 184 | } |
| @@ -172,13 +197,17 @@ class Route { · 12 unmodified lines | ||
| 172 | 197 | |
| 173 | 198 | match(path, params) { |
| 174 | 199 | let matchData; |
| 175 | − if (!(matchData = this.regexp.exec(path))) { return; } | |
| 200 | + if (!(matchData = this.regexp.exec(path))) { | |
| 201 | + return; | |
| 202 | + } | |
| 176 | 203 | |
| 177 | 204 | const iterable = matchData.slice(1); |
| 178 | 205 | for (let i = 0; i < iterable.length; i++) { |
| 179 | 206 | var key; |
| 180 | 207 | var value = iterable[i]; |
| 181 | − if (typeof value === 'string') { value = decodeURIComponent(value); } | |
| 208 | + if (typeof value === "string") { | |
| 209 | + value = decodeURIComponent(value); | |
| 210 | + } | |
| 182 | 211 | if ((key = this.keys[i])) { |
| 183 | 212 | params[key.name] = value; |
| 184 | 213 | } else { |
| @@ -189,32 +218,50 @@ class Route { · 4 unmodified lines | ||
| 189 | 218 | } |
| 190 | 219 | } |
| 191 | 220 | |
| 192 | −var pathtoRegexp = function(path, keys) { | |
| 193 | − if (path instanceof RegExp) { return path; } | |
| 221 | +var pathtoRegexp = function (path, keys) { | |
| 222 | + if (path instanceof RegExp) { | |
| 223 | + return path; | |
| 224 | + } | |
| 194 | 225 | |
| 195 | − if (path instanceof Array) { path = `(${path.join('|')})`; } | |
| 226 | + if (path instanceof Array) { | |
| 227 | + path = `(${path.join("|")})`; | |
| 228 | + } | |
| 196 | 229 | path = path |
| 197 | − .replace(/\/\(/g, '(?:/') | |
| 198 | − .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional) { | |
| 199 | − if (slash == null) { slash = ''; } | |
| 200 | − if (format == null) { format = ''; } | |
| 201 | − keys.push({name: key, optional: !!optional}); | |
| 202 | − let str = optional ? '' : slash; | |
| 203 | − str += '(?:'; | |
| 204 | − if (optional) { str += slash; } | |
| 205 | − str += format; | |
| 206 | − str += capture || (format ? '([^/.]+?)' : '([^/]+?)'); | |
| 207 | − str += ')'; | |
| 208 | − if (optional) { str += optional; } | |
| 209 | − return str; | |
| 210 | − }).replace(/([\/.])/g, '\\$1') | |
| 211 | − .replace(/\*/g, '(.*)'); | |
| 230 | + .replace(/\/\(/g, "(?:/") | |
| 231 | + .replace( | |
| 232 | + /(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, | |
| 233 | + function (_, slash, format, key, capture, optional) { | |
| 234 | + if (slash == null) { | |
| 235 | + slash = ""; | |
| 236 | + } | |
| 237 | + if (format == null) { | |
| 238 | + format = ""; | |
| 239 | + } | |
| 240 | + keys.push({ name: key, optional: !!optional }); | |
| 241 | + let str = optional ? "" : slash; | |
| 242 | + str += "(?:"; | |
| 243 | + if (optional) { | |
| 244 | + str += slash; | |
| 245 | + } | |
| 246 | + str += format; | |
| 247 | + str += capture || (format ? "([^/.]+?)" : "([^/]+?)"); | |
| 248 | + str += ")"; | |
| 249 | + if (optional) { | |
| 250 | + str += optional; | |
| 251 | + } | |
| 252 | + return str; | |
| 253 | + }, | |
| 254 | + ) | |
| 255 | + .replace(/([\/.])/g, "\\$1") | |
| 256 | + .replace(/\*/g, "(.*)"); | |
| 212 | 257 | |
| 213 | 258 | return new RegExp(`^${path}$`); |
| 214 | 259 | }; |
| 215 | 260 | |
| 216 | −var onpopstate = function(event) { | |
| 217 | − if (!event.state || Context.isInitialPopState(event.state)) { return; } | |
| 261 | +var onpopstate = function (event) { | |
| 262 | + if (!event.state || Context.isInitialPopState(event.state)) { | |
| 263 | + return; | |
| 264 | + } | |
| 218 | 265 | |
| 219 | 266 | if (Context.isSameSession(event.state)) { |
| 220 | 267 | page.replace(event.state.path, event.state); |
| @@ -223,59 +270,83 @@ var onpopstate = function(event) { · 2 unmodified lines | ||
| 223 | 270 | } |
| 224 | 271 | }; |
| 225 | 272 | |
| 226 | −var onclick = function(event) { | |
| 273 | +var onclick = function (event) { | |
| 227 | 274 | try { |
| 228 | − if ((event.which !== 1) || event.metaKey || event.ctrlKey || event.shiftKey || event.defaultPrevented) { return; } | |
| 275 | + if ( | |
| 276 | + event.which !== 1 || | |
| 277 | + event.metaKey || | |
| 278 | + event.ctrlKey || | |
| 279 | + event.shiftKey || | |
| 280 | + event.defaultPrevented | |
| 281 | + ) { | |
| 282 | + return; | |
| 283 | + } | |
| 229 | 284 | } catch (error) { |
| 230 | 285 | return; |
| 231 | 286 | } |
| 232 | 287 | |
| 233 | 288 | let link = $.eventTarget(event); |
| 234 | − while (link && (link.tagName !== 'A')) { link = link.parentNode; } | |
| 289 | + while (link && link.tagName !== "A") { | |
| 290 | + link = link.parentNode; | |
| 291 | + } | |
| 235 | 292 | |
| 236 | 293 | if (link && !link.target && isSameOrigin(link.href)) { |
| 237 | 294 | event.preventDefault(); |
| 238 | 295 | let path = link.pathname + link.search + link.hash; |
| 239 | − path = path.replace(/^\/\/+/, '/'); // IE11 bug | |
| 296 | + path = path.replace(/^\/\/+/, "/"); // IE11 bug | |
| 240 | 297 | page.show(path); |
| 241 | 298 | } |
| 242 | 299 | }; |
| 243 | 300 | |
| 244 | −var isSameOrigin = url => url.indexOf(`${location.protocol}//${location.hostname}`) === 0; | |
| 301 | +var isSameOrigin = (url) => | |
| 302 | + url.indexOf(`${location.protocol}//${location.hostname}`) === 0; | |
| 245 | 303 | |
| 246 | −var updateCanonicalLink = function() { | |
| 247 | − if (!this.canonicalLink) { this.canonicalLink = document.head.querySelector('link[rel="canonical"]'); } | |
| 248 | − return this.canonicalLink.setAttribute('href', `https://${location.host}${location.pathname}`); | |
| 304 | +var updateCanonicalLink = function () { | |
| 305 | + if (!this.canonicalLink) { | |
| 306 | + this.canonicalLink = document.head.querySelector('link[rel="canonical"]'); | |
| 307 | + } | |
| 308 | + return this.canonicalLink.setAttribute( | |
| 309 | + "href", | |
| 310 | + `https://${location.host}${location.pathname}`, | |
| 311 | + ); | |
| 249 | 312 | }; |
| 250 | 313 | |
| 251 | 314 | const trackers = []; |
| 252 | 315 | |
| 253 | −page.track = function(fn) { | |
| 316 | +page.track = function (fn) { | |
| 254 | 317 | trackers.push(fn); |
| 255 | 318 | }; |
| 256 | 319 | |
| 257 | −var track = function() { | |
| 258 | − if (app.config.env !== 'production') { return; } | |
| 259 | − if (navigator.doNotTrack === '1') { return; } | |
| 260 | − if (navigator.globalPrivacyControl) { return; } | |
| 320 | +var track = function () { | |
| 321 | + if (app.config.env !== "production") { | |
| 322 | + return; | |
| 323 | + } | |
| 324 | + if (navigator.doNotTrack === "1") { | |
| 325 | + return; | |
| 326 | + } | |
| 327 | + if (navigator.globalPrivacyControl) { | |
| 328 | + return; | |
| 329 | + } | |
| 261 | 330 | |
| 262 | − const consentGiven = Cookies.get('analyticsConsent'); | |
| 263 | − const consentAsked = Cookies.get('analyticsConsentAsked'); | |
| 331 | + const consentGiven = Cookies.get("analyticsConsent"); | |
| 332 | + const consentAsked = Cookies.get("analyticsConsentAsked"); | |
| 264 | 333 | |
| 265 | − if (consentGiven === '1') { | |
| 266 | − for (var tracker of Array.from(trackers)) { tracker.call(); } | |
| 267 | − } else if ((consentGiven === undefined) && (consentAsked === undefined)) { | |
| 334 | + if (consentGiven === "1") { | |
| 335 | + for (var tracker of Array.from(trackers)) { | |
| 336 | + tracker.call(); | |
| 337 | + } | |
| 338 | + } else if (consentGiven === undefined && consentAsked === undefined) { | |
| 268 | 339 | // Only ask for consent once per browser session |
| 269 | − Cookies.set('analyticsConsentAsked', '1'); | |
| 340 | + Cookies.set("analyticsConsentAsked", "1"); | |
| 270 | 341 | |
| 271 | − new app.views.Notif('AnalyticsConsent', {autoHide: null}); | |
| 342 | + new app.views.Notif("AnalyticsConsent", { autoHide: null }); | |
| 272 | 343 | } |
| 273 | 344 | }; |
| 274 | 345 | |
| 275 | −this.resetAnalytics = function() { | |
| 346 | +this.resetAnalytics = function () { | |
| 276 | 347 | for (var cookie of Array.from(document.cookie.split(/;\s?/))) { |
| 277 | − var name = cookie.split('=')[0]; | |
| 278 | − if ((name[0] === '_') && (name[1] !== '_')) { | |
| 348 | + var name = cookie.split("=")[0]; | |
| 349 | + if (name[0] === "_" && name[1] !== "_") { | |
| 279 | 350 | Cookies.expire(name); |
| 280 | 351 | } |
| 281 | 352 | } |
| @@ -16,32 +16,52 @@ · 15 unmodified lines | ||
| 16 | 16 | // |
| 17 | 17 | |
| 18 | 18 | let smoothDistance, smoothDuration, smoothEnd, smoothStart; |
| 19 | −this.$ = function(selector, el) { | |
| 20 | − if (el == null) { el = document; } | |
| 21 | − try { return el.querySelector(selector); } catch (error) {} | |
| 19 | +this.$ = function (selector, el) { | |
| 20 | + if (el == null) { | |
| 21 | + el = document; | |
| 22 | + } | |
| 23 | + try { | |
| 24 | + return el.querySelector(selector); | |
| 25 | + } catch (error) {} | |
| 22 | 26 | }; |
| 23 | 27 | |
| 24 | −this.$$ = function(selector, el) { | |
| 25 | − if (el == null) { el = document; } | |
| 26 | − try { return el.querySelectorAll(selector); } catch (error) {} | |
| 28 | +this.$$ = function (selector, el) { | |
| 29 | + if (el == null) { | |
| 30 | + el = document; | |
| 31 | + } | |
| 32 | + try { | |
| 33 | + return el.querySelectorAll(selector); | |
| 34 | + } catch (error) {} | |
| 27 | 35 | }; |
| 28 | 36 | |
| 29 | −$.id = id => document.getElementById(id); | |
| 37 | +$.id = (id) => document.getElementById(id); | |
| 30 | 38 | |
| 31 | −$.hasChild = function(parent, el) { | |
| 32 | − if (!parent) { return; } | |
| 39 | +$.hasChild = function (parent, el) { | |
| 40 | + if (!parent) { | |
| 41 | + return; | |
| 42 | + } | |
| 33 | 43 | while (el) { |
| 34 | − if (el === parent) { return true; } | |
| 35 | − if (el === document.body) { return; } | |
| 44 | + if (el === parent) { | |
| 45 | + return true; | |
| 46 | + } | |
| 47 | + if (el === document.body) { | |
| 48 | + return; | |
| 49 | + } | |
| 36 | 50 | el = el.parentNode; |
| 37 | 51 | } |
| 38 | 52 | }; |
| 39 | 53 | |
| 40 | −$.closestLink = function(el, parent) { | |
| 41 | − if (parent == null) { parent = document.body; } | |
| 54 | +$.closestLink = function (el, parent) { | |
| 55 | + if (parent == null) { | |
| 56 | + parent = document.body; | |
| 57 | + } | |
| 42 | 58 | while (el) { |
| 43 | − if (el.tagName === 'A') { return el; } | |
| 44 | − if (el === parent) { return; } | |
| 59 | + if (el.tagName === "A") { | |
| 60 | + return el; | |
| 61 | + } | |
| 62 | + if (el === parent) { | |
| 63 | + return; | |
| 64 | + } | |
| 45 | 65 | el = el.parentNode; |
| 46 | 66 | } |
| 47 | 67 | }; |
| @@ -50,55 +70,85 @@ $.closestLink = function(el, parent) { · 2 unmodified lines | ||
| 50 | 70 | // Events |
| 51 | 71 | // |
| 52 | 72 | |
| 53 | −$.on = function(el, event, callback, useCapture) { | |
| 54 | − if (useCapture == null) { useCapture = false; } | |
| 55 | − if (event.indexOf(' ') >= 0) { | |
| 56 | − for (var name of Array.from(event.split(' '))) { $.on(el, name, callback); } | |
| 73 | +$.on = function (el, event, callback, useCapture) { | |
| 74 | + if (useCapture == null) { | |
| 75 | + useCapture = false; | |
| 76 | + } | |
| 77 | + if (event.indexOf(" ") >= 0) { | |
| 78 | + for (var name of Array.from(event.split(" "))) { | |
| 79 | + $.on(el, name, callback); | |
| 80 | + } | |
| 57 | 81 | } else { |
| 58 | 82 | el.addEventListener(event, callback, useCapture); |
| 59 | 83 | } |
| 60 | 84 | }; |
| 61 | 85 | |
| 62 | −$.off = function(el, event, callback, useCapture) { | |
| 63 | − if (useCapture == null) { useCapture = false; } | |
| 64 | − if (event.indexOf(' ') >= 0) { | |
| 65 | − for (var name of Array.from(event.split(' '))) { $.off(el, name, callback); } | |
| 86 | +$.off = function (el, event, callback, useCapture) { | |
| 87 | + if (useCapture == null) { | |
| 88 | + useCapture = false; | |
| 89 | + } | |
| 90 | + if (event.indexOf(" ") >= 0) { | |
| 91 | + for (var name of Array.from(event.split(" "))) { | |
| 92 | + $.off(el, name, callback); | |
| 93 | + } | |
| 66 | 94 | } else { |
| 67 | 95 | el.removeEventListener(event, callback, useCapture); |
| 68 | 96 | } |
| 69 | 97 | }; |
| 70 | 98 | |
| 71 | −$.trigger = function(el, type, canBubble, cancelable) { | |
| 72 | − if (canBubble == null) { canBubble = true; } | |
| 73 | − if (cancelable == null) { cancelable = true; } | |
| 74 | − const event = document.createEvent('Event'); | |
| 99 | +$.trigger = function (el, type, canBubble, cancelable) { | |
| 100 | + if (canBubble == null) { | |
| 101 | + canBubble = true; | |
| 102 | + } | |
| 103 | + if (cancelable == null) { | |
| 104 | + cancelable = true; | |
| 105 | + } | |
| 106 | + const event = document.createEvent("Event"); | |
| 75 | 107 | event.initEvent(type, canBubble, cancelable); |
| 76 | 108 | el.dispatchEvent(event); |
| 77 | 109 | }; |
| 78 | 110 | |
| 79 | −$.click = function(el) { | |
| 80 | − const event = document.createEvent('MouseEvent'); | |
| 81 | − event.initMouseEvent('click', true, true, window, null, 0, 0, 0, 0, false, false, false, false, 0, null); | |
| 111 | +$.click = function (el) { | |
| 112 | + const event = document.createEvent("MouseEvent"); | |
| 113 | + event.initMouseEvent( | |
| 114 | + "click", | |
| 115 | + true, | |
| 116 | + true, | |
| 117 | + window, | |
| 118 | + null, | |
| 119 | + 0, | |
| 120 | + 0, | |
| 121 | + 0, | |
| 122 | + 0, | |
| 123 | + false, | |
| 124 | + false, | |
| 125 | + false, | |
| 126 | + false, | |
| 127 | + 0, | |
| 128 | + null, | |
| 129 | + ); | |
| 82 | 130 | el.dispatchEvent(event); |
| 83 | 131 | }; |
| 84 | 132 | |
| 85 | −$.stopEvent = function(event) { | |
| 133 | +$.stopEvent = function (event) { | |
| 86 | 134 | event.preventDefault(); |
| 87 | 135 | event.stopPropagation(); |
| 88 | 136 | event.stopImmediatePropagation(); |
| 89 | 137 | }; |
| 90 | 138 | |
| 91 | −$.eventTarget = event => event.target.correspondingUseElement || event.target; | |
| 139 | +$.eventTarget = (event) => event.target.correspondingUseElement || event.target; | |
| 92 | 140 | |
| 93 | 141 | // |
| 94 | 142 | // Manipulation |
| 95 | 143 | // |
| 96 | 144 | |
| 97 | −const buildFragment = function(value) { | |
| 145 | +const buildFragment = function (value) { | |
| 98 | 146 | const fragment = document.createDocumentFragment(); |
| 99 | 147 | |
| 100 | 148 | if ($.isCollection(value)) { |
| 101 | − for (var child of Array.from($.makeArray(value))) { fragment.appendChild(child); } | |
| 149 | + for (var child of Array.from($.makeArray(value))) { | |
| 150 | + fragment.appendChild(child); | |
| 151 | + } | |
| 102 | 152 | } else { |
| 103 | 153 | fragment.innerHTML = value; |
| 104 | 154 | } |
| @@ -106,36 +156,40 @@ const buildFragment = function(value) { · 1 unmodified line | ||
| 106 | 156 | return fragment; |
| 107 | 157 | }; |
| 108 | 158 | |
| 109 | −$.append = function(el, value) { | |
| 110 | − if (typeof value === 'string') { | |
| 111 | − el.insertAdjacentHTML('beforeend', value); | |
| 159 | +$.append = function (el, value) { | |
| 160 | + if (typeof value === "string") { | |
| 161 | + el.insertAdjacentHTML("beforeend", value); | |
| 112 | 162 | } else { |
| 113 | − if ($.isCollection(value)) { value = buildFragment(value); } | |
| 163 | + if ($.isCollection(value)) { | |
| 164 | + value = buildFragment(value); | |
| 165 | + } | |
| 114 | 166 | el.appendChild(value); |
| 115 | 167 | } |
| 116 | 168 | }; |
| 117 | 169 | |
| 118 | −$.prepend = function(el, value) { | |
| 170 | +$.prepend = function (el, value) { | |
| 119 | 171 | if (!el.firstChild) { |
| 120 | 172 | $.append(value); |
| 121 | − } else if (typeof value === 'string') { | |
| 122 | − el.insertAdjacentHTML('afterbegin', value); | |
| 173 | + } else if (typeof value === "string") { | |
| 174 | + el.insertAdjacentHTML("afterbegin", value); | |
| 123 | 175 | } else { |
| 124 | − if ($.isCollection(value)) { value = buildFragment(value); } | |
| 176 | + if ($.isCollection(value)) { | |
| 177 | + value = buildFragment(value); | |
| 178 | + } | |
| 125 | 179 | el.insertBefore(value, el.firstChild); |
| 126 | 180 | } |
| 127 | 181 | }; |
| 128 | 182 | |
| 129 | −$.before = function(el, value) { | |
| 130 | − if ((typeof value === 'string') || $.isCollection(value)) { | |
| 183 | +$.before = function (el, value) { | |
| 184 | + if (typeof value === "string" || $.isCollection(value)) { | |
| 131 | 185 | value = buildFragment(value); |
| 132 | 186 | } |
| 133 | 187 | |
| 134 | 188 | el.parentNode.insertBefore(value, el); |
| 135 | 189 | }; |
| 136 | 190 | |
| 137 | −$.after = function(el, value) { | |
| 138 | − if ((typeof value === 'string') || $.isCollection(value)) { | |
| 191 | +$.after = function (el, value) { | |
| 192 | + if (typeof value === "string" || $.isCollection(value)) { | |
| 139 | 193 | value = buildFragment(value); |
| 140 | 194 | } |
| 141 | 195 | |
| @@ -146,11 +200,13 @@ $.after = function(el, value) { · 4 unmodified lines | ||
| 146 | 200 | } |
| 147 | 201 | }; |
| 148 | 202 | |
| 149 | −$.remove = function(value) { | |
| 203 | +$.remove = function (value) { | |
| 150 | 204 | if ($.isCollection(value)) { |
| 151 | − for (var el of Array.from($.makeArray(value))) { if (el.parentNode != null) { | |
| 152 | − el.parentNode.removeChild(el); | |
| 153 | − } } | |
| 205 | + for (var el of Array.from($.makeArray(value))) { | |
| 206 | + if (el.parentNode != null) { | |
| 207 | + el.parentNode.removeChild(el); | |
| 208 | + } | |
| 209 | + } | |
| 154 | 210 | } else { |
| 155 | 211 | if (value.parentNode != null) { |
| 156 | 212 | value.parentNode.removeChild(value); |
| @@ -158,13 +214,15 @@ $.remove = function(value) { · 1 unmodified line | ||
| 158 | 214 | } |
| 159 | 215 | }; |
| 160 | 216 | |
| 161 | −$.empty = function(el) { | |
| 162 | − while (el.firstChild) { el.removeChild(el.firstChild); } | |
| 217 | +$.empty = function (el) { | |
| 218 | + while (el.firstChild) { | |
| 219 | + el.removeChild(el.firstChild); | |
| 220 | + } | |
| 163 | 221 | }; |
| 164 | 222 | |
| 165 | 223 | // Calls the function while the element is off the DOM to avoid triggering |
| 166 | 224 | // unnecessary reflows and repaints. |
| 167 | −$.batchUpdate = function(el, fn) { | |
| 225 | +$.batchUpdate = function (el, fn) { | |
| 168 | 226 | const parent = el.parentNode; |
| 169 | 227 | const sibling = el.nextSibling; |
| 170 | 228 | parent.removeChild(el); |
| @@ -182,14 +240,16 @@ $.batchUpdate = function(el, fn) { · 11 unmodified lines | ||
| 182 | 240 | // Offset |
| 183 | 241 | // |
| 184 | 242 | |
| 185 | −$.rect = el => el.getBoundingClientRect(); | |
| 243 | +$.rect = (el) => el.getBoundingClientRect(); | |
| 186 | 244 | |
| 187 | −$.offset = function(el, container) { | |
| 188 | − if (container == null) { container = document.body; } | |
| 245 | +$.offset = function (el, container) { | |
| 246 | + if (container == null) { | |
| 247 | + container = document.body; | |
| 248 | + } | |
| 189 | 249 | let top = 0; |
| 190 | 250 | let left = 0; |
| 191 | 251 | |
| 192 | − while (el && (el !== container)) { | |
| 252 | + while (el && el !== container) { | |
| 193 | 253 | top += el.offsetTop; |
| 194 | 254 | left += el.offsetLeft; |
| 195 | 255 | el = el.offsetParent; |
| @@ -197,102 +257,131 @@ $.offset = function(el, container) { · 1 unmodified line | ||
| 197 | 257 | |
| 198 | 258 | return { |
| 199 | 259 | top, |
| 200 | − left | |
| 260 | + left, | |
| 201 | 261 | }; |
| 202 | 262 | }; |
| 203 | 263 | |
| 204 | −$.scrollParent = function(el) { | |
| 205 | − while ((el = el.parentNode) && (el.nodeType === 1)) { | |
| 264 | +$.scrollParent = function (el) { | |
| 265 | + while ((el = el.parentNode) && el.nodeType === 1) { | |
| 206 | 266 | var needle; |
| 207 | − if (el.scrollTop > 0) { break; } | |
| 208 | − if ((needle = __guard__(getComputedStyle(el), x => x.overflowY), ['auto', 'scroll'].includes(needle))) { break; } | |
| 267 | + if (el.scrollTop > 0) { | |
| 268 | + break; | |
| 269 | + } | |
| 270 | + if ( | |
| 271 | + ((needle = __guard__(getComputedStyle(el), (x) => x.overflowY)), | |
| 272 | + ["auto", "scroll"].includes(needle)) | |
| 273 | + ) { | |
| 274 | + break; | |
| 275 | + } | |
| 209 | 276 | } |
| 210 | 277 | return el; |
| 211 | 278 | }; |
| 212 | 279 | |
| 213 | −$.scrollTo = function(el, parent, position, options) { | |
| 214 | − if (position == null) { position = 'center'; } | |
| 215 | − if (options == null) { options = {}; } | |
| 216 | − if (!el) { return; } | |
| 280 | +$.scrollTo = function (el, parent, position, options) { | |
| 281 | + if (position == null) { | |
| 282 | + position = "center"; | |
| 283 | + } | |
| 284 | + if (options == null) { | |
| 285 | + options = {}; | |
| 286 | + } | |
| 287 | + if (!el) { | |
| 288 | + return; | |
| 289 | + } | |
| 217 | 290 | |
| 218 | − if (parent == null) { parent = $.scrollParent(el); } | |
| 219 | − if (!parent) { return; } | |
| 291 | + if (parent == null) { | |
| 292 | + parent = $.scrollParent(el); | |
| 293 | + } | |
| 294 | + if (!parent) { | |
| 295 | + return; | |
| 296 | + } | |
| 220 | 297 | |
| 221 | 298 | const parentHeight = parent.clientHeight; |
| 222 | 299 | const parentScrollHeight = parent.scrollHeight; |
| 223 | − if (!(parentScrollHeight > parentHeight)) { return; } | |
| 300 | + if (!(parentScrollHeight > parentHeight)) { | |
| 301 | + return; | |
| 302 | + } | |
| 224 | 303 | |
| 225 | − const { | |
| 226 | − top | |
| 227 | − } = $.offset(el, parent); | |
| 228 | − const { | |
| 229 | − offsetTop | |
| 230 | − } = parent.firstElementChild; | |
| 304 | + const { top } = $.offset(el, parent); | |
| 305 | + const { offsetTop } = parent.firstElementChild; | |
| 231 | 306 | |
| 232 | 307 | switch (position) { |
| 233 | − case 'top': | |
| 234 | − parent.scrollTop = top - offsetTop - ((options.margin != null) ? options.margin : 0); | |
| 308 | + case "top": | |
| 309 | + parent.scrollTop = | |
| 310 | + top - offsetTop - (options.margin != null ? options.margin : 0); | |
| 235 | 311 | break; |
| 236 | − case 'center': | |
| 237 | − parent.scrollTop = top - Math.round((parentHeight / 2) - (el.offsetHeight / 2)); | |
| 312 | + case "center": | |
| 313 | + parent.scrollTop = | |
| 314 | + top - Math.round(parentHeight / 2 - el.offsetHeight / 2); | |
| 238 | 315 | break; |
| 239 | − case 'continuous': | |
| 240 | − var { | |
| 241 | − scrollTop | |
| 242 | − } = parent; | |
| 316 | + case "continuous": | |
| 317 | + var { scrollTop } = parent; | |
| 243 | 318 | var height = el.offsetHeight; |
| 244 | 319 | |
| 245 | − var lastElementOffset = parent.lastElementChild.offsetTop + parent.lastElementChild.offsetHeight; | |
| 246 | − var offsetBottom = lastElementOffset > 0 ? parentScrollHeight - lastElementOffset : 0; | |
| 320 | + var lastElementOffset = | |
| 321 | + parent.lastElementChild.offsetTop + | |
| 322 | + parent.lastElementChild.offsetHeight; | |
| 323 | + var offsetBottom = | |
| 324 | + lastElementOffset > 0 ? parentScrollHeight - lastElementOffset : 0; | |
| 247 | 325 | |
| 248 | 326 | // If the target element is above the visible portion of its scrollable |
| 249 | 327 | // ancestor, move it near the top with a gap = options.topGap * target's height. |
| 250 | − if ((top - offsetTop) <= (scrollTop + (height * (options.topGap || 1)))) { | |
| 251 | − parent.scrollTop = top - offsetTop - (height * (options.topGap || 1)); | |
| 252 | − // If the target element is below the visible portion of its scrollable | |
| 253 | − // ancestor, move it near the bottom with a gap = options.bottomGap * target's height. | |
| 254 | − } else if ((top + offsetBottom) >= ((scrollTop + parentHeight) - (height * ((options.bottomGap || 1) + 1)))) { | |
| 255 | − parent.scrollTop = ((top + offsetBottom) - parentHeight) + (height * ((options.bottomGap || 1) + 1)); | |
| 328 | + if (top - offsetTop <= scrollTop + height * (options.topGap || 1)) { | |
| 329 | + parent.scrollTop = top - offsetTop - height * (options.topGap || 1); | |
| 330 | + // If the target element is below the visible portion of its scrollable | |
| 331 | + // ancestor, move it near the bottom with a gap = options.bottomGap * target's height. | |
| 332 | + } else if ( | |
| 333 | + top + offsetBottom >= | |
| 334 | + scrollTop + parentHeight - height * ((options.bottomGap || 1) + 1) | |
| 335 | + ) { | |
| 336 | + parent.scrollTop = | |
| 337 | + top + | |
| 338 | + offsetBottom - | |
| 339 | + parentHeight + | |
| 340 | + height * ((options.bottomGap || 1) + 1); | |
| 256 | 341 | } |
| 257 | 342 | break; |
| 258 | 343 | } |
| 259 | 344 | }; |
| 260 | 345 | |
| 261 | −$.scrollToWithImageLock = function(el, parent, ...args) { | |
| 262 | − if (parent == null) { parent = $.scrollParent(el); } | |
| 263 | − if (!parent) { return; } | |
| 346 | +$.scrollToWithImageLock = function (el, parent, ...args) { | |
| 347 | + if (parent == null) { | |
| 348 | + parent = $.scrollParent(el); | |
| 349 | + } | |
| 350 | + if (!parent) { | |
| 351 | + return; | |
| 352 | + } | |
| 264 | 353 | |
| 265 | 354 | $.scrollTo(el, parent, ...Array.from(args)); |
| 266 | 355 | |
| 267 | 356 | // Lock the scroll position on the target element for up to 3 seconds while |
| 268 | 357 | // nearby images are loaded and rendered. |
| 269 | − for (var image of Array.from(parent.getElementsByTagName('img'))) { | |
| 358 | + for (var image of Array.from(parent.getElementsByTagName("img"))) { | |
| 270 | 359 | if (!image.complete) { |
| 271 | − (function() { | |
| 360 | + (function () { | |
| 272 | 361 | let timeout; |
| 273 | − const onLoad = function(event) { | |
| 362 | + const onLoad = function (event) { | |
| 274 | 363 | clearTimeout(timeout); |
| 275 | 364 | unbind(event.target); |
| 276 | 365 | return $.scrollTo(el, parent, ...Array.from(args)); |
| 277 | 366 | }; |
| 278 | 367 | |
| 279 | − var unbind = target => $.off(target, 'load', onLoad); | |
| 368 | + var unbind = (target) => $.off(target, "load", onLoad); | |
| 280 | 369 | |
| 281 | − $.on(image, 'load', onLoad); | |
| 282 | − return timeout = setTimeout(unbind.bind(null, image), 3000); | |
| 370 | + $.on(image, "load", onLoad); | |
| 371 | + return (timeout = setTimeout(unbind.bind(null, image), 3000)); | |
| 283 | 372 | })(); |
| 284 | 373 | } |
| 285 | 374 | } |
| 286 | 375 | }; |
| 287 | 376 | |
| 288 | 377 | // Calls the function while locking the element's position relative to the window. |
| 289 | −$.lockScroll = function(el, fn) { | |
| 378 | +$.lockScroll = function (el, fn) { | |
| 290 | 379 | let parent; |
| 291 | − if (parent = $.scrollParent(el)) { | |
| 292 | − let { | |
| 293 | − top | |
| 294 | − } = $.rect(el); | |
| 295 | − if (![document.body, document.documentElement].includes(parent)) { top -= $.rect(parent).top; } | |
| 380 | + if ((parent = $.scrollParent(el))) { | |
| 381 | + let { top } = $.rect(el); | |
| 382 | + if (![document.body, document.documentElement].includes(parent)) { | |
| 383 | + top -= $.rect(parent).top; | |
| 384 | + } | |
| 296 | 385 | fn(); |
| 297 | 386 | parent.scrollTop = $.offset(el, parent).top - top; |
| 298 | 387 | } else { |
| @@ -300,9 +389,14 @@ $.lockScroll = function(el, fn) { · 1 unmodified line | ||
| 300 | 389 | } |
| 301 | 390 | }; |
| 302 | 391 | |
| 303 | −let smoothScroll = (smoothStart = (smoothEnd = (smoothDistance = (smoothDuration = null)))); | |
| 392 | +let smoothScroll = | |
| 393 | + (smoothStart = | |
| 394 | + smoothEnd = | |
| 395 | + smoothDistance = | |
| 396 | + smoothDuration = | |
| 397 | + null); | |
| 304 | 398 | |
| 305 | −$.smoothScroll = function(el, end) { | |
| 399 | +$.smoothScroll = function (el, end) { | |
| 306 | 400 | if (!window.requestAnimationFrame) { |
| 307 | 401 | el.scrollTop = end; |
| 308 | 402 | return; |
| @@ -322,12 +416,18 @@ $.smoothScroll = function(el, end) { · 13 unmodified lines | ||
| 322 | 416 | smoothDuration = Math.min(300, Math.abs(smoothDistance)); |
| 323 | 417 | const startTime = Date.now(); |
| 324 | 418 | |
| 325 | − smoothScroll = function() { | |
| 419 | + smoothScroll = function () { | |
| 326 | 420 | const p = Math.min(1, (Date.now() - startTime) / smoothDuration); |
| 327 | − const y = Math.max(0, Math.floor(smoothStart + (smoothDistance * (p < 0.5 ? 2 * p * p : (p * (4 - (p * 2))) - 1)))); | |
| 421 | + const y = Math.max( | |
| 422 | + 0, | |
| 423 | + Math.floor( | |
| 424 | + smoothStart + | |
| 425 | + smoothDistance * (p < 0.5 ? 2 * p * p : p * (4 - p * 2) - 1), | |
| 426 | + ), | |
| 427 | + ); | |
| 328 | 428 | el.scrollTop = y; |
| 329 | 429 | if (p === 1) { |
| 330 | − return smoothScroll = null; | |
| 430 | + return (smoothScroll = null); | |
| 331 | 431 | } else { |
| 332 | 432 | return requestAnimationFrame(smoothScroll); |
| 333 | 433 | } |
| @@ -339,7 +439,7 @@ $.smoothScroll = function(el, end) { · 5 unmodified lines | ||
| 339 | 439 | // Utilities |
| 340 | 440 | // |
| 341 | 441 | |
| 342 | −$.extend = function(target, ...objects) { | |
| 442 | +$.extend = function (target, ...objects) { | |
| 343 | 443 | for (var object of Array.from(objects)) { |
| 344 | 444 | if (object) { |
| 345 | 445 | for (var key in object) { |
| @@ -351,7 +451,7 @@ $.extend = function(target, ...objects) { · 5 unmodified lines | ||
| 351 | 451 | return target; |
| 352 | 452 | }; |
| 353 | 453 | |
| 354 | −$.makeArray = function(object) { | |
| 454 | +$.makeArray = function (object) { | |
| 355 | 455 | if (Array.isArray(object)) { |
| 356 | 456 | return object; |
| 357 | 457 | } else { |
| @@ -359,7 +459,7 @@ $.makeArray = function(object) { · 1 unmodified line | ||
| 359 | 459 | } |
| 360 | 460 | }; |
| 361 | 461 | |
| 362 | −$.arrayDelete = function(array, object) { | |
| 462 | +$.arrayDelete = function (array, object) { | |
| 363 | 463 | const index = array.indexOf(object); |
| 364 | 464 | if (index >= 0) { |
| 365 | 465 | array.splice(index, 1); |
| @@ -370,45 +470,49 @@ $.arrayDelete = function(array, object) { · 4 unmodified lines | ||
| 370 | 470 | }; |
| 371 | 471 | |
| 372 | 472 | // Returns true if the object is an array or a collection of DOM elements. |
| 373 | −$.isCollection = object => Array.isArray(object) || (typeof (object != null ? object.item : undefined) === 'function'); | |
| 473 | +$.isCollection = (object) => | |
| 474 | + Array.isArray(object) || | |
| 475 | + typeof (object != null ? object.item : undefined) === "function"; | |
| 374 | 476 | |
| 375 | 477 | const ESCAPE_HTML_MAP = { |
| 376 | − '&': '&', | |
| 377 | − '<': '<', | |
| 378 | − '>': '>', | |
| 379 | − '"': '"', | |
| 380 | − "'": ''', | |
| 381 | − '/': '/' | |
| 478 | + "&": "&", | |
| 479 | + "<": "<", | |
| 480 | + ">": ">", | |
| 481 | + '"': """, | |
| 482 | + "'": "'", | |
| 483 | + "/": "/", | |
| 382 | 484 | }; |
| 383 | 485 | |
| 384 | 486 | const ESCAPE_HTML_REGEXP = /[&<>"'\/]/g; |
| 385 | 487 | |
| 386 | −$.escape = string => string.replace(ESCAPE_HTML_REGEXP, match => ESCAPE_HTML_MAP[match]); | |
| 488 | +$.escape = (string) => | |
| 489 | + string.replace(ESCAPE_HTML_REGEXP, (match) => ESCAPE_HTML_MAP[match]); | |
| 387 | 490 | |
| 388 | 491 | const ESCAPE_REGEXP = /([.*+?^=!:${}()|\[\]\/\\])/g; |
| 389 | 492 | |
| 390 | −$.escapeRegexp = string => string.replace(ESCAPE_REGEXP, "\\$1"); | |
| 493 | +$.escapeRegexp = (string) => string.replace(ESCAPE_REGEXP, "\\$1"); | |
| 391 | 494 | |
| 392 | −$.urlDecode = string => decodeURIComponent(string.replace(/\+/g, '%20')); | |
| 495 | +$.urlDecode = (string) => decodeURIComponent(string.replace(/\+/g, "%20")); | |
| 393 | 496 | |
| 394 | −$.classify = function(string) { | |
| 395 | − string = string.split('_'); | |
| 497 | +$.classify = function (string) { | |
| 498 | + string = string.split("_"); | |
| 396 | 499 | for (let i = 0; i < string.length; i++) { |
| 397 | 500 | var substr = string[i]; |
| 398 | 501 | string[i] = substr[0].toUpperCase() + substr.slice(1); |
| 399 | 502 | } |
| 400 | − return string.join(''); | |
| 503 | + return string.join(""); | |
| 401 | 504 | }; |
| 402 | 505 | |
| 403 | −$.framify = function(fn, obj) { | |
| 506 | +$.framify = function (fn, obj) { | |
| 404 | 507 | if (window.requestAnimationFrame) { |
| 405 | − return (...args) => requestAnimationFrame(fn.bind(obj, ...Array.from(args))); | |
| 508 | + return (...args) => | |
| 509 | + requestAnimationFrame(fn.bind(obj, ...Array.from(args))); | |
| 406 | 510 | } else { |
| 407 | 511 | return fn; |
| 408 | 512 | } |
| 409 | 513 | }; |
| 410 | 514 | |
| 411 | −$.requestAnimationFrame = function(fn) { | |
| 515 | +$.requestAnimationFrame = function (fn) { | |
| 412 | 516 | if (window.requestAnimationFrame) { |
| 413 | 517 | requestAnimationFrame(fn); |
| 414 | 518 | } else { |
| @@ -420,37 +524,81 @@ $.requestAnimationFrame = function(fn) { · 5 unmodified lines | ||
| 420 | 524 | // Miscellaneous |
| 421 | 525 | // |
| 422 | 526 | |
| 423 | −$.noop = function() {}; | |
| 527 | +$.noop = function () {}; | |
| 424 | 528 | |
| 425 | −$.popup = function(value) { | |
| 529 | +$.popup = function (value) { | |
| 426 | 530 | try { |
| 427 | 531 | const win = window.open(); |
| 428 | − if (win.opener) { win.opener = null; } | |
| 532 | + if (win.opener) { | |
| 533 | + win.opener = null; | |
| 534 | + } | |
| 429 | 535 | win.location = value.href || value; |
| 430 | 536 | } catch (error) { |
| 431 | − window.open(value.href || value, '_blank'); | |
| 537 | + window.open(value.href || value, "_blank"); | |
| 432 | 538 | } |
| 433 | 539 | }; |
| 434 | 540 | |
| 435 | 541 | let isMac = null; |
| 436 | −$.isMac = () => isMac != null ? isMac : (isMac = (navigator.userAgent != null ? navigator.userAgent.indexOf('Mac') : undefined) >= 0); | |
| 542 | +$.isMac = () => | |
| 543 | + isMac != null | |
| 544 | + ? isMac | |
| 545 | + : (isMac = | |
| 546 | + (navigator.userAgent != null | |
| 547 | + ? navigator.userAgent.indexOf("Mac") | |
| 548 | + : undefined) >= 0); | |
| 437 | 549 | |
| 438 | 550 | let isIE = null; |
| 439 | −$.isIE = () => isIE != null ? isIE : (isIE = ((navigator.userAgent != null ? navigator.userAgent.indexOf('MSIE') : undefined) >= 0) || ((navigator.userAgent != null ? navigator.userAgent.indexOf('rv:11.0') : undefined) >= 0)); | |
| 551 | +$.isIE = () => | |
| 552 | + isIE != null | |
| 553 | + ? isIE | |
| 554 | + : (isIE = | |
| 555 | + (navigator.userAgent != null | |
| 556 | + ? navigator.userAgent.indexOf("MSIE") | |
| 557 | + : undefined) >= 0 || | |
| 558 | + (navigator.userAgent != null | |
| 559 | + ? navigator.userAgent.indexOf("rv:11.0") | |
| 560 | + : undefined) >= 0); | |
| 440 | 561 | |
| 441 | 562 | let isChromeForAndroid = null; |
| 442 | −$.isChromeForAndroid = () => isChromeForAndroid != null ? isChromeForAndroid : (isChromeForAndroid = ((navigator.userAgent != null ? navigator.userAgent.indexOf('Android') : undefined) >= 0) && /Chrome\/([.0-9])+ Mobile/.test(navigator.userAgent)); | |
| 563 | +$.isChromeForAndroid = () => | |
| 564 | + isChromeForAndroid != null | |
| 565 | + ? isChromeForAndroid | |
| 566 | + : (isChromeForAndroid = | |
| 567 | + (navigator.userAgent != null | |
| 568 | + ? navigator.userAgent.indexOf("Android") | |
| 569 | + : undefined) >= 0 && | |
| 570 | + /Chrome\/([.0-9])+ Mobile/.test(navigator.userAgent)); | |
| 443 | 571 | |
| 444 | 572 | let isAndroid = null; |
| 445 | −$.isAndroid = () => isAndroid != null ? isAndroid : (isAndroid = (navigator.userAgent != null ? navigator.userAgent.indexOf('Android') : undefined) >= 0); | |
| 573 | +$.isAndroid = () => | |
| 574 | + isAndroid != null | |
| 575 | + ? isAndroid | |
| 576 | + : (isAndroid = | |
| 577 | + (navigator.userAgent != null | |
| 578 | + ? navigator.userAgent.indexOf("Android") | |
| 579 | + : undefined) >= 0); | |
| 446 | 580 | |
| 447 | 581 | let isIOS = null; |
| 448 | −$.isIOS = () => isIOS != null ? isIOS : (isIOS = ((navigator.userAgent != null ? navigator.userAgent.indexOf('iPhone') : undefined) >= 0) || ((navigator.userAgent != null ? navigator.userAgent.indexOf('iPad') : undefined) >= 0)); | |
| 449 | − | |
| 450 | −$.overlayScrollbarsEnabled = function() { | |
| 451 | − if (!$.isMac()) { return false; } | |
| 452 | − const div = document.createElement('div'); | |
| 453 | − div.setAttribute('style', 'width: 100px; height: 100px; overflow: scroll; position: absolute'); | |
| 582 | +$.isIOS = () => | |
| 583 | + isIOS != null | |
| 584 | + ? isIOS | |
| 585 | + : (isIOS = | |
| 586 | + (navigator.userAgent != null | |
| 587 | + ? navigator.userAgent.indexOf("iPhone") | |
| 588 | + : undefined) >= 0 || | |
| 589 | + (navigator.userAgent != null | |
| 590 | + ? navigator.userAgent.indexOf("iPad") | |
| 591 | + : undefined) >= 0); | |
| 592 | + | |
| 593 | +$.overlayScrollbarsEnabled = function () { | |
| 594 | + if (!$.isMac()) { | |
| 595 | + return false; | |
| 596 | + } | |
| 597 | + const div = document.createElement("div"); | |
| 598 | + div.setAttribute( | |
| 599 | + "style", | |
| 600 | + "width: 100px; height: 100px; overflow: scroll; position: absolute", | |
| 601 | + ); | |
| 454 | 602 | document.body.appendChild(div); |
| 455 | 603 | const result = div.offsetWidth === div.clientWidth; |
| 456 | 604 | document.body.removeChild(div); |
| @@ -458,36 +606,39 @@ $.overlayScrollbarsEnabled = function() { · 1 unmodified line | ||
| 458 | 606 | }; |
| 459 | 607 | |
| 460 | 608 | const HIGHLIGHT_DEFAULTS = { |
| 461 | − className: 'highlight', | |
| 462 | − delay: 1000 | |
| 609 | + className: "highlight", | |
| 610 | + delay: 1000, | |
| 463 | 611 | }; |
| 464 | 612 | |
| 465 | −$.highlight = function(el, options) { | |
| 466 | − if (options == null) { options = {}; } | |
| 613 | +$.highlight = function (el, options) { | |
| 614 | + if (options == null) { | |
| 615 | + options = {}; | |
| 616 | + } | |
| 467 | 617 | options = $.extend({}, HIGHLIGHT_DEFAULTS, options); |
| 468 | 618 | el.classList.add(options.className); |
| 469 | − setTimeout((() => el.classList.remove(options.className)), options.delay); | |
| 619 | + setTimeout(() => el.classList.remove(options.className), options.delay); | |
| 470 | 620 | }; |
| 471 | 621 | |
| 472 | −$.copyToClipboard = function(string) { | |
| 622 | +$.copyToClipboard = function (string) { | |
| 473 | 623 | let result; |
| 474 | − const textarea = document.createElement('textarea'); | |
| 475 | − textarea.style.position = 'fixed'; | |
| 624 | + const textarea = document.createElement("textarea"); | |
| 625 | + textarea.style.position = "fixed"; | |
| 476 | 626 | textarea.style.opacity = 0; |
| 477 | 627 | textarea.value = string; |
| 478 | 628 | document.body.appendChild(textarea); |
| 479 | 629 | try { |
| 480 | 630 | textarea.select(); |
| 481 | − result = !!document.execCommand('copy'); | |
| 631 | + result = !!document.execCommand("copy"); | |
| 482 | 632 | } catch (error) { |
| 483 | 633 | result = false; |
| 484 | − } | |
| 485 | − finally { | |
| 634 | + } finally { | |
| 486 | 635 | document.body.removeChild(textarea); |
| 487 | 636 | } |
| 488 | 637 | return result; |
| 489 | 638 | }; |
| 490 | 639 | |
| 491 | 640 | function __guard__(value, transform) { |
| 492 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 493 | −} | |
| 641 | + return typeof value !== "undefined" && value !== null | |
| 642 | + ? transform(value) | |
| 643 | + : undefined; | |
| 644 | +} | |
| @@ -12,10 +12,12 @@ app.models.Doc = class Doc extends app.Model { · 11 unmodified lines | ||
| 12 | 12 | constructor() { |
| 13 | 13 | super(...arguments); |
| 14 | 14 | this.reset(this); |
| 15 | − this.slug_without_version = this.slug.split('~')[0]; | |
| 16 | − this.fullName = `${this.name}` + (this.version ? ` ${this.version}` : ''); | |
| 15 | + this.slug_without_version = this.slug.split("~")[0]; | |
| 16 | + this.fullName = `${this.name}` + (this.version ? ` ${this.version}` : ""); | |
| 17 | 17 | this.icon = this.slug_without_version; |
| 18 | − if (this.version) { this.short_version = this.version.split(' ')[0]; } | |
| 18 | + if (this.version) { | |
| 19 | + this.short_version = this.version.split(" ")[0]; | |
| 20 | + } | |
| 19 | 21 | this.text = this.toEntry().text; |
| 20 | 22 | } |
| 21 | 23 | |
| @@ -26,17 +28,25 @@ app.models.Doc = class Doc extends app.Model { · 4 unmodified lines | ||
| 26 | 28 | |
| 27 | 29 | resetEntries(entries) { |
| 28 | 30 | this.entries = new app.collections.Entries(entries); |
| 29 | − this.entries.each(entry => { return entry.doc = this; }); | |
| 31 | + this.entries.each((entry) => { | |
| 32 | + return (entry.doc = this); | |
| 33 | + }); | |
| 30 | 34 | } |
| 31 | 35 | |
| 32 | 36 | resetTypes(types) { |
| 33 | 37 | this.types = new app.collections.Types(types); |
| 34 | − this.types.each(type => { return type.doc = this; }); | |
| 38 | + this.types.each((type) => { | |
| 39 | + return (type.doc = this); | |
| 40 | + }); | |
| 35 | 41 | } |
| 36 | 42 | |
| 37 | 43 | fullPath(path) { |
| 38 | − if (path == null) { path = ''; } | |
| 39 | − if (path[0] !== '/') { path = `/${path}`; } | |
| 44 | + if (path == null) { | |
| 45 | + path = ""; | |
| 46 | + } | |
| 47 | + if (path[0] !== "/") { | |
| 48 | + path = `/${path}`; | |
| 49 | + } | |
| 40 | 50 | return `/${this.slug}${path}`; |
| 41 | 51 | } |
| 42 | 52 | |
| @@ -49,45 +59,57 @@ app.models.Doc = class Doc extends app.Model { · 6 unmodified lines | ||
| 49 | 59 | } |
| 50 | 60 | |
| 51 | 61 | indexUrl() { |
| 52 | − return `${app.indexHost()}/${this.slug}/${app.config.index_filename}?${this.mtime}`; | |
| 62 | + return `${app.indexHost()}/${this.slug}/${app.config.index_filename}?${ | |
| 63 | + this.mtime | |
| 64 | + }`; | |
| 53 | 65 | } |
| 54 | 66 | |
| 55 | 67 | toEntry() { |
| 56 | − if (this.entry) { return this.entry; } | |
| 68 | + if (this.entry) { | |
| 69 | + return this.entry; | |
| 70 | + } | |
| 57 | 71 | this.entry = new app.models.Entry({ |
| 58 | 72 | doc: this, |
| 59 | 73 | name: this.fullName, |
| 60 | − path: 'index' | |
| 74 | + path: "index", | |
| 61 | 75 | }); |
| 62 | − if (this.version) { this.entry.addAlias(this.name); } | |
| 76 | + if (this.version) { | |
| 77 | + this.entry.addAlias(this.name); | |
| 78 | + } | |
| 63 | 79 | return this.entry; |
| 64 | 80 | } |
| 65 | 81 | |
| 66 | 82 | findEntryByPathAndHash(path, hash) { |
| 67 | 83 | let entry; |
| 68 | − if (hash && (entry = this.entries.findBy('path', `${path}#${hash}`))) { | |
| 84 | + if (hash && (entry = this.entries.findBy("path", `${path}#${hash}`))) { | |
| 69 | 85 | return entry; |
| 70 | − } else if (path === 'index') { | |
| 86 | + } else if (path === "index") { | |
| 71 | 87 | return this.toEntry(); |
| 72 | 88 | } else { |
| 73 | − return this.entries.findBy('path', path); | |
| 89 | + return this.entries.findBy("path", path); | |
| 74 | 90 | } |
| 75 | 91 | } |
| 76 | 92 | |
| 77 | 93 | load(onSuccess, onError, options) { |
| 78 | − if (options == null) { options = {}; } | |
| 79 | − if (options.readCache && this._loadFromCache(onSuccess)) { return; } | |
| 94 | + if (options == null) { | |
| 95 | + options = {}; | |
| 96 | + } | |
| 97 | + if (options.readCache && this._loadFromCache(onSuccess)) { | |
| 98 | + return; | |
| 99 | + } | |
| 80 | 100 | |
| 81 | − const callback = data => { | |
| 101 | + const callback = (data) => { | |
| 82 | 102 | this.reset(data); |
| 83 | 103 | onSuccess(); |
| 84 | − if (options.writeCache) { this._setCache(data); } | |
| 104 | + if (options.writeCache) { | |
| 105 | + this._setCache(data); | |
| 106 | + } | |
| 85 | 107 | }; |
| 86 | 108 | |
| 87 | 109 | return ajax({ |
| 88 | 110 | url: this.indexUrl(), |
| 89 | 111 | success: callback, |
| 90 | − error: onError | |
| 112 | + error: onError, | |
| 91 | 113 | }); |
| 92 | 114 | } |
| 93 | 115 | |
| @@ -97,7 +119,9 @@ app.models.Doc = class Doc extends app.Model { · 3 unmodified lines | ||
| 97 | 119 | |
| 98 | 120 | _loadFromCache(onSuccess) { |
| 99 | 121 | let data; |
| 100 | − if (!(data = this._getCache())) { return; } | |
| 122 | + if (!(data = this._getCache())) { | |
| 123 | + return; | |
| 124 | + } | |
| 101 | 125 | |
| 102 | 126 | const callback = () => { |
| 103 | 127 | this.reset(data); |
| @@ -110,7 +134,9 @@ app.models.Doc = class Doc extends app.Model { · 6 unmodified lines | ||
| 110 | 134 | |
| 111 | 135 | _getCache() { |
| 112 | 136 | let data; |
| 113 | − if (!(data = app.localStorage.get(this.slug))) { return; } | |
| 137 | + if (!(data = app.localStorage.get(this.slug))) { | |
| 138 | + return; | |
| 139 | + } | |
| 114 | 140 | |
| 115 | 141 | if (data[0] === this.mtime) { |
| 116 | 142 | return data[1]; |
| @@ -125,7 +151,9 @@ app.models.Doc = class Doc extends app.Model { · 8 unmodified lines | ||
| 125 | 151 | } |
| 126 | 152 | |
| 127 | 153 | install(onSuccess, onError, onProgress) { |
| 128 | − if (this.installing) { return; } | |
| 154 | + if (this.installing) { | |
| 155 | + return; | |
| 156 | + } | |
| 129 | 157 | this.installing = true; |
| 130 | 158 | |
| 131 | 159 | const error = () => { |
| @@ -133,7 +161,7 @@ app.models.Doc = class Doc extends app.Model { · 1 unmodified line | ||
| 133 | 161 | onError(); |
| 134 | 162 | }; |
| 135 | 163 | |
| 136 | − const success = data => { | |
| 164 | + const success = (data) => { | |
| 137 | 165 | this.installing = null; |
| 138 | 166 | app.db.store(this, data, onSuccess, error); |
| 139 | 167 | }; |
| @@ -143,12 +171,14 @@ app.models.Doc = class Doc extends app.Model { · 3 unmodified lines | ||
| 143 | 171 | success, |
| 144 | 172 | error, |
| 145 | 173 | progress: onProgress, |
| 146 | − timeout: 3600 | |
| 174 | + timeout: 3600, | |
| 147 | 175 | }); |
| 148 | 176 | } |
| 149 | 177 | |
| 150 | 178 | uninstall(onSuccess, onError) { |
| 151 | − if (this.installing) { return; } | |
| 179 | + if (this.installing) { | |
| 180 | + return; | |
| 181 | + } | |
| 152 | 182 | this.installing = true; |
| 153 | 183 | |
| 154 | 184 | const success = () => { |
| @@ -165,12 +195,16 @@ app.models.Doc = class Doc extends app.Model { · 10 unmodified lines | ||
| 165 | 195 | } |
| 166 | 196 | |
| 167 | 197 | getInstallStatus(callback) { |
| 168 | − app.db.version(this, value => callback({installed: !!value, mtime: value})); | |
| 198 | + app.db.version(this, (value) => | |
| 199 | + callback({ installed: !!value, mtime: value }), | |
| 200 | + ); | |
| 169 | 201 | } |
| 170 | 202 | |
| 171 | 203 | isOutdated(status) { |
| 172 | − if (!status) { return false; } | |
| 173 | − const isInstalled = status.installed || app.settings.get('autoInstall'); | |
| 174 | − return isInstalled && (this.mtime !== status.mtime); | |
| 204 | + if (!status) { | |
| 205 | + return false; | |
| 206 | + } | |
| 207 | + const isInstalled = status.installed || app.settings.get("autoInstall"); | |
| 208 | + return isInstalled && this.mtime !== status.mtime; | |
| 175 | 209 | } |
| 176 | 210 | }; |
| @@ -8,63 +8,62 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | //= require app/searcher |
| 10 | 10 | |
| 11 | −(function() { | |
| 11 | +(function () { | |
| 12 | 12 | let applyAliases = undefined; |
| 13 | 13 | const Cls = (app.models.Entry = class Entry extends app.Model { |
| 14 | 14 | static initClass() { |
| 15 | − | |
| 16 | 15 | let ALIASES; |
| 17 | − applyAliases = function(string) { | |
| 16 | + applyAliases = function (string) { | |
| 18 | 17 | if (ALIASES.hasOwnProperty(string)) { |
| 19 | 18 | return [string, ALIASES[string]]; |
| 20 | 19 | } else { |
| 21 | − const words = string.split('.'); | |
| 20 | + const words = string.split("."); | |
| 22 | 21 | for (let i = 0; i < words.length; i++) { |
| 23 | 22 | var word = words[i]; |
| 24 | 23 | if (ALIASES.hasOwnProperty(word)) { |
| 25 | 24 | words[i] = ALIASES[word]; |
| 26 | − return [string, words.join('.')]; | |
| 25 | + return [string, words.join(".")]; | |
| 27 | 26 | } |
| 28 | 27 | } |
| 29 | 28 | } |
| 30 | 29 | return string; |
| 31 | 30 | }; |
| 32 | − | |
| 33 | − this.ALIASES = (ALIASES = { | |
| 34 | − 'angular': 'ng', | |
| 35 | − 'angular.js': 'ng', | |
| 36 | − 'backbone.js': 'bb', | |
| 37 | − 'c++': 'cpp', | |
| 38 | − 'coffeescript': 'cs', | |
| 39 | − 'crystal': 'cr', | |
| 40 | − 'elixir': 'ex', | |
| 41 | − 'javascript': 'js', | |
| 42 | − 'julia': 'jl', | |
| 43 | − 'jquery': '$', | |
| 44 | − 'knockout.js': 'ko', | |
| 45 | − 'kubernetes': 'k8s', | |
| 46 | − 'less': 'ls', | |
| 47 | − 'lodash': '_', | |
| 48 | − 'löve': 'love', | |
| 49 | − 'marionette': 'mn', | |
| 50 | − 'markdown': 'md', | |
| 51 | − 'matplotlib': 'mpl', | |
| 52 | − 'modernizr': 'mdr', | |
| 53 | − 'moment.js': 'mt', | |
| 54 | − 'openjdk': 'java', | |
| 55 | − 'nginx': 'ngx', | |
| 56 | − 'numpy': 'np', | |
| 57 | − 'pandas': 'pd', | |
| 58 | − 'postgresql': 'pg', | |
| 59 | − 'python': 'py', | |
| 60 | − 'ruby.on.rails': 'ror', | |
| 61 | − 'ruby': 'rb', | |
| 62 | − 'rust': 'rs', | |
| 63 | − 'sass': 'scss', | |
| 64 | − 'tensorflow': 'tf', | |
| 65 | − 'typescript': 'ts', | |
| 66 | − 'underscore.js': '_' | |
| 67 | − }); | |
| 31 | + | |
| 32 | + this.ALIASES = ALIASES = { | |
| 33 | + angular: "ng", | |
| 34 | + "angular.js": "ng", | |
| 35 | + "backbone.js": "bb", | |
| 36 | + "c++": "cpp", | |
| 37 | + coffeescript: "cs", | |
| 38 | + crystal: "cr", | |
| 39 | + elixir: "ex", | |
| 40 | + javascript: "js", | |
| 41 | + julia: "jl", | |
| 42 | + jquery: "$", | |
| 43 | + "knockout.js": "ko", | |
| 44 | + kubernetes: "k8s", | |
| 45 | + less: "ls", | |
| 46 | + lodash: "_", | |
| 47 | + löve: "love", | |
| 48 | + marionette: "mn", | |
| 49 | + markdown: "md", | |
| 50 | + matplotlib: "mpl", | |
| 51 | + modernizr: "mdr", | |
| 52 | + "moment.js": "mt", | |
| 53 | + openjdk: "java", | |
| 54 | + nginx: "ngx", | |
| 55 | + numpy: "np", | |
| 56 | + pandas: "pd", | |
| 57 | + postgresql: "pg", | |
| 58 | + python: "py", | |
| 59 | + "ruby.on.rails": "ror", | |
| 60 | + ruby: "rb", | |
| 61 | + rust: "rs", | |
| 62 | + sass: "scss", | |
| 63 | + tensorflow: "tf", | |
| 64 | + typescript: "ts", | |
| 65 | + "underscore.js": "_", | |
| 66 | + }; | |
| 68 | 67 | } |
| 69 | 68 | // Attributes: name, type, path |
| 70 | 69 | |
| @@ -75,16 +74,18 @@ · 4 unmodified lines | ||
| 75 | 74 | |
| 76 | 75 | addAlias(name) { |
| 77 | 76 | const text = applyAliases(app.Searcher.normalizeString(name)); |
| 78 | − if (!Array.isArray(this.text)) { this.text = [this.text]; } | |
| 77 | + if (!Array.isArray(this.text)) { | |
| 78 | + this.text = [this.text]; | |
| 79 | + } | |
| 79 | 80 | this.text.push(Array.isArray(text) ? text[1] : text); |
| 80 | 81 | } |
| 81 | 82 | |
| 82 | 83 | fullPath() { |
| 83 | − return this.doc.fullPath(this.isIndex() ? '' : this.path); | |
| 84 | + return this.doc.fullPath(this.isIndex() ? "" : this.path); | |
| 84 | 85 | } |
| 85 | 86 | |
| 86 | 87 | dbPath() { |
| 87 | − return this.path.replace(/#.*/, ''); | |
| 88 | + return this.path.replace(/#.*/, ""); | |
| 88 | 89 | } |
| 89 | 90 | |
| 90 | 91 | filePath() { |
| @@ -96,17 +97,19 @@ · 5 unmodified lines | ||
| 96 | 97 | } |
| 97 | 98 | |
| 98 | 99 | _filePath() { |
| 99 | − let result = this.path.replace(/#.*/, ''); | |
| 100 | − if (result.slice(-5) !== '.html') { result += '.html'; } | |
| 100 | + let result = this.path.replace(/#.*/, ""); | |
| 101 | + if (result.slice(-5) !== ".html") { | |
| 102 | + result += ".html"; | |
| 103 | + } | |
| 101 | 104 | return result; |
| 102 | 105 | } |
| 103 | 106 | |
| 104 | 107 | isIndex() { |
| 105 | − return this.path === 'index'; | |
| 108 | + return this.path === "index"; | |
| 106 | 109 | } |
| 107 | 110 | |
| 108 | 111 | getType() { |
| 109 | − return this.doc.types.findBy('name', this.type); | |
| 112 | + return this.doc.types.findBy("name", this.type); | |
| 110 | 113 | } |
| 111 | 114 | |
| 112 | 115 | loadFile(onSuccess, onError) { |
| @@ -2,6 +2,9 @@ · 1 unmodified line | ||
| 2 | 2 | // Sanity-check the conversion and remove this comment. |
| 3 | 3 | app.Model = class Model { |
| 4 | 4 | constructor(attributes) { |
| 5 | − for (var key in attributes) { var value = attributes[key]; this[key] = value; } | |
| 5 | + for (var key in attributes) { | |
| 6 | + var value = attributes[key]; | |
| 7 | + this[key] = value; | |
| 8 | + } | |
| 6 | 9 | } |
| 7 | 10 | }; |
| @@ -13,14 +13,14 @@ app.models.Type = class Type extends app.Model { · 12 unmodified lines | ||
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | entries() { |
| 16 | − return this.doc.entries.findAllBy('type', this.name); | |
| 16 | + return this.doc.entries.findAllBy("type", this.name); | |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | toEntry() { |
| 20 | 20 | return new app.models.Entry({ |
| 21 | 21 | doc: this.doc, |
| 22 | 22 | name: `${this.doc.name} / ${this.name}`, |
| 23 | − path: '..' + this.fullPath() | |
| 23 | + path: ".." + this.fullPath(), | |
| 24 | 24 | }); |
| 25 | 25 | } |
| 26 | 26 | }; |
| @@ -6,14 +6,16 @@ · 5 unmodified lines | ||
| 6 | 6 | * DS102: Remove unnecessary code created because of implicit returns |
| 7 | 7 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 8 | 8 | */ |
| 9 | −app.templates.render = function(name, value, ...args) { | |
| 9 | +app.templates.render = function (name, value, ...args) { | |
| 10 | 10 | const template = app.templates[name]; |
| 11 | 11 | |
| 12 | 12 | if (Array.isArray(value)) { |
| 13 | − let result = ''; | |
| 14 | − for (var val of Array.from(value)) { result += template(val, ...Array.from(args)); } | |
| 13 | + let result = ""; | |
| 14 | + for (var val of Array.from(value)) { | |
| 15 | + result += template(val, ...Array.from(args)); | |
| 16 | + } | |
| 15 | 17 | return result; |
| 16 | − } else if (typeof template === 'function') { | |
| 18 | + } else if (typeof template === "function") { | |
| 17 | 19 | return template(value, ...Array.from(args)); |
| 18 | 20 | } else { |
| 19 | 21 | return template; |
| @@ -7,62 +7,79 @@ · 6 unmodified lines | ||
| 7 | 7 | * DS207: Consider shorter variations of null checks |
| 8 | 8 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 9 | 9 | */ |
| 10 | −const error = function(title, text, links) { | |
| 11 | − if (text == null) { text = ''; } | |
| 12 | − if (links == null) { links = ''; } | |
| 13 | − if (text) { text = `<p class="_error-text">${text}</p>`; } | |
| 14 | − if (links) { links = `<p class="_error-links">${links}</p>`; } | |
| 10 | +const error = function (title, text, links) { | |
| 11 | + if (text == null) { | |
| 12 | + text = ""; | |
| 13 | + } | |
| 14 | + if (links == null) { | |
| 15 | + links = ""; | |
| 16 | + } | |
| 17 | + if (text) { | |
| 18 | + text = `<p class="_error-text">${text}</p>`; | |
| 19 | + } | |
| 20 | + if (links) { | |
| 21 | + links = `<p class="_error-links">${links}</p>`; | |
| 22 | + } | |
| 15 | 23 | return `<div class="_error"><h1 class="_error-title">${title}</h1>${text}${links}</div>`; |
| 16 | 24 | }; |
| 17 | 25 | |
| 18 | 26 | const back = '<a href="#" data-behavior="back" class="_error-link">Go back</a>'; |
| 19 | 27 | |
| 20 | −app.templates.notFoundPage = () => error(" Page not found. ", | |
| 21 | − " It may be missing from the source documentation or this could be a bug. ", | |
| 22 | − back); | |
| 28 | +app.templates.notFoundPage = () => | |
| 29 | + error( | |
| 30 | + " Page not found. ", | |
| 31 | + " It may be missing from the source documentation or this could be a bug. ", | |
| 32 | + back, | |
| 33 | + ); | |
| 23 | 34 | |
| 24 | −app.templates.pageLoadError = () => error(" The page failed to load. ", | |
| 25 | − ` It may be missing from the server (try reloading the app) or you could be offline (try <a href="/offline">installing the documentation for offline usage</a> when online again).<br> | |
| 35 | +app.templates.pageLoadError = () => | |
| 36 | + error( | |
| 37 | + " The page failed to load. ", | |
| 38 | + ` It may be missing from the server (try reloading the app) or you could be offline (try <a href="/offline">installing the documentation for offline usage</a> when online again).<br> | |
| 26 | 39 | If you're online and you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. `, |
| 27 | − ` ${back} · <a href="/#${location.pathname}" target="_top" class="_error-link">Reload</a> | |
| 28 | −· <a href="#" class="_error-link" data-retry>Retry</a> ` | |
| 29 | −); | |
| 40 | + ` ${back} · <a href="/#${location.pathname}" target="_top" class="_error-link">Reload</a> | |
| 41 | +· <a href="#" class="_error-link" data-retry>Retry</a> `, | |
| 42 | + ); | |
| 30 | 43 | |
| 31 | −app.templates.bootError = () => error(" The app failed to load. ", | |
| 32 | − ` Check your Internet connection and try <a href="#" data-behavior="reload">reloading</a>.<br> | |
| 33 | −If you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. ` | |
| 34 | −); | |
| 44 | +app.templates.bootError = () => | |
| 45 | + error( | |
| 46 | + " The app failed to load. ", | |
| 47 | + ` Check your Internet connection and try <a href="#" data-behavior="reload">reloading</a>.<br> | |
| 48 | +If you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. `, | |
| 49 | + ); | |
| 35 | 50 | |
| 36 | −app.templates.offlineError = function(reason, exception) { | |
| 37 | − if (reason === 'cookie_blocked') { | |
| 51 | +app.templates.offlineError = function (reason, exception) { | |
| 52 | + if (reason === "cookie_blocked") { | |
| 38 | 53 | return error(" Cookies must be enabled to use offline mode. "); |
| 39 | 54 | } |
| 40 | 55 | |
| 41 | − reason = (() => { switch (reason) { | |
| 42 | − case 'not_supported': | |
| 43 | − return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> | |
| 56 | + reason = (() => { | |
| 57 | + switch (reason) { | |
| 58 | + case "not_supported": | |
| 59 | + return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> | |
| 44 | 60 | Unfortunately your browser either doesn't support IndexedDB or doesn't make it available. `; |
| 45 | − case 'buggy': | |
| 46 | − return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> | |
| 61 | + case "buggy": | |
| 62 | + return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> | |
| 47 | 63 | Unfortunately your browser's implementation of IndexedDB contains bugs that prevent DevDocs from using it. `; |
| 48 | − case 'private_mode': | |
| 49 | − return ` Your browser appears to be running in private mode.<br> | |
| 64 | + case "private_mode": | |
| 65 | + return ` Your browser appears to be running in private mode.<br> | |
| 50 | 66 | This prevents DevDocs from caching documentations for offline access.`; |
| 51 | − case 'exception': | |
| 52 | − return ` An error occurred when trying to open the IndexedDB database:<br> | |
| 67 | + case "exception": | |
| 68 | + return ` An error occurred when trying to open the IndexedDB database:<br> | |
| 53 | 69 | <code class="_label">${exception.name}: ${exception.message}</code> `; |
| 54 | − case 'cant_open': | |
| 55 | − return ` An error occurred when trying to open the IndexedDB database:<br> | |
| 70 | + case "cant_open": | |
| 71 | + return ` An error occurred when trying to open the IndexedDB database:<br> | |
| 56 | 72 | <code class="_label">${exception.name}: ${exception.message}</code><br> |
| 57 | 73 | This could be because you're browsing in private mode or have disallowed offline storage on the domain. `; |
| 58 | − case 'version': | |
| 59 | − return ` The IndexedDB database was modified with a newer version of the app.<br> | |
| 74 | + case "version": | |
| 75 | + return ` The IndexedDB database was modified with a newer version of the app.<br> | |
| 60 | 76 | <a href="#" data-behavior="reload">Reload the page</a> to use offline mode. `; |
| 61 | − case 'empty': | |
| 62 | − return " The IndexedDB database appears to be corrupted. Try <a href=\"#\" data-behavior=\"reset\">resetting the app</a>. "; | |
| 63 | − } })(); | |
| 77 | + case "empty": | |
| 78 | + return ' The IndexedDB database appears to be corrupted. Try <a href="#" data-behavior="reset">resetting the app</a>. '; | |
| 79 | + } | |
| 80 | + })(); | |
| 64 | 81 | |
| 65 | − return error('Offline mode is unavailable.', reason); | |
| 82 | + return error("Offline mode is unavailable.", reason); | |
| 66 | 83 | }; |
| 67 | 84 | |
| 68 | 85 | app.templates.unsupportedBrowser = `\ |
| @@ -5,12 +5,12 @@ · 4 unmodified lines | ||
| 5 | 5 | * DS102: Remove unnecessary code created because of implicit returns |
| 6 | 6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 7 | 7 | */ |
| 8 | −const notice = text => `<p class="_notice-text">${text}</p>`; | |
| 8 | +const notice = (text) => `<p class="_notice-text">${text}</p>`; | |
| 9 | 9 | |
| 10 | −app.templates.singleDocNotice = doc => notice(` You're browsing the ${doc.fullName} documentation. To browse all docs, go to | |
| 11 | −<a href="//${app.config.production_host}" target="_top">${app.config.production_host}</a> (or press <code>esc</code>). ` | |
| 12 | −); | |
| 10 | +app.templates.singleDocNotice = (doc) => | |
| 11 | + notice(` You're browsing the ${doc.fullName} documentation. To browse all docs, go to | |
| 12 | +<a href="//${app.config.production_host}" target="_top">${app.config.production_host}</a> (or press <code>esc</code>). `); | |
| 13 | 13 | |
| 14 | −app.templates.disabledDocNotice = () => notice(` <strong>This documentation is disabled.</strong> | |
| 15 | −To enable it, go to <a href="/settings" class="_notice-link">Preferences</a>. ` | |
| 16 | −); | |
| 14 | +app.templates.disabledDocNotice = () => | |
| 15 | + notice(` <strong>This documentation is disabled.</strong> | |
| 16 | +To enable it, go to <a href="/settings" class="_notice-link">Preferences</a>. `); | |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | * DS102: Remove unnecessary code created because of implicit returns |
| 7 | 7 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 8 | 8 | */ |
| 9 | −const notif = function(title, html) { | |
| 9 | +const notif = function (title, html) { | |
| 10 | 10 | html = html.replace(/<a /g, '<a class="_notif-link" '); |
| 11 | 11 | return ` <h5 class="_notif-title">${title}</h5> |
| 12 | 12 | ${html} |
| @@ -14,32 +14,56 @@ ${html} · 1 unmodified line | ||
| 14 | 14 | `; |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | −const textNotif = (title, message) => notif(title, `<p class="_notif-text">${message}`); | |
| 17 | +const textNotif = (title, message) => | |
| 18 | + notif(title, `<p class="_notif-text">${message}`); | |
| 18 | 19 | |
| 19 | −app.templates.notifUpdateReady = () => textNotif("<span data-behavior=\"reboot\">DevDocs has been updated.</span>", | |
| 20 | − "<span data-behavior=\"reboot\"><a href=\"#\" data-behavior=\"reboot\">Reload the page</a> to use the new version.</span>"); | |
| 20 | +app.templates.notifUpdateReady = () => | |
| 21 | + textNotif( | |
| 22 | + '<span data-behavior="reboot">DevDocs has been updated.</span>', | |
| 23 | + '<span data-behavior="reboot"><a href="#" data-behavior="reboot">Reload the page</a> to use the new version.</span>', | |
| 24 | + ); | |
| 21 | 25 | |
| 22 | −app.templates.notifError = () => textNotif(" Oops, an error occurred. ", | |
| 23 | − ` Try <a href="#" data-behavior="hard-reload">reloading</a>, and if the problem persists, | |
| 26 | +app.templates.notifError = () => | |
| 27 | + textNotif( | |
| 28 | + " Oops, an error occurred. ", | |
| 29 | + ` Try <a href="#" data-behavior="hard-reload">reloading</a>, and if the problem persists, | |
| 24 | 30 | <a href="#" data-behavior="reset">resetting the app</a>.<br> |
| 25 | −You can also report this issue on <a href="https://github.com/freeCodeCamp/devdocs/issues/new" target="_blank" rel="noopener">GitHub</a>. ` | |
| 26 | −); | |
| 31 | +You can also report this issue on <a href="https://github.com/freeCodeCamp/devdocs/issues/new" target="_blank" rel="noopener">GitHub</a>. `, | |
| 32 | + ); | |
| 27 | 33 | |
| 28 | −app.templates.notifQuotaExceeded = () => textNotif(" The offline database has exceeded its size limitation. ", | |
| 29 | − " Unfortunately this quota can't be detected programmatically, and the database can't be opened while over the quota, so it had to be reset. "); | |
| 34 | +app.templates.notifQuotaExceeded = () => | |
| 35 | + textNotif( | |
| 36 | + " The offline database has exceeded its size limitation. ", | |
| 37 | + " Unfortunately this quota can't be detected programmatically, and the database can't be opened while over the quota, so it had to be reset. ", | |
| 38 | + ); | |
| 30 | 39 | |
| 31 | −app.templates.notifCookieBlocked = () => textNotif(" Please enable cookies. ", | |
| 32 | − " DevDocs will not work properly if cookies are disabled. "); | |
| 40 | +app.templates.notifCookieBlocked = () => | |
| 41 | + textNotif( | |
| 42 | + " Please enable cookies. ", | |
| 43 | + " DevDocs will not work properly if cookies are disabled. ", | |
| 44 | + ); | |
| 33 | 45 | |
| 34 | −app.templates.notifInvalidLocation = () => textNotif(` DevDocs must be loaded from ${app.config.production_host} `, | |
| 35 | − " Otherwise things are likely to break. "); | |
| 46 | +app.templates.notifInvalidLocation = () => | |
| 47 | + textNotif( | |
| 48 | + ` DevDocs must be loaded from ${app.config.production_host} `, | |
| 49 | + " Otherwise things are likely to break. ", | |
| 50 | + ); | |
| 36 | 51 | |
| 37 | −app.templates.notifImportInvalid = () => textNotif(" Oops, an error occurred. ", | |
| 38 | − " The file you selected is invalid. "); | |
| 52 | +app.templates.notifImportInvalid = () => | |
| 53 | + textNotif( | |
| 54 | + " Oops, an error occurred. ", | |
| 55 | + " The file you selected is invalid. ", | |
| 56 | + ); | |
| 39 | 57 | |
| 40 | −app.templates.notifNews = news => notif('Changelog', `<div class="_notif-content _notif-news">${app.templates.newsList(news, {years: false})}</div>`); | |
| 58 | +app.templates.notifNews = (news) => | |
| 59 | + notif( | |
| 60 | + "Changelog", | |
| 61 | + `<div class="_notif-content _notif-news">${app.templates.newsList(news, { | |
| 62 | + years: false, | |
| 63 | + })}</div>`, | |
| 64 | + ); | |
| 41 | 65 | |
| 42 | −app.templates.notifUpdates = function(docs, disabledDocs) { | |
| 66 | +app.templates.notifUpdates = function (docs, disabledDocs) { | |
| 43 | 67 | let doc; |
| 44 | 68 | let html = '<div class="_notif-content _notif-news">'; |
| 45 | 69 | |
| @@ -48,9 +72,11 @@ app.templates.notifUpdates = function(docs, disabledDocs) { · 2 unmodified lines | ||
| 48 | 72 | html += '<ul class="_notif-list">'; |
| 49 | 73 | for (doc of Array.from(docs)) { |
| 50 | 74 | html += `<li>${doc.name}`; |
| 51 | − if (doc.release) { html += ` <code>→</code> ${doc.release}`; } | |
| 75 | + if (doc.release) { | |
| 76 | + html += ` <code>→</code> ${doc.release}`; | |
| 77 | + } | |
| 52 | 78 | } |
| 53 | − html += '</ul></div>'; | |
| 79 | + html += "</ul></div>"; | |
| 54 | 80 | } |
| 55 | 81 | |
| 56 | 82 | if (disabledDocs.length > 0) { |
| @@ -58,26 +84,35 @@ app.templates.notifUpdates = function(docs, disabledDocs) { · 1 unmodified line | ||
| 58 | 84 | html += '<ul class="_notif-list">'; |
| 59 | 85 | for (doc of Array.from(disabledDocs)) { |
| 60 | 86 | html += `<li>${doc.name}`; |
| 61 | − if (doc.release) { html += ` <code>→</code> ${doc.release}`; } | |
| 62 | − html += "<span class=\"_notif-info\"><a href=\"/settings\">Enable</a></span>"; | |
| 87 | + if (doc.release) { | |
| 88 | + html += ` <code>→</code> ${doc.release}`; | |
| 89 | + } | |
| 90 | + html += '<span class="_notif-info"><a href="/settings">Enable</a></span>'; | |
| 63 | 91 | } |
| 64 | − html += '</ul></div>'; | |
| 92 | + html += "</ul></div>"; | |
| 65 | 93 | } |
| 66 | 94 | |
| 67 | − return notif('Updates', `${html}</div>`); | |
| 95 | + return notif("Updates", `${html}</div>`); | |
| 68 | 96 | }; |
| 69 | 97 | |
| 70 | −app.templates.notifShare = () => textNotif(" Hi there! ", | |
| 71 | − ` Like DevDocs? Help us reach more developers by sharing the link with your friends on | |
| 98 | +app.templates.notifShare = () => | |
| 99 | + textNotif( | |
| 100 | + " Hi there! ", | |
| 101 | + ` Like DevDocs? Help us reach more developers by sharing the link with your friends on | |
| 72 | 102 | <a href="https://out.devdocs.io/s/tw" target="_blank" rel="noopener">Twitter</a>, <a href="https://out.devdocs.io/s/fb" target="_blank" rel="noopener">Facebook</a>, |
| 73 | −<a href="https://out.devdocs.io/s/re" target="_blank" rel="noopener">Reddit</a>, etc.<br>Thanks :) ` | |
| 74 | −); | |
| 103 | +<a href="https://out.devdocs.io/s/re" target="_blank" rel="noopener">Reddit</a>, etc.<br>Thanks :) `, | |
| 104 | + ); | |
| 75 | 105 | |
| 76 | −app.templates.notifUpdateDocs = () => textNotif(" Documentation updates available. ", | |
| 77 | − " <a href=\"/offline\">Install them</a> as soon as possible to avoid broken pages. "); | |
| 106 | +app.templates.notifUpdateDocs = () => | |
| 107 | + textNotif( | |
| 108 | + " Documentation updates available. ", | |
| 109 | + ' <a href="/offline">Install them</a> as soon as possible to avoid broken pages. ', | |
| 110 | + ); | |
| 78 | 111 | |
| 79 | −app.templates.notifAnalyticsConsent = () => textNotif(" Tracking cookies ", | |
| 80 | − ` We would like to gather usage data about how DevDocs is used through Google Analytics and Gauges. We only collect anonymous traffic information. | |
| 112 | +app.templates.notifAnalyticsConsent = () => | |
| 113 | + textNotif( | |
| 114 | + " Tracking cookies ", | |
| 115 | + ` We would like to gather usage data about how DevDocs is used through Google Analytics and Gauges. We only collect anonymous traffic information. | |
| 81 | 116 | Please confirm if you accept our tracking cookies. You can always change your decision in the settings. |
| 82 | −<br><span class="_notif-right"><a href="#" data-behavior="accept-analytics">Accept</a> or <a href="#" data-behavior="decline-analytics">Decline</a></span> ` | |
| 83 | −); | |
| 117 | +<br><span class="_notif-right"><a href="#" data-behavior="accept-analytics">Accept</a> or <a href="#" data-behavior="decline-analytics">Decline</a></span> `, | |
| 118 | + ); | |
| @@ -8,12 +8,18 @@ · 7 unmodified lines | ||
| 8 | 8 | * DS207: Consider shorter variations of null checks |
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | −app.templates.aboutPage = function() { | |
| 11 | +app.templates.aboutPage = function () { | |
| 12 | 12 | let doc; |
| 13 | − const all_docs = app.docs.all().concat(...Array.from(app.disabledDocs.all() || [])); | |
| 13 | + const all_docs = app.docs | |
| 14 | + .all() | |
| 15 | + .concat(...Array.from(app.disabledDocs.all() || [])); | |
| 14 | 16 | // de-duplicate docs by doc.name |
| 15 | 17 | const docs = []; |
| 16 | − for (doc of Array.from(all_docs)) { if (!(docs.find(d => d.name === doc.name))) { docs.push(doc); } } | |
| 18 | + for (doc of Array.from(all_docs)) { | |
| 19 | + if (!docs.find((d) => d.name === doc.name)) { | |
| 20 | + docs.push(doc); | |
| 21 | + } | |
| 22 | + } | |
| 17 | 23 | return `\ |
| 18 | 24 | <nav class="_toc" role="directory"> |
| 19 | 25 | <h3 class="_toc-title">Table of Contents</h3> |
| @@ -79,18 +85,23 @@ app.templates.aboutPage = function() { · 59 unmodified lines | ||
| 79 | 85 | <th>Documentation |
| 80 | 86 | <th>Copyright/License |
| 81 | 87 | <th>Source code |
| 82 | − ${((() => { | |
| 83 | − const result = []; | |
| 84 | − | |
| 85 | − for (doc of Array.from(docs)) { result.push(`<tr> \ | |
| 86 | −<td><a href=\"${(doc.links != null ? doc.links.home : undefined)}\">${doc.name}</a></td> \ | |
| 88 | + ${(() => { | |
| 89 | + const result = []; | |
| 90 | + | |
| 91 | + for (doc of Array.from(docs)) { | |
| 92 | + result.push(`<tr> \ | |
| 93 | +<td><a href=\"${doc.links != null ? doc.links.home : undefined}\">${ | |
| 94 | + doc.name | |
| 95 | + }</a></td> \ | |
| 87 | 96 | <td>${doc.attribution}</td> \ |
| 88 | −<td><a href=\"${(doc.links != null ? doc.links.code : undefined)}\">Source code</a></td> \ | |
| 97 | +<td><a href=\"${ | |
| 98 | + doc.links != null ? doc.links.code : undefined | |
| 99 | + }\">Source code</a></td> \ | |
| 89 | 100 | </tr>`); |
| 90 | − } | |
| 91 | − | |
| 92 | − return result; | |
| 93 | − })()).join('')} | |
| 101 | + } | |
| 102 | + | |
| 103 | + return result; | |
| 104 | + })().join("")} | |
| 94 | 105 | </table> |
| 95 | 106 | </div> |
| 96 | 107 | |
| @@ -6,11 +6,11 @@ · 5 unmodified lines | ||
| 6 | 6 | * DS205: Consider reworking code to avoid use of IIFEs |
| 7 | 7 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 8 | 8 | */ |
| 9 | −app.templates.helpPage = function() { | |
| 9 | +app.templates.helpPage = function () { | |
| 10 | 10 | let key, value; |
| 11 | − const ctrlKey = $.isMac() ? 'cmd' : 'ctrl'; | |
| 12 | − const navKey = $.isMac() ? 'cmd' : 'alt'; | |
| 13 | − const arrowScroll = app.settings.get('arrowScroll'); | |
| 11 | + const ctrlKey = $.isMac() ? "cmd" : "ctrl"; | |
| 12 | + const navKey = $.isMac() ? "cmd" : "alt"; | |
| 13 | + const arrowScroll = app.settings.get("arrowScroll"); | |
| 14 | 14 | |
| 15 | 15 | const aliases_one = {}; |
| 16 | 16 | const aliases_two = {}; |
| @@ -18,7 +18,8 @@ app.templates.helpPage = function() { · 1 unmodified line | ||
| 18 | 18 | const middle = Math.ceil(keys.length / 2) - 1; |
| 19 | 19 | for (let i = 0; i < keys.length; i++) { |
| 20 | 20 | key = keys[i]; |
| 21 | − (i > middle ? aliases_two : aliases_one)[key] = app.models.Entry.ALIASES[key]; | |
| 21 | + (i > middle ? aliases_two : aliases_one)[key] = | |
| 22 | + app.models.Entry.ALIASES[key]; | |
| 22 | 23 | } |
| 23 | 24 | |
| 24 | 25 | return `\ |
| @@ -79,12 +80,12 @@ app.templates.helpPage = function() { · 54 unmodified lines | ||
| 79 | 80 | <h3 class="_shortcuts-title">Sidebar</h3> |
| 80 | 81 | <dl class="_shortcuts-dl"> |
| 81 | 82 | <dt class="_shortcuts-dt"> |
| 82 | − ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ''} | |
| 83 | + ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ""} | |
| 83 | 84 | <code class="_shortcut-code">↓</code> |
| 84 | 85 | <code class="_shortcut-code">↑</code> |
| 85 | 86 | <dd class="_shortcuts-dd">Move selection |
| 86 | 87 | <dt class="_shortcuts-dt"> |
| 87 | − ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ''} | |
| 88 | + ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ""} | |
| 88 | 89 | <code class="_shortcut-code">→</code> |
| 89 | 90 | <code class="_shortcut-code">←</code> |
| 90 | 91 | <dd class="_shortcuts-dd">Show/hide sub-list |
| @@ -105,15 +106,16 @@ app.templates.helpPage = function() { · 14 unmodified lines | ||
| 105 | 106 | <code class="_shortcut-code">${navKey} + →</code> |
| 106 | 107 | <dd class="_shortcuts-dd">Go back/forward |
| 107 | 108 | <dt class="_shortcuts-dt"> |
| 108 | − ${arrowScroll ? | |
| 109 | − '<code class="_shortcut-code">↓</code> ' + | |
| 109 | + ${ | |
| 110 | + arrowScroll | |
| 111 | + ? '<code class="_shortcut-code">↓</code> ' + | |
| 110 | 112 | '<code class="_shortcut-code">↑</code>' |
| 111 | − : | |
| 112 | − '<code class="_shortcut-code">alt + ↓</code> ' + | |
| 113 | + : '<code class="_shortcut-code">alt + ↓</code> ' + | |
| 113 | 114 | '<code class="_shortcut-code">alt + ↑</code>' + |
| 114 | − '<br>' + | |
| 115 | + "<br>" + | |
| 115 | 116 | '<code class="_shortcut-code">shift + ↓</code> ' + |
| 116 | − '<code class="_shortcut-code">shift + ↑</code>'} | |
| 117 | + '<code class="_shortcut-code">shift + ↑</code>' | |
| 118 | + } | |
| 117 | 119 | <dd class="_shortcuts-dd">Scroll step by step<br><br> |
| 118 | 120 | <dt class="_shortcuts-dt"> |
| 119 | 121 | <code class="_shortcut-code">space</code> |
| @@ -167,27 +169,31 @@ app.templates.helpPage = function() { · 47 unmodified lines | ||
| 167 | 169 | <tr> |
| 168 | 170 | <th>Word |
| 169 | 171 | <th>Alias |
| 170 | − ${((() => { | |
| 171 | − const result = []; | |
| 172 | − for (key in aliases_one) { | |
| 173 | − value = aliases_one[key]; | |
| 174 | − result.push(`<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`); | |
| 175 | − } | |
| 176 | − return result; | |
| 177 | − })()).join('')} | |
| 172 | + ${(() => { | |
| 173 | + const result = []; | |
| 174 | + for (key in aliases_one) { | |
| 175 | + value = aliases_one[key]; | |
| 176 | + result.push( | |
| 177 | + `<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`, | |
| 178 | + ); | |
| 179 | + } | |
| 180 | + return result; | |
| 181 | + })().join("")} | |
| 178 | 182 | </table> |
| 179 | 183 | <table> |
| 180 | 184 | <tr> |
| 181 | 185 | <th>Word |
| 182 | 186 | <th>Alias |
| 183 | − ${((() => { | |
| 184 | − const result1 = []; | |
| 185 | − for (key in aliases_two) { | |
| 186 | − value = aliases_two[key]; | |
| 187 | − result1.push(`<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`); | |
| 188 | − } | |
| 189 | − return result1; | |
| 190 | − })()).join('')} | |
| 187 | + ${(() => { | |
| 188 | + const result1 = []; | |
| 189 | + for (key in aliases_two) { | |
| 190 | + value = aliases_two[key]; | |
| 191 | + result1.push( | |
| 192 | + `<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`, | |
| 193 | + ); | |
| 194 | + } | |
| 195 | + return result1; | |
| 196 | + })().join("")} | |
| 191 | 197 | </table> |
| 192 | 198 | </div> |
| 193 | 199 | <p>Feel free to suggest new aliases on <a href="https://github.com/freeCodeCamp/devdocs/issues/new">GitHub</a>.\ |
| @@ -5,12 +5,14 @@ · 4 unmodified lines | ||
| 5 | 5 | * DS102: Remove unnecessary code created because of implicit returns |
| 6 | 6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 7 | 7 | */ |
| 8 | −app.templates.offlinePage = docs => `\ | |
| 8 | +app.templates.offlinePage = (docs) => `\ | |
| 9 | 9 | <h1 class="_lined-heading">Offline Documentation</h1> |
| 10 | 10 | |
| 11 | 11 | <div class="_docs-tools"> |
| 12 | 12 | <label> |
| 13 | − <input type="checkbox" name="autoUpdate" value="1" ${app.settings.get('manualUpdate') ? '' : 'checked'}>Install updates automatically | |
| 13 | + <input type="checkbox" name="autoUpdate" value="1" ${ | |
| 14 | + app.settings.get("manualUpdate") ? "" : "checked" | |
| 15 | + }>Install updates automatically | |
| 14 | 16 | </label> |
| 15 | 17 | <div class="_docs-links"> |
| 16 | 18 | <button type="button" class="_btn-link" data-action-all="install">Install all</button><button type="button" class="_btn-link" data-action-all="update"><strong>Update all</strong></button><button type="button" class="_btn-link" data-action-all="uninstall">Uninstall all</button> |
| @@ -47,14 +49,15 @@ app.templates.offlinePage = docs => `\ · 30 unmodified lines | ||
| 47 | 49 | </dl>\ |
| 48 | 50 | `; |
| 49 | 51 | |
| 50 | −var canICloseTheTab = function() { | |
| 52 | +var canICloseTheTab = function () { | |
| 51 | 53 | if (app.ServiceWorker.isEnabled()) { |
| 52 | − return " Yes! Even offline, you can open a new tab, go to <a href=\"//devdocs.io\">devdocs.io</a>, and everything will work as if you were online (provided you installed all the documentations you want to use beforehand). "; | |
| 54 | + return ' Yes! Even offline, you can open a new tab, go to <a href="//devdocs.io">devdocs.io</a>, and everything will work as if you were online (provided you installed all the documentations you want to use beforehand). '; | |
| 53 | 55 | } else { |
| 54 | 56 | let reason = "aren't available in your browser (or are disabled)"; |
| 55 | 57 | |
| 56 | − if (app.config.env !== 'production') { | |
| 57 | − reason = "are disabled in your development instance of DevDocs (enable them by setting the <code>ENABLE_SERVICE_WORKER</code> environment variable to <code>true</code>)"; | |
| 58 | + if (app.config.env !== "production") { | |
| 59 | + reason = | |
| 60 | + "are disabled in your development instance of DevDocs (enable them by setting the <code>ENABLE_SERVICE_WORKER</code> environment variable to <code>true</code>)"; | |
| 58 | 61 | } |
| 59 | 62 | |
| 60 | 63 | return ` No. Service Workers ${reason}, so loading <a href="//devdocs.io">devdocs.io</a> offline won't work.<br> |
| @@ -62,30 +65,31 @@ The current tab will continue to function even when you go offline (provided you · 1 unmodified line | ||
| 62 | 65 | } |
| 63 | 66 | }; |
| 64 | 67 | |
| 65 | −app.templates.offlineDoc = function(doc, status) { | |
| 68 | +app.templates.offlineDoc = function (doc, status) { | |
| 66 | 69 | const outdated = doc.isOutdated(status); |
| 67 | 70 | |
| 68 | 71 | let html = `\ |
| 69 | −<tr data-slug="${doc.slug}"${outdated ? ' class="_highlight"' : ''}> | |
| 72 | +<tr data-slug="${doc.slug}"${outdated ? ' class="_highlight"' : ""}> | |
| 70 | 73 | <td class="_docs-name _icon-${doc.icon}">${doc.fullName}</td> |
| 71 | − <td class="_docs-size">${Math.ceil(doc.db_size / 100000) / 10} <small>MB</small></td>\ | |
| 74 | + <td class="_docs-size">${ | |
| 75 | + Math.ceil(doc.db_size / 100000) / 10 | |
| 76 | + } <small>MB</small></td>\ | |
| 72 | 77 | `; |
| 73 | 78 | |
| 74 | − html += !(status && status.installed) ? | |
| 75 | − `\ | |
| 79 | + html += !(status && status.installed) | |
| 80 | + ? `\ | |
| 76 | 81 | <td>-</td> |
| 77 | 82 | <td><button type="button" class="_btn-link" data-action="install">Install</button></td>\ |
| 78 | 83 | ` |
| 79 | − : outdated ? | |
| 80 | − `\ | |
| 84 | + : outdated | |
| 85 | + ? `\ | |
| 81 | 86 | <td><strong>Outdated</strong></td> |
| 82 | 87 | <td><button type="button" class="_btn-link _bold" data-action="update">Update</button> - <button type="button" class="_btn-link" data-action="uninstall">Uninstall</button></td>\ |
| 83 | 88 | ` |
| 84 | − : | |
| 85 | − `\ | |
| 89 | + : `\ | |
| 86 | 90 | <td>Up‑to‑date</td> |
| 87 | 91 | <td><button type="button" class="_btn-link" data-action="uninstall">Uninstall</button></td>\ |
| 88 | 92 | `; |
| 89 | 93 | |
| 90 | − return html + '</tr>'; | |
| 94 | + return html + "</tr>"; | |
| 91 | 95 | }; |
| @@ -7,23 +7,32 @@ · 6 unmodified lines | ||
| 7 | 7 | */ |
| 8 | 8 | const themeOption = ({ label, value }, settings) => `\ |
| 9 | 9 | <label class="_settings-label _theme-label"> |
| 10 | − <input type="radio" name="theme" value="${value}"${settings.theme === value ? ' checked' : ''}> | |
| 10 | + <input type="radio" name="theme" value="${value}"${ | |
| 11 | + settings.theme === value ? " checked" : "" | |
| 12 | + }> | |
| 11 | 13 | ${label} |
| 12 | 14 | </label>\ |
| 13 | 15 | `; |
| 14 | 16 | |
| 15 | −app.templates.settingsPage = settings => `\ | |
| 17 | +app.templates.settingsPage = (settings) => `\ | |
| 16 | 18 | <h1 class="_lined-heading">Preferences</h1> |
| 17 | 19 | |
| 18 | 20 | <div class="_settings-fieldset"> |
| 19 | 21 | <h2 class="_settings-legend">Theme:</h2> |
| 20 | 22 | <div class="_settings-inputs"> |
| 21 | − ${settings.autoSupported ? | |
| 22 | − themeOption({label: "Automatic <small>Matches system setting</small>", value: "auto"}, settings) | |
| 23 | − : | |
| 24 | − ""} | |
| 25 | − ${themeOption({label: "Light", value: "default"}, settings)} | |
| 26 | − ${themeOption({label: "Dark", value: "dark"}, settings)} | |
| 23 | + ${ | |
| 24 | + settings.autoSupported | |
| 25 | + ? themeOption( | |
| 26 | + { | |
| 27 | + label: "Automatic <small>Matches system setting</small>", | |
| 28 | + value: "auto", | |
| 29 | + }, | |
| 30 | + settings, | |
| 31 | + ) | |
| 32 | + : "" | |
| 33 | + } | |
| 34 | + ${themeOption({ label: "Light", value: "default" }, settings)} | |
| 35 | + ${themeOption({ label: "Dark", value: "dark" }, settings)} | |
| 27 | 36 | </div> |
| 28 | 37 | </div> |
| 29 | 38 | |
| @@ -32,24 +41,36 @@ app.templates.settingsPage = settings => `\ · 2 unmodified lines | ||
| 32 | 41 | |
| 33 | 42 | <div class="_settings-inputs"> |
| 34 | 43 | <label class="_settings-label _setting-max-width"> |
| 35 | − <input type="checkbox" form="settings" name="layout" value="_max-width"${settings['_max-width'] ? ' checked' : ''}>Enable fixed-width layout | |
| 44 | + <input type="checkbox" form="settings" name="layout" value="_max-width"${ | |
| 45 | + settings["_max-width"] ? " checked" : "" | |
| 46 | + }>Enable fixed-width layout | |
| 36 | 47 | </label> |
| 37 | 48 | <label class="_settings-label _setting-text-justify-hyphenate"> |
| 38 | − <input type="checkbox" form="settings" name="layout" value="_text-justify-hyphenate"${settings['_text-justify-hyphenate'] ? ' checked' : ''}>Enable justified layout and automatic hyphenation | |
| 49 | + <input type="checkbox" form="settings" name="layout" value="_text-justify-hyphenate"${ | |
| 50 | + settings["_text-justify-hyphenate"] ? " checked" : "" | |
| 51 | + }>Enable justified layout and automatic hyphenation | |
| 39 | 52 | </label> |
| 40 | 53 | <label class="_settings-label _hide-on-mobile"> |
| 41 | − <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"${settings['_sidebar-hidden'] ? ' checked' : ''}>Automatically hide and show the sidebar | |
| 54 | + <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"${ | |
| 55 | + settings["_sidebar-hidden"] ? " checked" : "" | |
| 56 | + }>Automatically hide and show the sidebar | |
| 42 | 57 | <small>Tip: drag the edge of the sidebar to resize it.</small> |
| 43 | 58 | </label> |
| 44 | 59 | <label class="_settings-label _hide-on-mobile"> |
| 45 | − <input type="checkbox" form="settings" name="noAutofocus" value="_no-autofocus"${settings.noAutofocus ? ' checked' : ''}>Disable autofocus of search input | |
| 60 | + <input type="checkbox" form="settings" name="noAutofocus" value="_no-autofocus"${ | |
| 61 | + settings.noAutofocus ? " checked" : "" | |
| 62 | + }>Disable autofocus of search input | |
| 46 | 63 | </label> |
| 47 | 64 | <label class="_settings-label"> |
| 48 | − <input type="checkbox" form="settings" name="autoInstall" value="_auto-install"${settings.autoInstall ? ' checked' : ''}>Automatically download documentation for offline use | |
| 65 | + <input type="checkbox" form="settings" name="autoInstall" value="_auto-install"${ | |
| 66 | + settings.autoInstall ? " checked" : "" | |
| 67 | + }>Automatically download documentation for offline use | |
| 49 | 68 | <small>Only enable this when bandwidth isn't a concern to you.</small> |
| 50 | 69 | </label> |
| 51 | 70 | <label class="_settings-label _hide-in-development"> |
| 52 | − <input type="checkbox" form="settings" name="analyticsConsent"${settings.analyticsConsent ? ' checked' : ''}>Enable tracking cookies | |
| 71 | + <input type="checkbox" form="settings" name="analyticsConsent"${ | |
| 72 | + settings.analyticsConsent ? " checked" : "" | |
| 73 | + }>Enable tracking cookies | |
| 53 | 74 | <small>With this checked, we enable Google Analytics and Gauges to collect anonymous traffic information.</small> |
| 54 | 75 | </label> |
| 55 | 76 | </div> |
| @@ -60,20 +81,30 @@ app.templates.settingsPage = settings => `\ · 4 unmodified lines | ||
| 60 | 81 | |
| 61 | 82 | <div class="_settings-inputs"> |
| 62 | 83 | <label class="_settings-label"> |
| 63 | − <input type="checkbox" form="settings" name="smoothScroll" value="1"${settings.smoothScroll ? ' checked' : ''}>Use smooth scrolling | |
| 84 | + <input type="checkbox" form="settings" name="smoothScroll" value="1"${ | |
| 85 | + settings.smoothScroll ? " checked" : "" | |
| 86 | + }>Use smooth scrolling | |
| 64 | 87 | </label> |
| 65 | 88 | <label class="_settings-label _setting-native-scrollbar"> |
| 66 | − <input type="checkbox" form="settings" name="layout" value="_native-scrollbars"${settings['_native-scrollbars'] ? ' checked' : ''}>Use native scrollbars | |
| 89 | + <input type="checkbox" form="settings" name="layout" value="_native-scrollbars"${ | |
| 90 | + settings["_native-scrollbars"] ? " checked" : "" | |
| 91 | + }>Use native scrollbars | |
| 67 | 92 | </label> |
| 68 | 93 | <label class="_settings-label"> |
| 69 | − <input type="checkbox" form="settings" name="arrowScroll" value="1"${settings.arrowScroll ? ' checked' : ''}>Use arrow keys to scroll the main content area | |
| 94 | + <input type="checkbox" form="settings" name="arrowScroll" value="1"${ | |
| 95 | + settings.arrowScroll ? " checked" : "" | |
| 96 | + }>Use arrow keys to scroll the main content area | |
| 70 | 97 | <small>With this checked, use <code class="_label">shift</code> + <code class="_label">↑</code><code class="_label">↓</code><code class="_label">←</code><code class="_label">→</code> to navigate the sidebar.</small> |
| 71 | 98 | </label> |
| 72 | 99 | <label class="_settings-label"> |
| 73 | − <input type="checkbox" form="settings" name="spaceScroll" value="1"${settings.spaceScroll ? ' checked' : ''}>Use spacebar to scroll during search | |
| 100 | + <input type="checkbox" form="settings" name="spaceScroll" value="1"${ | |
| 101 | + settings.spaceScroll ? " checked" : "" | |
| 102 | + }>Use spacebar to scroll during search | |
| 74 | 103 | </label> |
| 75 | 104 | <label class="_settings-label"> |
| 76 | − <input type="number" step="0.1" form="settings" name="spaceTimeout" min="0" max="5" value="${settings.spaceTimeout}"> Delay until you can scroll by pressing space | |
| 105 | + <input type="number" step="0.1" form="settings" name="spaceTimeout" min="0" max="5" value="${ | |
| 106 | + settings.spaceTimeout | |
| 107 | + }"> Delay until you can scroll by pressing space | |
| 77 | 108 | <small>Time in seconds</small> |
| 78 | 109 | </label> |
| 79 | 110 | </div> |
| @@ -5,7 +5,13 @@ · 4 unmodified lines | ||
| 5 | 5 | * DS102: Remove unnecessary code created because of implicit returns |
| 6 | 6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 7 | 7 | */ |
| 8 | −app.templates.typePage = type => ` <h1>${type.doc.fullName} / ${type.name}</h1> | |
| 9 | −<ul class="_entry-list">${app.templates.render('typePageEntry', type.entries())}</ul> `; | |
| 8 | +app.templates.typePage = (type) => ` <h1>${type.doc.fullName} / ${ | |
| 9 | + type.name | |
| 10 | +}</h1> | |
| 11 | +<ul class="_entry-list">${app.templates.render( | |
| 12 | + "typePageEntry", | |
| 13 | + type.entries(), | |
| 14 | +)}</ul> `; | |
| 10 | 15 | |
| 11 | −app.templates.typePageEntry = entry => `<li><a href="${entry.fullPath()}">${$.escape(entry.name)}</a></li>`; | |
| 16 | +app.templates.typePageEntry = (entry) => | |
| 17 | + `<li><a href="${entry.fullPath()}">${$.escape(entry.name)}</a></li>`; | |
| @@ -5,11 +5,19 @@ · 4 unmodified lines | ||
| 5 | 5 | * DS102: Remove unnecessary code created because of implicit returns |
| 6 | 6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 7 | 7 | */ |
| 8 | −const arrow = "<svg class=\"_path-arrow\"><use xlink:href=\"#icon-dir\"/></svg>"; | |
| 8 | +const arrow = '<svg class="_path-arrow"><use xlink:href="#icon-dir"/></svg>'; | |
| 9 | 9 | |
| 10 | −app.templates.path = function(doc, type, entry) { | |
| 11 | − let html = `<a href="${doc.fullPath()}" class="_path-item _icon-${doc.icon}">${doc.fullName}</a>`; | |
| 12 | − if (type) { html += `${arrow}<a href="${type.fullPath()}" class="_path-item">${type.name}</a>`; } | |
| 13 | − if (entry) { html += `${arrow}<span class="_path-item">${$.escape(entry.name)}</span>`; } | |
| 10 | +app.templates.path = function (doc, type, entry) { | |
| 11 | + let html = `<a href="${doc.fullPath()}" class="_path-item _icon-${ | |
| 12 | + doc.icon | |
| 13 | + }">${doc.fullName}</a>`; | |
| 14 | + if (type) { | |
| 15 | + html += `${arrow}<a href="${type.fullPath()}" class="_path-item">${ | |
| 16 | + type.name | |
| 17 | + }</a>`; | |
| 18 | + } | |
| 19 | + if (entry) { | |
| 20 | + html += `${arrow}<span class="_path-item">${$.escape(entry.name)}</span>`; | |
| 21 | + } | |
| 14 | 22 | return html; |
| 15 | 23 | }; |
| @@ -6,74 +6,112 @@ · 5 unmodified lines | ||
| 6 | 6 | * DS207: Consider shorter variations of null checks |
| 7 | 7 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 8 | 8 | */ |
| 9 | −const { | |
| 10 | − templates | |
| 11 | −} = app; | |
| 9 | +const { templates } = app; | |
| 12 | 10 | |
| 13 | −const arrow = "<svg class=\"_list-arrow\"><use xlink:href=\"#icon-dir\"/></svg>"; | |
| 11 | +const arrow = '<svg class="_list-arrow"><use xlink:href="#icon-dir"/></svg>'; | |
| 14 | 12 | |
| 15 | −templates.sidebarDoc = function(doc, options) { | |
| 16 | − if (options == null) { options = {}; } | |
| 17 | − let link = `<a href="${doc.fullPath()}" class="_list-item _icon-${doc.icon} `; | |
| 18 | − link += options.disabled ? '_list-disabled' : '_list-dir'; | |
| 13 | +templates.sidebarDoc = function (doc, options) { | |
| 14 | + if (options == null) { | |
| 15 | + options = {}; | |
| 16 | + } | |
| 17 | + let link = `<a href="${doc.fullPath()}" class="_list-item _icon-${doc.icon} `; | |
| 18 | + link += options.disabled ? "_list-disabled" : "_list-dir"; | |
| 19 | 19 | link += `" data-slug="${doc.slug}" title="${doc.fullName}" tabindex="-1">`; |
| 20 | 20 | if (options.disabled) { |
| 21 | 21 | link += `<span class="_list-enable" data-enable="${doc.slug}">Enable</span>`; |
| 22 | 22 | } else { |
| 23 | 23 | link += arrow; |
| 24 | 24 | } |
| 25 | − if (doc.release) { link += `<span class="_list-count">${doc.release}</span>`; } | |
| 25 | + if (doc.release) { | |
| 26 | + link += `<span class="_list-count">${doc.release}</span>`; | |
| 27 | + } | |
| 26 | 28 | link += `<span class="_list-text">${doc.name}`; |
| 27 | − if (options.fullName || (options.disabled && doc.version)) { link += ` ${doc.version}`; } | |
| 29 | + if (options.fullName || (options.disabled && doc.version)) { | |
| 30 | + link += ` ${doc.version}`; | |
| 31 | + } | |
| 28 | 32 | return link + "</span></a>"; |
| 29 | 33 | }; |
| 30 | 34 | |
| 31 | −templates.sidebarType = type => `<a href="${type.fullPath()}" class="_list-item _list-dir" data-slug="${type.slug}" tabindex="-1">${arrow}<span class="_list-count">${type.count}</span><span class="_list-text">${$.escape(type.name)}</span></a>`; | |
| 35 | +templates.sidebarType = (type) => | |
| 36 | + `<a href="${type.fullPath()}" class="_list-item _list-dir" data-slug="${ | |
| 37 | + type.slug | |
| 38 | + }" tabindex="-1">${arrow}<span class="_list-count">${ | |
| 39 | + type.count | |
| 40 | + }</span><span class="_list-text">${$.escape(type.name)}</span></a>`; | |
| 32 | 41 | |
| 33 | −templates.sidebarEntry = entry => `<a href="${entry.fullPath()}" class="_list-item _list-hover" tabindex="-1">${$.escape(entry.name)}</a>`; | |
| 42 | +templates.sidebarEntry = (entry) => | |
| 43 | + `<a href="${entry.fullPath()}" class="_list-item _list-hover" tabindex="-1">${$.escape( | |
| 44 | + entry.name, | |
| 45 | + )}</a>`; | |
| 34 | 46 | |
| 35 | −templates.sidebarResult = function(entry) { | |
| 36 | − let addons = entry.isIndex() && app.disabledDocs.contains(entry.doc) ? | |
| 37 | − `<span class="_list-enable" data-enable="${entry.doc.slug}">Enable</span>` | |
| 38 | − : | |
| 39 | − "<span class=\"_list-reveal\" data-reset-list title=\"Reveal in list\"></span>"; | |
| 40 | − if (entry.doc.version && !entry.isIndex()) { addons += `<span class="_list-count">${entry.doc.short_version}</span>`; } | |
| 41 | − return `<a href="${entry.fullPath()}" class="_list-item _list-hover _list-result _icon-${entry.doc.icon}" tabindex="-1">${addons}<span class="_list-text">${$.escape(entry.name)}</span></a>`; | |
| 47 | +templates.sidebarResult = function (entry) { | |
| 48 | + let addons = | |
| 49 | + entry.isIndex() && app.disabledDocs.contains(entry.doc) | |
| 50 | + ? `<span class="_list-enable" data-enable="${entry.doc.slug}">Enable</span>` | |
| 51 | + : '<span class="_list-reveal" data-reset-list title="Reveal in list"></span>'; | |
| 52 | + if (entry.doc.version && !entry.isIndex()) { | |
| 53 | + addons += `<span class="_list-count">${entry.doc.short_version}</span>`; | |
| 54 | + } | |
| 55 | + return `<a href="${entry.fullPath()}" class="_list-item _list-hover _list-result _icon-${ | |
| 56 | + entry.doc.icon | |
| 57 | + }" tabindex="-1">${addons}<span class="_list-text">${$.escape( | |
| 58 | + entry.name, | |
| 59 | + )}</span></a>`; | |
| 42 | 60 | }; |
| 43 | 61 | |
| 44 | −templates.sidebarNoResults = function() { | |
| 45 | − let html = " <div class=\"_list-note\">No results.</div> "; | |
| 46 | − if (!app.isSingleDoc() && !app.disabledDocs.isEmpty()) { html += `\ | |
| 62 | +templates.sidebarNoResults = function () { | |
| 63 | + let html = ' <div class="_list-note">No results.</div> '; | |
| 64 | + if (!app.isSingleDoc() && !app.disabledDocs.isEmpty()) { | |
| 65 | + html += `\ | |
| 47 | 66 | <div class="_list-note">Note: documentations must be <a href="/settings" class="_list-note-link">enabled</a> to appear in the search.</div>\ |
| 48 | −`; } | |
| 67 | +`; | |
| 68 | + } | |
| 49 | 69 | return html; |
| 50 | 70 | }; |
| 51 | 71 | |
| 52 | −templates.sidebarPageLink = count => `<span role="link" class="_list-item _list-pagelink">Show more\u2026 (${count})</span>`; | |
| 72 | +templates.sidebarPageLink = (count) => | |
| 73 | + `<span role="link" class="_list-item _list-pagelink">Show more\u2026 (${count})</span>`; | |
| 53 | 74 | |
| 54 | −templates.sidebarLabel = function(doc, options) { | |
| 55 | − if (options == null) { options = {}; } | |
| 56 | − let label = "<label class=\"_list-item"; | |
| 57 | − if (!doc.version) { label += ` _icon-${doc.icon}`; } | |
| 75 | +templates.sidebarLabel = function (doc, options) { | |
| 76 | + if (options == null) { | |
| 77 | + options = {}; | |
| 78 | + } | |
| 79 | + let label = '<label class="_list-item'; | |
| 80 | + if (!doc.version) { | |
| 81 | + label += ` _icon-${doc.icon}`; | |
| 82 | + } | |
| 58 | 83 | label += `"><input type="checkbox" name="${doc.slug}" class="_list-checkbox" `; |
| 59 | − if (options.checked) { label += "checked"; } | |
| 84 | + if (options.checked) { | |
| 85 | + label += "checked"; | |
| 86 | + } | |
| 60 | 87 | return label + `><span class="_list-text">${doc.fullName}</span></label>`; |
| 61 | 88 | }; |
| 62 | 89 | |
| 63 | −templates.sidebarVersionedDoc = function(doc, versions, options) { | |
| 64 | − if (options == null) { options = {}; } | |
| 90 | +templates.sidebarVersionedDoc = function (doc, versions, options) { | |
| 91 | + if (options == null) { | |
| 92 | + options = {}; | |
| 93 | + } | |
| 65 | 94 | let html = `<div class="_list-item _list-dir _list-rdir _icon-${doc.icon}`; |
| 66 | − if (options.open) { html += " open"; } | |
| 67 | − return html + `" tabindex="0">${arrow}${doc.name}</div><div class="_list _list-sub">${versions}</div>`; | |
| 95 | + if (options.open) { | |
| 96 | + html += " open"; | |
| 97 | + } | |
| 98 | + return ( | |
| 99 | + html + | |
| 100 | + `" tabindex="0">${arrow}${doc.name}</div><div class="_list _list-sub">${versions}</div>` | |
| 101 | + ); | |
| 68 | 102 | }; |
| 69 | 103 | |
| 70 | −templates.sidebarDisabled = options => `<h6 class="_list-title">${arrow}Disabled (${options.count}) <a href="/settings" class="_list-title-link" tabindex="-1">Customize</a></h6>`; | |
| 104 | +templates.sidebarDisabled = (options) => | |
| 105 | + `<h6 class="_list-title">${arrow}Disabled (${options.count}) <a href="/settings" class="_list-title-link" tabindex="-1">Customize</a></h6>`; | |
| 71 | 106 | |
| 72 | −templates.sidebarDisabledList = html => `<div class="_disabled-list">${html}</div>`; | |
| 107 | +templates.sidebarDisabledList = (html) => | |
| 108 | + `<div class="_disabled-list">${html}</div>`; | |
| 73 | 109 | |
| 74 | −templates.sidebarDisabledVersionedDoc = (doc, versions) => `<a class="_list-item _list-dir _icon-${doc.icon} _list-disabled" data-slug="${doc.slug_without_version}" tabindex="-1">${arrow}${doc.name}</a><div class="_list _list-sub">${versions}</div>`; | |
| 110 | +templates.sidebarDisabledVersionedDoc = (doc, versions) => | |
| 111 | + `<a class="_list-item _list-dir _icon-${doc.icon} _list-disabled" data-slug="${doc.slug_without_version}" tabindex="-1">${arrow}${doc.name}</a><div class="_list _list-sub">${versions}</div>`; | |
| 75 | 112 | |
| 76 | −templates.docPickerHeader = "<div class=\"_list-picker-head\"><span>Documentation</span> <span>Enable</span></div>"; | |
| 113 | +templates.docPickerHeader = | |
| 114 | + '<div class="_list-picker-head"><span>Documentation</span> <span>Enable</span></div>'; | |
| 77 | 115 | |
| 78 | 116 | templates.docPickerNote = `\ |
| 79 | 117 | <div class="_list-note">Tip: for faster and better search results, select only the docs you need.</div> |
| @@ -10,8 +10,14 @@ app.templates.tipKeyNav = () => `\ · 9 unmodified lines | ||
| 10 | 10 | <strong>ProTip</strong> |
| 11 | 11 | <span class="_notif-info">(click to dismiss)</span> |
| 12 | 12 | <p class="_notif-text"> |
| 13 | − Hit ${app.settings.get('arrowScroll') ? '<code class="_label">shift</code> +' : ''} <code class="_label">↓</code> <code class="_label">↑</code> <code class="_label">←</code> <code class="_label">→</code> to navigate the sidebar.<br> | |
| 14 | − Hit <code class="_label">space / shift space</code>${app.settings.get('arrowScroll') ? ' or <code class="_label">↓/↑</code>' : ', <code class="_label">alt ↓/↑</code> or <code class="_label">shift ↓/↑</code>'} to scroll the page. | |
| 13 | + Hit ${ | |
| 14 | + app.settings.get("arrowScroll") ? '<code class="_label">shift</code> +' : "" | |
| 15 | + } <code class="_label">↓</code> <code class="_label">↑</code> <code class="_label">←</code> <code class="_label">→</code> to navigate the sidebar.<br> | |
| 16 | + Hit <code class="_label">space / shift space</code>${ | |
| 17 | + app.settings.get("arrowScroll") | |
| 18 | + ? ' or <code class="_label">↓/↑</code>' | |
| 19 | + : ', <code class="_label">alt ↓/↑</code> or <code class="_label">shift ↓/↑</code>' | |
| 20 | + } to scroll the page. | |
| 15 | 21 | <p class="_notif-text"> |
| 16 | 22 | <a href="/help#shortcuts" class="_notif-link">See all keyboard shortcuts</a>\ |
| 17 | 23 | `; |
| @@ -1,32 +1,55 @@ | ||
| 1 | 1 | try { |
| 2 | − if (app.config.env === 'production') { | |
| 3 | − if (Cookies.get('analyticsConsent') === '1') { | |
| 4 | − (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | |
| 5 | − (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | |
| 6 | − m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | |
| 7 | − })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); | |
| 8 | − ga('create', 'UA-5544833-12', 'devdocs.io'); | |
| 9 | − page.track(function() { | |
| 10 | − ga('send', 'pageview', { | |
| 2 | + if (app.config.env === "production") { | |
| 3 | + if (Cookies.get("analyticsConsent") === "1") { | |
| 4 | + (function (i, s, o, g, r, a, m) { | |
| 5 | + i["GoogleAnalyticsObject"] = r; | |
| 6 | + (i[r] = | |
| 7 | + i[r] || | |
| 8 | + function () { | |
| 9 | + (i[r].q = i[r].q || []).push(arguments); | |
| 10 | + }), | |
| 11 | + (i[r].l = 1 * new Date()); | |
| 12 | + (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]); | |
| 13 | + a.async = 1; | |
| 14 | + a.src = g; | |
| 15 | + m.parentNode.insertBefore(a, m); | |
| 16 | + })( | |
| 17 | + window, | |
| 18 | + document, | |
| 19 | + "script", | |
| 20 | + "https://www.google-analytics.com/analytics.js", | |
| 21 | + "ga", | |
| 22 | + ); | |
| 23 | + ga("create", "UA-5544833-12", "devdocs.io"); | |
| 24 | + page.track(function () { | |
| 25 | + ga("send", "pageview", { | |
| 11 | 26 | page: location.pathname + location.search + location.hash, |
| 12 | − dimension1: app.router.context && app.router.context.doc && app.router.context.doc.slug_without_version | |
| 27 | + dimension1: | |
| 28 | + app.router.context && | |
| 29 | + app.router.context.doc && | |
| 30 | + app.router.context.doc.slug_without_version, | |
| 13 | 31 | }); |
| 14 | 32 | }); |
| 15 | 33 | |
| 16 | − page.track(function() { | |
| 17 | − if (window._gauges) | |
| 18 | − _gauges.push(['track']); | |
| 34 | + page.track(function () { | |
| 35 | + if (window._gauges) _gauges.push(["track"]); | |
| 19 | 36 | else |
| 20 | − (function() { | |
| 21 | − var _gauges=_gauges||[];!function(){var a=document.createElement("script"); | |
| 22 | − a.type="text/javascript",a.async=!0,a.id="gauges-tracker", | |
| 23 | − a.setAttribute("data-site-id","51c15f82613f5d7819000067"), | |
| 24 | − a.src="https://secure.gaug.es/track.js";var b=document.getElementsByTagName("script")[0]; | |
| 25 | − b.parentNode.insertBefore(a,b)}(); | |
| 37 | + (function () { | |
| 38 | + var _gauges = _gauges || []; | |
| 39 | + !(function () { | |
| 40 | + var a = document.createElement("script"); | |
| 41 | + (a.type = "text/javascript"), | |
| 42 | + (a.async = !0), | |
| 43 | + (a.id = "gauges-tracker"), | |
| 44 | + a.setAttribute("data-site-id", "51c15f82613f5d7819000067"), | |
| 45 | + (a.src = "https://secure.gaug.es/track.js"); | |
| 46 | + var b = document.getElementsByTagName("script")[0]; | |
| 47 | + b.parentNode.insertBefore(a, b); | |
| 48 | + })(); | |
| 26 | 49 | })(); |
| 27 | 50 | }); |
| 28 | 51 | } else { |
| 29 | 52 | resetAnalytics(); |
| 30 | 53 | } |
| 31 | 54 | } |
| 32 | −} catch(e) { } | |
| 55 | +} catch (e) {} | |
| @@ -5,171 +5,204 @@ · 4 unmodified lines | ||
| 5 | 5 | * This is free and unencumbered software released into the public domain. |
| 6 | 6 | */ |
| 7 | 7 | (function (global, undefined) { |
| 8 | − 'use strict'; | |
| 8 | + "use strict"; | |
| 9 | 9 | |
| 10 | − var factory = function (window) { | |
| 11 | − if (typeof window.document !== 'object') { | |
| 12 | − throw new Error('Cookies.js requires a `window` with a `document` object'); | |
| 10 | + var factory = function (window) { | |
| 11 | + if (typeof window.document !== "object") { | |
| 12 | + throw new Error( | |
| 13 | + "Cookies.js requires a `window` with a `document` object", | |
| 14 | + ); | |
| 15 | + } | |
| 16 | + | |
| 17 | + var Cookies = function (key, value, options) { | |
| 18 | + return arguments.length === 1 | |
| 19 | + ? Cookies.get(key) | |
| 20 | + : Cookies.set(key, value, options); | |
| 21 | + }; | |
| 22 | + | |
| 23 | + // Allows for setter injection in unit tests | |
| 24 | + Cookies._document = window.document; | |
| 25 | + | |
| 26 | + // Used to ensure cookie keys do not collide with | |
| 27 | + // built-in `Object` properties | |
| 28 | + Cookies._cacheKeyPrefix = "cookey."; // Hurr hurr, :) | |
| 29 | + | |
| 30 | + Cookies._maxExpireDate = new Date("Fri, 31 Dec 9999 23:59:59 UTC"); | |
| 31 | + | |
| 32 | + Cookies.defaults = { | |
| 33 | + path: "/", | |
| 34 | + SameSite: "Strict", | |
| 35 | + secure: true, | |
| 36 | + }; | |
| 37 | + | |
| 38 | + Cookies.get = function (key) { | |
| 39 | + if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) { | |
| 40 | + Cookies._renewCache(); | |
| 41 | + } | |
| 42 | + | |
| 43 | + var value = Cookies._cache[Cookies._cacheKeyPrefix + key]; | |
| 44 | + | |
| 45 | + return value === undefined ? undefined : decodeURIComponent(value); | |
| 46 | + }; | |
| 47 | + | |
| 48 | + Cookies.set = function (key, value, options) { | |
| 49 | + options = Cookies._getExtendedOptions(options); | |
| 50 | + options.expires = Cookies._getExpiresDate( | |
| 51 | + value === undefined ? -1 : options.expires, | |
| 52 | + ); | |
| 53 | + | |
| 54 | + Cookies._document.cookie = Cookies._generateCookieString( | |
| 55 | + key, | |
| 56 | + value, | |
| 57 | + options, | |
| 58 | + ); | |
| 59 | + | |
| 60 | + return Cookies; | |
| 61 | + }; | |
| 62 | + | |
| 63 | + Cookies.expire = function (key, options) { | |
| 64 | + return Cookies.set(key, undefined, options); | |
| 65 | + }; | |
| 66 | + | |
| 67 | + Cookies._getExtendedOptions = function (options) { | |
| 68 | + return { | |
| 69 | + path: (options && options.path) || Cookies.defaults.path, | |
| 70 | + domain: (options && options.domain) || Cookies.defaults.domain, | |
| 71 | + SameSite: (options && options.SameSite) || Cookies.defaults.SameSite, | |
| 72 | + expires: (options && options.expires) || Cookies.defaults.expires, | |
| 73 | + secure: | |
| 74 | + options && options.secure !== undefined | |
| 75 | + ? options.secure | |
| 76 | + : Cookies.defaults.secure, | |
| 77 | + }; | |
| 78 | + }; | |
| 79 | + | |
| 80 | + Cookies._isValidDate = function (date) { | |
| 81 | + return ( | |
| 82 | + Object.prototype.toString.call(date) === "[object Date]" && | |
| 83 | + !isNaN(date.getTime()) | |
| 84 | + ); | |
| 85 | + }; | |
| 86 | + | |
| 87 | + Cookies._getExpiresDate = function (expires, now) { | |
| 88 | + now = now || new Date(); | |
| 89 | + | |
| 90 | + if (typeof expires === "number") { | |
| 91 | + expires = | |
| 92 | + expires === Infinity | |
| 93 | + ? Cookies._maxExpireDate | |
| 94 | + : new Date(now.getTime() + expires * 1000); | |
| 95 | + } else if (typeof expires === "string") { | |
| 96 | + expires = new Date(expires); | |
| 97 | + } | |
| 98 | + | |
| 99 | + if (expires && !Cookies._isValidDate(expires)) { | |
| 100 | + throw new Error( | |
| 101 | + "`expires` parameter cannot be converted to a valid Date instance", | |
| 102 | + ); | |
| 103 | + } | |
| 104 | + | |
| 105 | + return expires; | |
| 106 | + }; | |
| 107 | + | |
| 108 | + Cookies._generateCookieString = function (key, value, options) { | |
| 109 | + key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent); | |
| 110 | + key = key.replace(/\(/g, "%28").replace(/\)/g, "%29"); | |
| 111 | + value = (value + "").replace( | |
| 112 | + /[^!#$&-+\--:<-\[\]-~]/g, | |
| 113 | + encodeURIComponent, | |
| 114 | + ); | |
| 115 | + options = options || {}; | |
| 116 | + | |
| 117 | + var cookieString = key + "=" + value; | |
| 118 | + cookieString += options.path ? ";path=" + options.path : ""; | |
| 119 | + cookieString += options.domain ? ";domain=" + options.domain : ""; | |
| 120 | + cookieString += options.SameSite ? ";SameSite=" + options.SameSite : ""; | |
| 121 | + cookieString += options.expires | |
| 122 | + ? ";expires=" + options.expires.toUTCString() | |
| 123 | + : ""; | |
| 124 | + cookieString += options.secure ? ";secure" : ""; | |
| 125 | + | |
| 126 | + return cookieString; | |
| 127 | + }; | |
| 128 | + | |
| 129 | + Cookies._getCacheFromString = function (documentCookie) { | |
| 130 | + var cookieCache = {}; | |
| 131 | + var cookiesArray = documentCookie ? documentCookie.split("; ") : []; | |
| 132 | + | |
| 133 | + for (var i = 0; i < cookiesArray.length; i++) { | |
| 134 | + var cookieKvp = Cookies._getKeyValuePairFromCookieString( | |
| 135 | + cookiesArray[i], | |
| 136 | + ); | |
| 137 | + | |
| 138 | + if ( | |
| 139 | + cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined | |
| 140 | + ) { | |
| 141 | + cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = | |
| 142 | + cookieKvp.value; | |
| 13 | 143 | } |
| 144 | + } | |
| 14 | 145 | |
| 15 | − var Cookies = function (key, value, options) { | |
| 16 | − return arguments.length === 1 ? | |
| 17 | − Cookies.get(key) : Cookies.set(key, value, options); | |
| 18 | − }; | |
| 146 | + return cookieCache; | |
| 147 | + }; | |
| 19 | 148 | |
| 20 | − // Allows for setter injection in unit tests | |
| 21 | − Cookies._document = window.document; | |
| 22 | − | |
| 23 | − // Used to ensure cookie keys do not collide with | |
| 24 | − // built-in `Object` properties | |
| 25 | − Cookies._cacheKeyPrefix = 'cookey.'; // Hurr hurr, :) | |
| 149 | + Cookies._getKeyValuePairFromCookieString = function (cookieString) { | |
| 150 | + // "=" is a valid character in a cookie value according to RFC6265, so cannot `split('=')` | |
| 151 | + var separatorIndex = cookieString.indexOf("="); | |
| 152 | + | |
| 153 | + // IE omits the "=" when the cookie value is an empty string | |
| 154 | + separatorIndex = | |
| 155 | + separatorIndex < 0 ? cookieString.length : separatorIndex; | |
| 156 | + | |
| 157 | + var key = cookieString.substr(0, separatorIndex); | |
| 158 | + var decodedKey; | |
| 159 | + try { | |
| 160 | + decodedKey = decodeURIComponent(key); | |
| 161 | + } catch (e) { | |
| 162 | + if (console && typeof console.error === "function") { | |
| 163 | + console.error('Could not decode cookie with key "' + key + '"', e); | |
| 164 | + } | |
| 165 | + } | |
| 26 | 166 | |
| 27 | − Cookies._maxExpireDate = new Date('Fri, 31 Dec 9999 23:59:59 UTC'); | |
| 167 | + return { | |
| 168 | + key: decodedKey, | |
| 169 | + value: cookieString.substr(separatorIndex + 1), // Defer decoding value until accessed | |
| 170 | + }; | |
| 171 | + }; | |
| 28 | 172 | |
| 29 | − Cookies.defaults = { | |
| 30 | − path: '/', | |
| 31 | − SameSite: 'Strict', | |
| 32 | − secure: true | |
| 33 | − }; | |
| 34 | − | |
| 35 | − Cookies.get = function (key) { | |
| 36 | − if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) { | |
| 37 | − Cookies._renewCache(); | |
| 38 | − } | |
| 39 | − | |
| 40 | − var value = Cookies._cache[Cookies._cacheKeyPrefix + key]; | |
| 41 | − | |
| 42 | − return value === undefined ? undefined : decodeURIComponent(value); | |
| 43 | − }; | |
| 44 | − | |
| 45 | − Cookies.set = function (key, value, options) { | |
| 46 | − options = Cookies._getExtendedOptions(options); | |
| 47 | − options.expires = Cookies._getExpiresDate(value === undefined ? -1 : options.expires); | |
| 48 | − | |
| 49 | − Cookies._document.cookie = Cookies._generateCookieString(key, value, options); | |
| 50 | − | |
| 51 | − return Cookies; | |
| 52 | − }; | |
| 53 | − | |
| 54 | − Cookies.expire = function (key, options) { | |
| 55 | − return Cookies.set(key, undefined, options); | |
| 56 | − }; | |
| 57 | − | |
| 58 | − Cookies._getExtendedOptions = function (options) { | |
| 59 | − return { | |
| 60 | − path: options && options.path || Cookies.defaults.path, | |
| 61 | − domain: options && options.domain || Cookies.defaults.domain, | |
| 62 | − SameSite: options && options.SameSite || Cookies.defaults.SameSite, | |
| 63 | − expires: options && options.expires || Cookies.defaults.expires, | |
| 64 | − secure: options && options.secure !== undefined ? options.secure : Cookies.defaults.secure | |
| 65 | − }; | |
| 66 | − }; | |
| 67 | − | |
| 68 | − Cookies._isValidDate = function (date) { | |
| 69 | − return Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime()); | |
| 70 | − }; | |
| 71 | − | |
| 72 | − Cookies._getExpiresDate = function (expires, now) { | |
| 73 | − now = now || new Date(); | |
| 74 | − | |
| 75 | − if (typeof expires === 'number') { | |
| 76 | − expires = expires === Infinity ? | |
| 77 | − Cookies._maxExpireDate : new Date(now.getTime() + expires * 1000); | |
| 78 | − } else if (typeof expires === 'string') { | |
| 79 | − expires = new Date(expires); | |
| 80 | − } | |
| 81 | − | |
| 82 | − if (expires && !Cookies._isValidDate(expires)) { | |
| 83 | − throw new Error('`expires` parameter cannot be converted to a valid Date instance'); | |
| 84 | − } | |
| 85 | − | |
| 86 | − return expires; | |
| 87 | − }; | |
| 88 | − | |
| 89 | − Cookies._generateCookieString = function (key, value, options) { | |
| 90 | − key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent); | |
| 91 | − key = key.replace(/\(/g, '%28').replace(/\)/g, '%29'); | |
| 92 | − value = (value + '').replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent); | |
| 93 | − options = options || {}; | |
| 94 | − | |
| 95 | − var cookieString = key + '=' + value; | |
| 96 | − cookieString += options.path ? ';path=' + options.path : ''; | |
| 97 | − cookieString += options.domain ? ';domain=' + options.domain : ''; | |
| 98 | − cookieString += options.SameSite ? ';SameSite=' + options.SameSite : ''; | |
| 99 | − cookieString += options.expires ? ';expires=' + options.expires.toUTCString() : ''; | |
| 100 | − cookieString += options.secure ? ';secure' : ''; | |
| 101 | − | |
| 102 | − return cookieString; | |
| 103 | − }; | |
| 104 | − | |
| 105 | − Cookies._getCacheFromString = function (documentCookie) { | |
| 106 | − var cookieCache = {}; | |
| 107 | − var cookiesArray = documentCookie ? documentCookie.split('; ') : []; | |
| 108 | − | |
| 109 | − for (var i = 0; i < cookiesArray.length; i++) { | |
| 110 | − var cookieKvp = Cookies._getKeyValuePairFromCookieString(cookiesArray[i]); | |
| 111 | − | |
| 112 | − if (cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined) { | |
| 113 | − cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = cookieKvp.value; | |
| 114 | − } | |
| 115 | − } | |
| 116 | − | |
| 117 | − return cookieCache; | |
| 118 | − }; | |
| 119 | − | |
| 120 | − Cookies._getKeyValuePairFromCookieString = function (cookieString) { | |
| 121 | − // "=" is a valid character in a cookie value according to RFC6265, so cannot `split('=')` | |
| 122 | − var separatorIndex = cookieString.indexOf('='); | |
| 123 | − | |
| 124 | − // IE omits the "=" when the cookie value is an empty string | |
| 125 | − separatorIndex = separatorIndex < 0 ? cookieString.length : separatorIndex; | |
| 126 | − | |
| 127 | − var key = cookieString.substr(0, separatorIndex); | |
| 128 | − var decodedKey; | |
| 129 | − try { | |
| 130 | − decodedKey = decodeURIComponent(key); | |
| 131 | − } catch (e) { | |
| 132 | − if (console && typeof console.error === 'function') { | |
| 133 | − console.error('Could not decode cookie with key "' + key + '"', e); | |
| 134 | − } | |
| 135 | − } | |
| 136 | − | |
| 137 | − return { | |
| 138 | − key: decodedKey, | |
| 139 | − value: cookieString.substr(separatorIndex + 1) // Defer decoding value until accessed | |
| 140 | − }; | |
| 141 | − }; | |
| 142 | − | |
| 143 | − Cookies._renewCache = function () { | |
| 144 | − Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie); | |
| 145 | − Cookies._cachedDocumentCookie = Cookies._document.cookie; | |
| 146 | − }; | |
| 147 | − | |
| 148 | − Cookies._areEnabled = function () { | |
| 149 | − var testKey = 'cookies.js'; | |
| 150 | − var areEnabled = Cookies.set(testKey, 1).get(testKey) === '1'; | |
| 151 | − Cookies.expire(testKey); | |
| 152 | − return areEnabled; | |
| 153 | − }; | |
| 154 | − | |
| 155 | − Cookies.enabled = Cookies._areEnabled(); | |
| 156 | − | |
| 157 | − return Cookies; | |
| 173 | + Cookies._renewCache = function () { | |
| 174 | + Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie); | |
| 175 | + Cookies._cachedDocumentCookie = Cookies._document.cookie; | |
| 158 | 176 | }; |
| 159 | − var cookiesExport = (global && typeof global.document === 'object') ? factory(global) : factory; | |
| 160 | 177 | |
| 161 | − // AMD support | |
| 162 | − if (typeof define === 'function' && define.amd) { | |
| 163 | − define(function () { return cookiesExport; }); | |
| 178 | + Cookies._areEnabled = function () { | |
| 179 | + var testKey = "cookies.js"; | |
| 180 | + var areEnabled = Cookies.set(testKey, 1).get(testKey) === "1"; | |
| 181 | + Cookies.expire(testKey); | |
| 182 | + return areEnabled; | |
| 183 | + }; | |
| 184 | + | |
| 185 | + Cookies.enabled = Cookies._areEnabled(); | |
| 186 | + | |
| 187 | + return Cookies; | |
| 188 | + }; | |
| 189 | + var cookiesExport = | |
| 190 | + global && typeof global.document === "object" ? factory(global) : factory; | |
| 191 | + | |
| 192 | + // AMD support | |
| 193 | + if (typeof define === "function" && define.amd) { | |
| 194 | + define(function () { | |
| 195 | + return cookiesExport; | |
| 196 | + }); | |
| 164 | 197 | // CommonJS/Node.js support |
| 165 | − } else if (typeof exports === 'object') { | |
| 166 | − // Support Node.js specific `module.exports` (which can be a function) | |
| 167 | − if (typeof module === 'object' && typeof module.exports === 'object') { | |
| 168 | − exports = module.exports = cookiesExport; | |
| 169 | − } | |
| 170 | − // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) | |
| 171 | − exports.Cookies = cookiesExport; | |
| 172 | − } else { | |
| 173 | − global.Cookies = cookiesExport; | |
| 198 | + } else if (typeof exports === "object") { | |
| 199 | + // Support Node.js specific `module.exports` (which can be a function) | |
| 200 | + if (typeof module === "object" && typeof module.exports === "object") { | |
| 201 | + exports = module.exports = cookiesExport; | |
| 174 | 202 | } |
| 175 | −})(typeof window === 'undefined' ? this : window); | |
| 203 | + // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) | |
| 204 | + exports.Cookies = cookiesExport; | |
| 205 | + } else { | |
| 206 | + global.Cookies = cookiesExport; | |
| 207 | + } | |
| 208 | +})(typeof window === "undefined" ? this : window); | |
| @@ -4,17 +4,22 @@ · 3 unmodified lines | ||
| 4 | 4 | * Adapted from: https://github.com/fred-wang/mathml.css */ |
| 5 | 5 | |
| 6 | 6 | (function () { |
| 7 | − window.addEventListener("load", function() { | |
| 7 | + window.addEventListener("load", function () { | |
| 8 | 8 | var box, div, link, namespaceURI; |
| 9 | 9 | // First check whether the page contains any <math> element. |
| 10 | 10 | namespaceURI = "http://www.w3.org/1998/Math/MathML"; |
| 11 | 11 | // Create a div to test mspace, using Kuma's "offscreen" CSS |
| 12 | − document.body.insertAdjacentHTML("afterbegin", "<div style='border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px;'><math xmlns='" + namespaceURI + "'><mspace height='23px' width='77px'></mspace></math></div>"); | |
| 12 | + document.body.insertAdjacentHTML( | |
| 13 | + "afterbegin", | |
| 14 | + "<div style='border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px;'><math xmlns='" + | |
| 15 | + namespaceURI + | |
| 16 | + "'><mspace height='23px' width='77px'></mspace></math></div>", | |
| 17 | + ); | |
| 13 | 18 | div = document.body.firstChild; |
| 14 | 19 | box = div.firstChild.firstChild.getBoundingClientRect(); |
| 15 | 20 | document.body.removeChild(div); |
| 16 | − if (Math.abs(box.height - 23) > 1 || Math.abs(box.width - 77) > 1) { | |
| 21 | + if (Math.abs(box.height - 23) > 1 || Math.abs(box.width - 77) > 1) { | |
| 17 | 22 | window.supportsMathML = false; |
| 18 | 23 | } |
| 19 | 24 | }); |
| 20 | −}()); | |
| 25 | +})(); | |
| @@ -2,13 +2,13 @@ · 1 unmodified line | ||
| 2 | 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+cmake+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+latex+lua+markdown+markup-templating+matlab+nginx+nim+nix+ocaml+perl+php+python+qml+r+jsx+ruby+rust+scss+scala+shell-session+sql+typescript+yaml+zig */ |
| 3 | 3 | /// <reference lib="WebWorker"/> |
| 4 | 4 | |
| 5 | −var _self = (typeof window !== 'undefined') | |
| 6 | − ? window // if in browser | |
| 7 | − : ( | |
| 8 | − (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) | |
| 9 | − ? self // if in worker | |
| 10 | − : {} // if in node js | |
| 11 | − ); | |
| 5 | +var _self = | |
| 6 | + typeof window !== "undefined" | |
| 7 | + ? window // if in browser | |
| 8 | + : typeof WorkerGlobalScope !== "undefined" && | |
| 9 | + self instanceof WorkerGlobalScope | |
| 10 | + ? self // if in worker | |
| 11 | + : {}; // if in node js | |
| 12 | 12 | |
| 13 | 13 | /** |
| 14 | 14 | * Prism: Lightweight, robust, elegant syntax highlighting |
| @@ -19,1200 +19,1260 @@ var _self = (typeof window !== 'undefined') · 4 unmodified lines | ||
| 19 | 19 | * @public |
| 20 | 20 | */ |
| 21 | 21 | var Prism = (function (_self) { |
| 22 | − | |
| 23 | − // Private helper vars | |
| 24 | − var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; | |
| 25 | − var uniqueId = 0; | |
| 26 | − | |
| 27 | − // The grammar object for plaintext | |
| 28 | − var plainTextGrammar = {}; | |
| 29 | − | |
| 30 | − | |
| 31 | − var _ = { | |
| 32 | − /** | |
| 33 | − * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the | |
| 34 | − * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load | |
| 35 | − * additional languages or plugins yourself. | |
| 36 | − * | |
| 37 | − * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. | |
| 38 | − * | |
| 39 | − * You obviously have to change this value before the automatic highlighting started. To do this, you can add an | |
| 40 | − * empty Prism object into the global scope before loading the Prism script like this: | |
| 41 | − * | |
| 42 | − * ```js | |
| 43 | − * window.Prism = window.Prism || {}; | |
| 44 | − * Prism.manual = true; | |
| 45 | − * // add a new <script> to load Prism's script | |
| 46 | − * ``` | |
| 47 | − * | |
| 48 | − * @default false | |
| 49 | − * @type {boolean} | |
| 50 | − * @memberof Prism | |
| 51 | − * @public | |
| 52 | − */ | |
| 53 | − manual: _self.Prism && _self.Prism.manual, | |
| 54 | − /** | |
| 55 | − * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses | |
| 56 | − * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your | |
| 57 | − * own worker, you don't want it to do this. | |
| 58 | − * | |
| 59 | − * By setting this value to `true`, Prism will not add its own listeners to the worker. | |
| 60 | − * | |
| 61 | − * You obviously have to change this value before Prism executes. To do this, you can add an | |
| 62 | − * empty Prism object into the global scope before loading the Prism script like this: | |
| 63 | − * | |
| 64 | − * ```js | |
| 65 | − * window.Prism = window.Prism || {}; | |
| 66 | − * Prism.disableWorkerMessageHandler = true; | |
| 67 | − * // Load Prism's script | |
| 68 | − * ``` | |
| 69 | − * | |
| 70 | − * @default false | |
| 71 | − * @type {boolean} | |
| 72 | − * @memberof Prism | |
| 73 | − * @public | |
| 74 | − */ | |
| 75 | − disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, | |
| 76 | − | |
| 77 | − /** | |
| 78 | − * A namespace for utility methods. | |
| 79 | − * | |
| 80 | − * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may | |
| 81 | − * change or disappear at any time. | |
| 82 | − * | |
| 83 | − * @namespace | |
| 84 | − * @memberof Prism | |
| 85 | − */ | |
| 86 | − util: { | |
| 87 | − encode: function encode(tokens) { | |
| 88 | − if (tokens instanceof Token) { | |
| 89 | − return new Token(tokens.type, encode(tokens.content), tokens.alias); | |
| 90 | − } else if (Array.isArray(tokens)) { | |
| 91 | − return tokens.map(encode); | |
| 92 | − } else { | |
| 93 | − return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); | |
| 94 | − } | |
| 95 | − }, | |
| 96 | − | |
| 97 | − /** | |
| 98 | − * Returns the name of the type of the given value. | |
| 99 | − * | |
| 100 | − * @param {any} o | |
| 101 | − * @returns {string} | |
| 102 | − * @example | |
| 103 | − * type(null) === 'Null' | |
| 104 | − * type(undefined) === 'Undefined' | |
| 105 | − * type(123) === 'Number' | |
| 106 | − * type('foo') === 'String' | |
| 107 | − * type(true) === 'Boolean' | |
| 108 | − * type([1, 2]) === 'Array' | |
| 109 | − * type({}) === 'Object' | |
| 110 | − * type(String) === 'Function' | |
| 111 | − * type(/abc+/) === 'RegExp' | |
| 112 | − */ | |
| 113 | − type: function (o) { | |
| 114 | − return Object.prototype.toString.call(o).slice(8, -1); | |
| 115 | − }, | |
| 116 | − | |
| 117 | − /** | |
| 118 | − * Returns a unique number for the given object. Later calls will still return the same number. | |
| 119 | − * | |
| 120 | − * @param {Object} obj | |
| 121 | − * @returns {number} | |
| 122 | − */ | |
| 123 | − objId: function (obj) { | |
| 124 | − if (!obj['__id']) { | |
| 125 | − Object.defineProperty(obj, '__id', { value: ++uniqueId }); | |
| 126 | − } | |
| 127 | − return obj['__id']; | |
| 128 | − }, | |
| 129 | − | |
| 130 | − /** | |
| 131 | − * Creates a deep clone of the given object. | |
| 132 | − * | |
| 133 | − * The main intended use of this function is to clone language definitions. | |
| 134 | − * | |
| 135 | − * @param {T} o | |
| 136 | − * @param {Record<number, any>} [visited] | |
| 137 | − * @returns {T} | |
| 138 | − * @template T | |
| 139 | − */ | |
| 140 | − clone: function deepClone(o, visited) { | |
| 141 | − visited = visited || {}; | |
| 142 | − | |
| 143 | − var clone; var id; | |
| 144 | − switch (_.util.type(o)) { | |
| 145 | − case 'Object': | |
| 146 | − id = _.util.objId(o); | |
| 147 | − if (visited[id]) { | |
| 148 | − return visited[id]; | |
| 149 | − } | |
| 150 | − clone = /** @type {Record<string, any>} */ ({}); | |
| 151 | − visited[id] = clone; | |
| 152 | − | |
| 153 | − for (var key in o) { | |
| 154 | − if (o.hasOwnProperty(key)) { | |
| 155 | − clone[key] = deepClone(o[key], visited); | |
| 156 | − } | |
| 157 | − } | |
| 158 | − | |
| 159 | − return /** @type {any} */ (clone); | |
| 160 | − | |
| 161 | − case 'Array': | |
| 162 | − id = _.util.objId(o); | |
| 163 | − if (visited[id]) { | |
| 164 | − return visited[id]; | |
| 165 | − } | |
| 166 | − clone = []; | |
| 167 | − visited[id] = clone; | |
| 168 | − | |
| 169 | − (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) { | |
| 170 | − clone[i] = deepClone(v, visited); | |
| 171 | − }); | |
| 172 | − | |
| 173 | − return /** @type {any} */ (clone); | |
| 174 | − | |
| 175 | − default: | |
| 176 | − return o; | |
| 177 | − } | |
| 178 | − }, | |
| 179 | − | |
| 180 | − /** | |
| 181 | − * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. | |
| 182 | − * | |
| 183 | − * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. | |
| 184 | − * | |
| 185 | − * @param {Element} element | |
| 186 | − * @returns {string} | |
| 187 | − */ | |
| 188 | − getLanguage: function (element) { | |
| 189 | − while (element) { | |
| 190 | − var m = lang.exec(element.className); | |
| 191 | − if (m) { | |
| 192 | − return m[1].toLowerCase(); | |
| 193 | − } | |
| 194 | − element = element.parentElement; | |
| 195 | − } | |
| 196 | − return 'none'; | |
| 197 | − }, | |
| 198 | − | |
| 199 | − /** | |
| 200 | − * Sets the Prism `language-xxxx` class of the given element. | |
| 201 | − * | |
| 202 | − * @param {Element} element | |
| 203 | − * @param {string} language | |
| 204 | − * @returns {void} | |
| 205 | − */ | |
| 206 | − setLanguage: function (element, language) { | |
| 207 | − // remove all `language-xxxx` classes | |
| 208 | − // (this might leave behind a leading space) | |
| 209 | − element.className = element.className.replace(RegExp(lang, 'gi'), ''); | |
| 210 | − | |
| 211 | − // add the new `language-xxxx` class | |
| 212 | − // (using `classList` will automatically clean up spaces for us) | |
| 213 | − element.classList.add('language-' + language); | |
| 214 | − }, | |
| 215 | − | |
| 216 | − /** | |
| 217 | − * Returns the script element that is currently executing. | |
| 218 | − * | |
| 219 | − * This does __not__ work for line script element. | |
| 220 | − * | |
| 221 | − * @returns {HTMLScriptElement | null} | |
| 222 | − */ | |
| 223 | − currentScript: function () { | |
| 224 | − if (typeof document === 'undefined') { | |
| 225 | − return null; | |
| 226 | − } | |
| 227 | − if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) { | |
| 228 | − return /** @type {any} */ (document.currentScript); | |
| 229 | − } | |
| 230 | − | |
| 231 | − // IE11 workaround | |
| 232 | − // we'll get the src of the current script by parsing IE11's error stack trace | |
| 233 | − // this will not work for inline scripts | |
| 234 | − | |
| 235 | − try { | |
| 236 | − throw new Error(); | |
| 237 | − } catch (err) { | |
| 238 | − // Get file src url from stack. Specifically works with the format of stack traces in IE. | |
| 239 | − // A stack will look like this: | |
| 240 | − // | |
| 241 | − // Error | |
| 242 | − // at _.util.currentScript (http://localhost/components/prism-core.js:119:5) | |
| 243 | − // at Global code (http://localhost/components/prism-core.js:606:1) | |
| 244 | − | |
| 245 | − var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1]; | |
| 246 | − if (src) { | |
| 247 | − var scripts = document.getElementsByTagName('script'); | |
| 248 | − for (var i in scripts) { | |
| 249 | − if (scripts[i].src == src) { | |
| 250 | − return scripts[i]; | |
| 251 | − } | |
| 252 | − } | |
| 253 | − } | |
| 254 | − return null; | |
| 255 | − } | |
| 256 | − }, | |
| 257 | − | |
| 258 | − /** | |
| 259 | − * Returns whether a given class is active for `element`. | |
| 260 | − * | |
| 261 | − * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated | |
| 262 | − * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the | |
| 263 | − * given class is just the given class with a `no-` prefix. | |
| 264 | − * | |
| 265 | − * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is | |
| 266 | − * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its | |
| 267 | − * ancestors have the given class or the negated version of it, then the default activation will be returned. | |
| 268 | − * | |
| 269 | − * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated | |
| 270 | − * version of it, the class is considered active. | |
| 271 | − * | |
| 272 | − * @param {Element} element | |
| 273 | − * @param {string} className | |
| 274 | − * @param {boolean} [defaultActivation=false] | |
| 275 | − * @returns {boolean} | |
| 276 | − */ | |
| 277 | − isActive: function (element, className, defaultActivation) { | |
| 278 | − var no = 'no-' + className; | |
| 279 | − | |
| 280 | − while (element) { | |
| 281 | − var classList = element.classList; | |
| 282 | − if (classList.contains(className)) { | |
| 283 | − return true; | |
| 284 | − } | |
| 285 | − if (classList.contains(no)) { | |
| 286 | − return false; | |
| 287 | − } | |
| 288 | − element = element.parentElement; | |
| 289 | − } | |
| 290 | − return !!defaultActivation; | |
| 291 | − } | |
| 292 | − }, | |
| 293 | − | |
| 294 | − /** | |
| 295 | − * This namespace contains all currently loaded languages and the some helper functions to create and modify languages. | |
| 296 | − * | |
| 297 | − * @namespace | |
| 298 | − * @memberof Prism | |
| 299 | − * @public | |
| 300 | − */ | |
| 301 | − languages: { | |
| 302 | − /** | |
| 303 | − * The grammar for plain, unformatted text. | |
| 304 | − */ | |
| 305 | − plain: plainTextGrammar, | |
| 306 | − plaintext: plainTextGrammar, | |
| 307 | − text: plainTextGrammar, | |
| 308 | − txt: plainTextGrammar, | |
| 309 | − | |
| 310 | − /** | |
| 311 | − * Creates a deep copy of the language with the given id and appends the given tokens. | |
| 312 | − * | |
| 313 | − * If a token in `redef` also appears in the copied language, then the existing token in the copied language | |
| 314 | − * will be overwritten at its original position. | |
| 315 | − * | |
| 316 | − * ## Best practices | |
| 317 | − * | |
| 318 | − * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) | |
| 319 | − * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to | |
| 320 | − * understand the language definition because, normally, the order of tokens matters in Prism grammars. | |
| 321 | − * | |
| 322 | − * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. | |
| 323 | − * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. | |
| 324 | − * | |
| 325 | − * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. | |
| 326 | − * @param {Grammar} redef The new tokens to append. | |
| 327 | − * @returns {Grammar} The new language created. | |
| 328 | − * @public | |
| 329 | − * @example | |
| 330 | − * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { | |
| 331 | − * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token | |
| 332 | − * // at its original position | |
| 333 | − * 'comment': { ... }, | |
| 334 | − * // CSS doesn't have a 'color' token, so this token will be appended | |
| 335 | − * 'color': /\b(?:red|green|blue)\b/ | |
| 336 | − * }); | |
| 337 | − */ | |
| 338 | − extend: function (id, redef) { | |
| 339 | − var lang = _.util.clone(_.languages[id]); | |
| 340 | − | |
| 341 | − for (var key in redef) { | |
| 342 | − lang[key] = redef[key]; | |
| 343 | − } | |
| 344 | − | |
| 345 | − return lang; | |
| 346 | − }, | |
| 347 | − | |
| 348 | − /** | |
| 349 | − * Inserts tokens _before_ another token in a language definition or any other grammar. | |
| 350 | − * | |
| 351 | − * ## Usage | |
| 352 | − * | |
| 353 | − * This helper method makes it easy to modify existing languages. For example, the CSS language definition | |
| 354 | − * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded | |
| 355 | − * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the | |
| 356 | − * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do | |
| 357 | − * this: | |
| 358 | − * | |
| 359 | − * ```js | |
| 360 | − * Prism.languages.markup.style = { | |
| 361 | − * // token | |
| 362 | − * }; | |
| 363 | − * ``` | |
| 364 | − * | |
| 365 | − * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens | |
| 366 | − * before existing tokens. For the CSS example above, you would use it like this: | |
| 367 | − * | |
| 368 | − * ```js | |
| 369 | − * Prism.languages.insertBefore('markup', 'cdata', { | |
| 370 | − * 'style': { | |
| 371 | − * // token | |
| 372 | − * } | |
| 373 | − * }); | |
| 374 | − * ``` | |
| 375 | − * | |
| 376 | − * ## Special cases | |
| 377 | − * | |
| 378 | − * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar | |
| 379 | − * will be ignored. | |
| 380 | − * | |
| 381 | − * This behavior can be used to insert tokens after `before`: | |
| 382 | − * | |
| 383 | − * ```js | |
| 384 | − * Prism.languages.insertBefore('markup', 'comment', { | |
| 385 | − * 'comment': Prism.languages.markup.comment, | |
| 386 | − * // tokens after 'comment' | |
| 387 | − * }); | |
| 388 | − * ``` | |
| 389 | − * | |
| 390 | − * ## Limitations | |
| 391 | − * | |
| 392 | − * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object | |
| 393 | − * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave | |
| 394 | − * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily | |
| 395 | − * deleting properties which is necessary to insert at arbitrary positions. | |
| 396 | − * | |
| 397 | − * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. | |
| 398 | − * Instead, it will create a new object and replace all references to the target object with the new one. This | |
| 399 | − * can be done without temporarily deleting properties, so the iteration order is well-defined. | |
| 400 | − * | |
| 401 | − * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if | |
| 402 | − * you hold the target object in a variable, then the value of the variable will not change. | |
| 403 | − * | |
| 404 | − * ```js | |
| 405 | − * var oldMarkup = Prism.languages.markup; | |
| 406 | − * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); | |
| 407 | − * | |
| 408 | − * assert(oldMarkup !== Prism.languages.markup); | |
| 409 | − * assert(newMarkup === Prism.languages.markup); | |
| 410 | − * ``` | |
| 411 | − * | |
| 412 | − * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the | |
| 413 | − * object to be modified. | |
| 414 | − * @param {string} before The key to insert before. | |
| 415 | − * @param {Grammar} insert An object containing the key-value pairs to be inserted. | |
| 416 | − * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the | |
| 417 | − * object to be modified. | |
| 418 | − * | |
| 419 | − * Defaults to `Prism.languages`. | |
| 420 | − * @returns {Grammar} The new grammar object. | |
| 421 | − * @public | |
| 422 | − */ | |
| 423 | − insertBefore: function (inside, before, insert, root) { | |
| 424 | − root = root || /** @type {any} */ (_.languages); | |
| 425 | − var grammar = root[inside]; | |
| 426 | − /** @type {Grammar} */ | |
| 427 | − var ret = {}; | |
| 428 | − | |
| 429 | − for (var token in grammar) { | |
| 430 | − if (grammar.hasOwnProperty(token)) { | |
| 431 | − | |
| 432 | − if (token == before) { | |
| 433 | − for (var newToken in insert) { | |
| 434 | − if (insert.hasOwnProperty(newToken)) { | |
| 435 | − ret[newToken] = insert[newToken]; | |
| 436 | − } | |
| 437 | − } | |
| 438 | − } | |
| 439 | − | |
| 440 | − // Do not insert token which also occur in insert. See #1525 | |
| 441 | − if (!insert.hasOwnProperty(token)) { | |
| 442 | − ret[token] = grammar[token]; | |
| 443 | − } | |
| 444 | − } | |
| 445 | − } | |
| 446 | − | |
| 447 | − var old = root[inside]; | |
| 448 | − root[inside] = ret; | |
| 449 | − | |
| 450 | − // Update references in other language definitions | |
| 451 | − _.languages.DFS(_.languages, function (key, value) { | |
| 452 | − if (value === old && key != inside) { | |
| 453 | − this[key] = ret; | |
| 454 | − } | |
| 455 | − }); | |
| 456 | − | |
| 457 | − return ret; | |
| 458 | − }, | |
| 459 | − | |
| 460 | − // Traverse a language definition with Depth First Search | |
| 461 | − DFS: function DFS(o, callback, type, visited) { | |
| 462 | − visited = visited || {}; | |
| 463 | − | |
| 464 | − var objId = _.util.objId; | |
| 465 | − | |
| 466 | − for (var i in o) { | |
| 467 | − if (o.hasOwnProperty(i)) { | |
| 468 | − callback.call(o, i, o[i], type || i); | |
| 469 | − | |
| 470 | − var property = o[i]; | |
| 471 | − var propertyType = _.util.type(property); | |
| 472 | − | |
| 473 | − if (propertyType === 'Object' && !visited[objId(property)]) { | |
| 474 | − visited[objId(property)] = true; | |
| 475 | − DFS(property, callback, null, visited); | |
| 476 | − } else if (propertyType === 'Array' && !visited[objId(property)]) { | |
| 477 | − visited[objId(property)] = true; | |
| 478 | − DFS(property, callback, i, visited); | |
| 479 | − } | |
| 480 | − } | |
| 481 | − } | |
| 482 | − } | |
| 483 | − }, | |
| 484 | − | |
| 485 | − plugins: {}, | |
| 486 | − | |
| 487 | − /** | |
| 488 | − * This is the most high-level function in Prism’s API. | |
| 489 | − * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on | |
| 490 | − * each one of them. | |
| 491 | − * | |
| 492 | − * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. | |
| 493 | − * | |
| 494 | − * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. | |
| 495 | − * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. | |
| 496 | − * @memberof Prism | |
| 497 | − * @public | |
| 498 | − */ | |
| 499 | − highlightAll: function (async, callback) { | |
| 500 | − _.highlightAllUnder(document, async, callback); | |
| 501 | − }, | |
| 502 | − | |
| 503 | − /** | |
| 504 | − * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls | |
| 505 | − * {@link Prism.highlightElement} on each one of them. | |
| 506 | − * | |
| 507 | − * The following hooks will be run: | |
| 508 | − * 1. `before-highlightall` | |
| 509 | − * 2. `before-all-elements-highlight` | |
| 510 | − * 3. All hooks of {@link Prism.highlightElement} for each element. | |
| 511 | − * | |
| 512 | − * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. | |
| 513 | − * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. | |
| 514 | − * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. | |
| 515 | − * @memberof Prism | |
| 516 | − * @public | |
| 517 | − */ | |
| 518 | − highlightAllUnder: function (container, async, callback) { | |
| 519 | − var env = { | |
| 520 | − callback: callback, | |
| 521 | − container: container, | |
| 522 | − selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' | |
| 523 | − }; | |
| 524 | − | |
| 525 | − _.hooks.run('before-highlightall', env); | |
| 526 | − | |
| 527 | − env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector)); | |
| 528 | − | |
| 529 | − _.hooks.run('before-all-elements-highlight', env); | |
| 530 | − | |
| 531 | − for (var i = 0, element; (element = env.elements[i++]);) { | |
| 532 | − _.highlightElement(element, async === true, env.callback); | |
| 533 | − } | |
| 534 | − }, | |
| 535 | − | |
| 536 | − /** | |
| 537 | − * Highlights the code inside a single element. | |
| 538 | − * | |
| 539 | − * The following hooks will be run: | |
| 540 | − * 1. `before-sanity-check` | |
| 541 | − * 2. `before-highlight` | |
| 542 | − * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. | |
| 543 | − * 4. `before-insert` | |
| 544 | − * 5. `after-highlight` | |
| 545 | − * 6. `complete` | |
| 546 | − * | |
| 547 | − * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for | |
| 548 | − * the element's language. | |
| 549 | − * | |
| 550 | − * @param {Element} element The element containing the code. | |
| 551 | − * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. | |
| 552 | − * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers | |
| 553 | − * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is | |
| 554 | − * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). | |
| 555 | − * | |
| 556 | − * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for | |
| 557 | − * asynchronous highlighting to work. You can build your own bundle on the | |
| 558 | − * [Download page](https://prismjs.com/download.html). | |
| 559 | − * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. | |
| 560 | − * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. | |
| 561 | − * @memberof Prism | |
| 562 | − * @public | |
| 563 | − */ | |
| 564 | − highlightElement: function (element, async, callback) { | |
| 565 | − // Find language | |
| 566 | − var language = _.util.getLanguage(element); | |
| 567 | − var grammar = _.languages[language]; | |
| 568 | − | |
| 569 | − // Set language on the element, if not present | |
| 570 | − _.util.setLanguage(element, language); | |
| 571 | − | |
| 572 | − // Set language on the parent, for styling | |
| 573 | − var parent = element.parentElement; | |
| 574 | − if (parent && parent.nodeName.toLowerCase() === 'pre') { | |
| 575 | − _.util.setLanguage(parent, language); | |
| 576 | − } | |
| 577 | − | |
| 578 | − var code = element.textContent; | |
| 579 | − | |
| 580 | − var env = { | |
| 581 | − element: element, | |
| 582 | − language: language, | |
| 583 | − grammar: grammar, | |
| 584 | − code: code | |
| 585 | − }; | |
| 586 | − | |
| 587 | − function insertHighlightedCode(highlightedCode) { | |
| 588 | − env.highlightedCode = highlightedCode; | |
| 589 | − | |
| 590 | − _.hooks.run('before-insert', env); | |
| 591 | − | |
| 592 | − env.element.innerHTML = env.highlightedCode; | |
| 593 | − | |
| 594 | − _.hooks.run('after-highlight', env); | |
| 595 | − _.hooks.run('complete', env); | |
| 596 | − callback && callback.call(env.element); | |
| 597 | − } | |
| 598 | − | |
| 599 | − _.hooks.run('before-sanity-check', env); | |
| 600 | − | |
| 601 | − // plugins may change/add the parent/element | |
| 602 | − parent = env.element.parentElement; | |
| 603 | − if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) { | |
| 604 | − parent.setAttribute('tabindex', '0'); | |
| 605 | − } | |
| 606 | − | |
| 607 | − if (!env.code) { | |
| 608 | − _.hooks.run('complete', env); | |
| 609 | − callback && callback.call(env.element); | |
| 610 | − return; | |
| 611 | − } | |
| 612 | − | |
| 613 | − _.hooks.run('before-highlight', env); | |
| 614 | − | |
| 615 | − if (!env.grammar) { | |
| 616 | − insertHighlightedCode(_.util.encode(env.code)); | |
| 617 | − return; | |
| 618 | − } | |
| 619 | − | |
| 620 | − if (async && _self.Worker) { | |
| 621 | − var worker = new Worker(_.filename); | |
| 622 | − | |
| 623 | − worker.onmessage = function (evt) { | |
| 624 | − insertHighlightedCode(evt.data); | |
| 625 | − }; | |
| 626 | − | |
| 627 | − worker.postMessage(JSON.stringify({ | |
| 628 | − language: env.language, | |
| 629 | − code: env.code, | |
| 630 | − immediateClose: true | |
| 631 | − })); | |
| 632 | − } else { | |
| 633 | − insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); | |
| 634 | − } | |
| 635 | − }, | |
| 636 | − | |
| 637 | − /** | |
| 638 | − * Low-level function, only use if you know what you’re doing. It accepts a string of text as input | |
| 639 | − * and the language definitions to use, and returns a string with the HTML produced. | |
| 640 | − * | |
| 641 | − * The following hooks will be run: | |
| 642 | − * 1. `before-tokenize` | |
| 643 | − * 2. `after-tokenize` | |
| 644 | − * 3. `wrap`: On each {@link Token}. | |
| 645 | − * | |
| 646 | − * @param {string} text A string with the code to be highlighted. | |
| 647 | − * @param {Grammar} grammar An object containing the tokens to use. | |
| 648 | − * | |
| 649 | − * Usually a language definition like `Prism.languages.markup`. | |
| 650 | − * @param {string} language The name of the language definition passed to `grammar`. | |
| 651 | − * @returns {string} The highlighted HTML. | |
| 652 | − * @memberof Prism | |
| 653 | − * @public | |
| 654 | − * @example | |
| 655 | − * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); | |
| 656 | − */ | |
| 657 | − highlight: function (text, grammar, language) { | |
| 658 | − var env = { | |
| 659 | − code: text, | |
| 660 | − grammar: grammar, | |
| 661 | − language: language | |
| 662 | − }; | |
| 663 | − _.hooks.run('before-tokenize', env); | |
| 664 | − if (!env.grammar) { | |
| 665 | − throw new Error('The language "' + env.language + '" has no grammar.'); | |
| 666 | − } | |
| 667 | − env.tokens = _.tokenize(env.code, env.grammar); | |
| 668 | − _.hooks.run('after-tokenize', env); | |
| 669 | − return Token.stringify(_.util.encode(env.tokens), env.language); | |
| 670 | − }, | |
| 671 | − | |
| 672 | − /** | |
| 673 | − * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input | |
| 674 | − * and the language definitions to use, and returns an array with the tokenized code. | |
| 675 | − * | |
| 676 | − * When the language definition includes nested tokens, the function is called recursively on each of these tokens. | |
| 677 | − * | |
| 678 | − * This method could be useful in other contexts as well, as a very crude parser. | |
| 679 | − * | |
| 680 | − * @param {string} text A string with the code to be highlighted. | |
| 681 | − * @param {Grammar} grammar An object containing the tokens to use. | |
| 682 | − * | |
| 683 | − * Usually a language definition like `Prism.languages.markup`. | |
| 684 | − * @returns {TokenStream} An array of strings and tokens, a token stream. | |
| 685 | − * @memberof Prism | |
| 686 | − * @public | |
| 687 | − * @example | |
| 688 | − * let code = `var foo = 0;`; | |
| 689 | − * let tokens = Prism.tokenize(code, Prism.languages.javascript); | |
| 690 | − * tokens.forEach(token => { | |
| 691 | − * if (token instanceof Prism.Token && token.type === 'number') { | |
| 692 | − * console.log(`Found numeric literal: ${token.content}`); | |
| 693 | − * } | |
| 694 | − * }); | |
| 695 | − */ | |
| 696 | − tokenize: function (text, grammar) { | |
| 697 | − var rest = grammar.rest; | |
| 698 | − if (rest) { | |
| 699 | − for (var token in rest) { | |
| 700 | − grammar[token] = rest[token]; | |
| 701 | − } | |
| 702 | − | |
| 703 | − delete grammar.rest; | |
| 704 | − } | |
| 705 | − | |
| 706 | − var tokenList = new LinkedList(); | |
| 707 | − addAfter(tokenList, tokenList.head, text); | |
| 708 | − | |
| 709 | − matchGrammar(text, tokenList, grammar, tokenList.head, 0); | |
| 710 | − | |
| 711 | − return toArray(tokenList); | |
| 712 | − }, | |
| 713 | − | |
| 714 | − /** | |
| 715 | − * @namespace | |
| 716 | − * @memberof Prism | |
| 717 | − * @public | |
| 718 | − */ | |
| 719 | − hooks: { | |
| 720 | − all: {}, | |
| 721 | − | |
| 722 | − /** | |
| 723 | − * Adds the given callback to the list of callbacks for the given hook. | |
| 724 | − * | |
| 725 | − * The callback will be invoked when the hook it is registered for is run. | |
| 726 | − * Hooks are usually directly run by a highlight function but you can also run hooks yourself. | |
| 727 | − * | |
| 728 | − * One callback function can be registered to multiple hooks and the same hook multiple times. | |
| 729 | − * | |
| 730 | − * @param {string} name The name of the hook. | |
| 731 | − * @param {HookCallback} callback The callback function which is given environment variables. | |
| 732 | − * @public | |
| 733 | − */ | |
| 734 | − add: function (name, callback) { | |
| 735 | − var hooks = _.hooks.all; | |
| 736 | − | |
| 737 | − hooks[name] = hooks[name] || []; | |
| 738 | − | |
| 739 | − hooks[name].push(callback); | |
| 740 | − }, | |
| 741 | − | |
| 742 | − /** | |
| 743 | − * Runs a hook invoking all registered callbacks with the given environment variables. | |
| 744 | − * | |
| 745 | − * Callbacks will be invoked synchronously and in the order in which they were registered. | |
| 746 | − * | |
| 747 | − * @param {string} name The name of the hook. | |
| 748 | − * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. | |
| 749 | − * @public | |
| 750 | − */ | |
| 751 | − run: function (name, env) { | |
| 752 | − var callbacks = _.hooks.all[name]; | |
| 753 | − | |
| 754 | − if (!callbacks || !callbacks.length) { | |
| 755 | − return; | |
| 756 | − } | |
| 757 | − | |
| 758 | − for (var i = 0, callback; (callback = callbacks[i++]);) { | |
| 759 | − callback(env); | |
| 760 | − } | |
| 761 | − } | |
| 762 | − }, | |
| 763 | − | |
| 764 | − Token: Token | |
| 765 | − }; | |
| 766 | − _self.Prism = _; | |
| 767 | − | |
| 768 | − | |
| 769 | − // Typescript note: | |
| 770 | − // The following can be used to import the Token type in JSDoc: | |
| 771 | − // | |
| 772 | − // @typedef {InstanceType<import("./prism-core")["Token"]>} Token | |
| 773 | − | |
| 774 | − /** | |
| 775 | − * Creates a new token. | |
| 776 | − * | |
| 777 | − * @param {string} type See {@link Token#type type} | |
| 778 | − * @param {string | TokenStream} content See {@link Token#content content} | |
| 779 | − * @param {string|string[]} [alias] The alias(es) of the token. | |
| 780 | − * @param {string} [matchedStr=""] A copy of the full string this token was created from. | |
| 781 | − * @class | |
| 782 | − * @global | |
| 783 | − * @public | |
| 784 | − */ | |
| 785 | − function Token(type, content, alias, matchedStr) { | |
| 786 | − /** | |
| 787 | − * The type of the token. | |
| 788 | − * | |
| 789 | − * This is usually the key of a pattern in a {@link Grammar}. | |
| 790 | − * | |
| 791 | − * @type {string} | |
| 792 | − * @see GrammarToken | |
| 793 | − * @public | |
| 794 | − */ | |
| 795 | − this.type = type; | |
| 796 | − /** | |
| 797 | − * The strings or tokens contained by this token. | |
| 798 | − * | |
| 799 | − * This will be a token stream if the pattern matched also defined an `inside` grammar. | |
| 800 | − * | |
| 801 | − * @type {string | TokenStream} | |
| 802 | − * @public | |
| 803 | − */ | |
| 804 | − this.content = content; | |
| 805 | − /** | |
| 806 | − * The alias(es) of the token. | |
| 807 | − * | |
| 808 | − * @type {string|string[]} | |
| 809 | − * @see GrammarToken | |
| 810 | − * @public | |
| 811 | − */ | |
| 812 | − this.alias = alias; | |
| 813 | − // Copy of the full string this token was created from | |
| 814 | − this.length = (matchedStr || '').length | 0; | |
| 815 | − } | |
| 816 | − | |
| 817 | − /** | |
| 818 | − * A token stream is an array of strings and {@link Token Token} objects. | |
| 819 | − * | |
| 820 | − * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process | |
| 821 | − * them. | |
| 822 | − * | |
| 823 | − * 1. No adjacent strings. | |
| 824 | − * 2. No empty strings. | |
| 825 | − * | |
| 826 | − * The only exception here is the token stream that only contains the empty string and nothing else. | |
| 827 | − * | |
| 828 | − * @typedef {Array<string | Token>} TokenStream | |
| 829 | − * @global | |
| 830 | − * @public | |
| 831 | − */ | |
| 832 | − | |
| 833 | − /** | |
| 834 | − * Converts the given token or token stream to an HTML representation. | |
| 835 | − * | |
| 836 | − * The following hooks will be run: | |
| 837 | − * 1. `wrap`: On each {@link Token}. | |
| 838 | − * | |
| 839 | − * @param {string | Token | TokenStream} o The token or token stream to be converted. | |
| 840 | − * @param {string} language The name of current language. | |
| 841 | − * @returns {string} The HTML representation of the token or token stream. | |
| 842 | − * @memberof Token | |
| 843 | − * @static | |
| 844 | − */ | |
| 845 | − Token.stringify = function stringify(o, language) { | |
| 846 | − if (typeof o == 'string') { | |
| 847 | − return o; | |
| 848 | − } | |
| 849 | − if (Array.isArray(o)) { | |
| 850 | − var s = ''; | |
| 851 | − o.forEach(function (e) { | |
| 852 | − s += stringify(e, language); | |
| 853 | − }); | |
| 854 | − return s; | |
| 855 | − } | |
| 856 | − | |
| 857 | − var env = { | |
| 858 | − type: o.type, | |
| 859 | − content: stringify(o.content, language), | |
| 860 | − tag: 'span', | |
| 861 | − classes: ['token', o.type], | |
| 862 | − attributes: {}, | |
| 863 | − language: language | |
| 864 | − }; | |
| 865 | − | |
| 866 | − var aliases = o.alias; | |
| 867 | − if (aliases) { | |
| 868 | − if (Array.isArray(aliases)) { | |
| 869 | − Array.prototype.push.apply(env.classes, aliases); | |
| 870 | − } else { | |
| 871 | − env.classes.push(aliases); | |
| 872 | − } | |
| 873 | − } | |
| 874 | − | |
| 875 | − _.hooks.run('wrap', env); | |
| 876 | − | |
| 877 | − var attributes = ''; | |
| 878 | − for (var name in env.attributes) { | |
| 879 | − attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; | |
| 880 | − } | |
| 881 | − | |
| 882 | − return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>'; | |
| 883 | − }; | |
| 884 | − | |
| 885 | − /** | |
| 886 | − * @param {RegExp} pattern | |
| 887 | − * @param {number} pos | |
| 888 | − * @param {string} text | |
| 889 | − * @param {boolean} lookbehind | |
| 890 | − * @returns {RegExpExecArray | null} | |
| 891 | − */ | |
| 892 | − function matchPattern(pattern, pos, text, lookbehind) { | |
| 893 | − pattern.lastIndex = pos; | |
| 894 | − var match = pattern.exec(text); | |
| 895 | − if (match && lookbehind && match[1]) { | |
| 896 | − // change the match to remove the text matched by the Prism lookbehind group | |
| 897 | − var lookbehindLength = match[1].length; | |
| 898 | − match.index += lookbehindLength; | |
| 899 | − match[0] = match[0].slice(lookbehindLength); | |
| 900 | − } | |
| 901 | − return match; | |
| 902 | − } | |
| 903 | − | |
| 904 | − /** | |
| 905 | − * @param {string} text | |
| 906 | − * @param {LinkedList<string | Token>} tokenList | |
| 907 | − * @param {any} grammar | |
| 908 | − * @param {LinkedListNode<string | Token>} startNode | |
| 909 | − * @param {number} startPos | |
| 910 | − * @param {RematchOptions} [rematch] | |
| 911 | − * @returns {void} | |
| 912 | − * @private | |
| 913 | − * | |
| 914 | − * @typedef RematchOptions | |
| 915 | − * @property {string} cause | |
| 916 | − * @property {number} reach | |
| 917 | − */ | |
| 918 | − function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) { | |
| 919 | − for (var token in grammar) { | |
| 920 | − if (!grammar.hasOwnProperty(token) || !grammar[token]) { | |
| 921 | − continue; | |
| 922 | − } | |
| 923 | − | |
| 924 | − var patterns = grammar[token]; | |
| 925 | − patterns = Array.isArray(patterns) ? patterns : [patterns]; | |
| 926 | − | |
| 927 | − for (var j = 0; j < patterns.length; ++j) { | |
| 928 | − if (rematch && rematch.cause == token + ',' + j) { | |
| 929 | − return; | |
| 930 | − } | |
| 931 | − | |
| 932 | − var patternObj = patterns[j]; | |
| 933 | − var inside = patternObj.inside; | |
| 934 | − var lookbehind = !!patternObj.lookbehind; | |
| 935 | − var greedy = !!patternObj.greedy; | |
| 936 | − var alias = patternObj.alias; | |
| 937 | − | |
| 938 | − if (greedy && !patternObj.pattern.global) { | |
| 939 | − // Without the global flag, lastIndex won't work | |
| 940 | − var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; | |
| 941 | − patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g'); | |
| 942 | − } | |
| 943 | − | |
| 944 | − /** @type {RegExp} */ | |
| 945 | − var pattern = patternObj.pattern || patternObj; | |
| 946 | − | |
| 947 | − for ( // iterate the token list and keep track of the current token/string position | |
| 948 | − var currentNode = startNode.next, pos = startPos; | |
| 949 | − currentNode !== tokenList.tail; | |
| 950 | − pos += currentNode.value.length, currentNode = currentNode.next | |
| 951 | − ) { | |
| 952 | − | |
| 953 | − if (rematch && pos >= rematch.reach) { | |
| 954 | − break; | |
| 955 | − } | |
| 956 | − | |
| 957 | − var str = currentNode.value; | |
| 958 | − | |
| 959 | − if (tokenList.length > text.length) { | |
| 960 | − // Something went terribly wrong, ABORT, ABORT! | |
| 961 | − return; | |
| 962 | − } | |
| 963 | − | |
| 964 | − if (str instanceof Token) { | |
| 965 | − continue; | |
| 966 | − } | |
| 967 | − | |
| 968 | − var removeCount = 1; // this is the to parameter of removeBetween | |
| 969 | − var match; | |
| 970 | − | |
| 971 | − if (greedy) { | |
| 972 | − match = matchPattern(pattern, pos, text, lookbehind); | |
| 973 | − if (!match || match.index >= text.length) { | |
| 974 | − break; | |
| 975 | − } | |
| 976 | − | |
| 977 | − var from = match.index; | |
| 978 | − var to = match.index + match[0].length; | |
| 979 | − var p = pos; | |
| 980 | − | |
| 981 | − // find the node that contains the match | |
| 982 | − p += currentNode.value.length; | |
| 983 | − while (from >= p) { | |
| 984 | − currentNode = currentNode.next; | |
| 985 | − p += currentNode.value.length; | |
| 986 | − } | |
| 987 | − // adjust pos (and p) | |
| 988 | − p -= currentNode.value.length; | |
| 989 | − pos = p; | |
| 990 | − | |
| 991 | − // the current node is a Token, then the match starts inside another Token, which is invalid | |
| 992 | − if (currentNode.value instanceof Token) { | |
| 993 | − continue; | |
| 994 | − } | |
| 995 | − | |
| 996 | − // find the last node which is affected by this match | |
| 997 | − for ( | |
| 998 | − var k = currentNode; | |
| 999 | − k !== tokenList.tail && (p < to || typeof k.value === 'string'); | |
| 1000 | − k = k.next | |
| 1001 | − ) { | |
| 1002 | − removeCount++; | |
| 1003 | − p += k.value.length; | |
| 1004 | − } | |
| 1005 | − removeCount--; | |
| 1006 | − | |
| 1007 | − // replace with the new match | |
| 1008 | − str = text.slice(pos, p); | |
| 1009 | − match.index -= pos; | |
| 1010 | − } else { | |
| 1011 | − match = matchPattern(pattern, 0, str, lookbehind); | |
| 1012 | − if (!match) { | |
| 1013 | − continue; | |
| 1014 | − } | |
| 1015 | − } | |
| 1016 | − | |
| 1017 | − // eslint-disable-next-line no-redeclare | |
| 1018 | − var from = match.index; | |
| 1019 | − var matchStr = match[0]; | |
| 1020 | − var before = str.slice(0, from); | |
| 1021 | − var after = str.slice(from + matchStr.length); | |
| 1022 | − | |
| 1023 | − var reach = pos + str.length; | |
| 1024 | − if (rematch && reach > rematch.reach) { | |
| 1025 | − rematch.reach = reach; | |
| 1026 | − } | |
| 1027 | − | |
| 1028 | − var removeFrom = currentNode.prev; | |
| 1029 | − | |
| 1030 | − if (before) { | |
| 1031 | − removeFrom = addAfter(tokenList, removeFrom, before); | |
| 1032 | − pos += before.length; | |
| 1033 | − } | |
| 1034 | − | |
| 1035 | − removeRange(tokenList, removeFrom, removeCount); | |
| 1036 | − | |
| 1037 | − var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr); | |
| 1038 | − currentNode = addAfter(tokenList, removeFrom, wrapped); | |
| 1039 | − | |
| 1040 | − if (after) { | |
| 1041 | − addAfter(tokenList, currentNode, after); | |
| 1042 | − } | |
| 1043 | − | |
| 1044 | − if (removeCount > 1) { | |
| 1045 | − // at least one Token object was removed, so we have to do some rematching | |
| 1046 | − // this can only happen if the current pattern is greedy | |
| 1047 | − | |
| 1048 | − /** @type {RematchOptions} */ | |
| 1049 | − var nestedRematch = { | |
| 1050 | − cause: token + ',' + j, | |
| 1051 | − reach: reach | |
| 1052 | − }; | |
| 1053 | − matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch); | |
| 1054 | − | |
| 1055 | − // the reach might have been extended because of the rematching | |
| 1056 | − if (rematch && nestedRematch.reach > rematch.reach) { | |
| 1057 | − rematch.reach = nestedRematch.reach; | |
| 1058 | − } | |
| 1059 | − } | |
| 1060 | − } | |
| 1061 | − } | |
| 1062 | − } | |
| 1063 | − } | |
| 1064 | − | |
| 1065 | − /** | |
| 1066 | − * @typedef LinkedListNode | |
| 1067 | − * @property {T} value | |
| 1068 | − * @property {LinkedListNode<T> | null} prev The previous node. | |
| 1069 | − * @property {LinkedListNode<T> | null} next The next node. | |
| 1070 | − * @template T | |
| 1071 | − * @private | |
| 1072 | − */ | |
| 1073 | − | |
| 1074 | − /** | |
| 1075 | − * @template T | |
| 1076 | − * @private | |
| 1077 | − */ | |
| 1078 | − function LinkedList() { | |
| 1079 | − /** @type {LinkedListNode<T>} */ | |
| 1080 | − var head = { value: null, prev: null, next: null }; | |
| 1081 | − /** @type {LinkedListNode<T>} */ | |
| 1082 | − var tail = { value: null, prev: head, next: null }; | |
| 1083 | − head.next = tail; | |
| 1084 | − | |
| 1085 | − /** @type {LinkedListNode<T>} */ | |
| 1086 | − this.head = head; | |
| 1087 | − /** @type {LinkedListNode<T>} */ | |
| 1088 | − this.tail = tail; | |
| 1089 | − this.length = 0; | |
| 1090 | − } | |
| 1091 | − | |
| 1092 | − /** | |
| 1093 | − * Adds a new node with the given value to the list. | |
| 1094 | − * | |
| 1095 | − * @param {LinkedList<T>} list | |
| 1096 | − * @param {LinkedListNode<T>} node | |
| 1097 | − * @param {T} value | |
| 1098 | − * @returns {LinkedListNode<T>} The added node. | |
| 1099 | − * @template T | |
| 1100 | − */ | |
| 1101 | − function addAfter(list, node, value) { | |
| 1102 | − // assumes that node != list.tail && values.length >= 0 | |
| 1103 | − var next = node.next; | |
| 1104 | − | |
| 1105 | − var newNode = { value: value, prev: node, next: next }; | |
| 1106 | − node.next = newNode; | |
| 1107 | − next.prev = newNode; | |
| 1108 | − list.length++; | |
| 1109 | − | |
| 1110 | − return newNode; | |
| 1111 | − } | |
| 1112 | − /** | |
| 1113 | − * Removes `count` nodes after the given node. The given node will not be removed. | |
| 1114 | − * | |
| 1115 | − * @param {LinkedList<T>} list | |
| 1116 | − * @param {LinkedListNode<T>} node | |
| 1117 | − * @param {number} count | |
| 1118 | − * @template T | |
| 1119 | − */ | |
| 1120 | − function removeRange(list, node, count) { | |
| 1121 | − var next = node.next; | |
| 1122 | − for (var i = 0; i < count && next !== list.tail; i++) { | |
| 1123 | − next = next.next; | |
| 1124 | − } | |
| 1125 | − node.next = next; | |
| 1126 | − next.prev = node; | |
| 1127 | − list.length -= i; | |
| 1128 | − } | |
| 1129 | − /** | |
| 1130 | − * @param {LinkedList<T>} list | |
| 1131 | − * @returns {T[]} | |
| 1132 | − * @template T | |
| 1133 | − */ | |
| 1134 | − function toArray(list) { | |
| 1135 | − var array = []; | |
| 1136 | − var node = list.head.next; | |
| 1137 | − while (node !== list.tail) { | |
| 1138 | − array.push(node.value); | |
| 1139 | − node = node.next; | |
| 1140 | − } | |
| 1141 | − return array; | |
| 1142 | − } | |
| 1143 | − | |
| 1144 | − | |
| 1145 | − if (!_self.document) { | |
| 1146 | − if (!_self.addEventListener) { | |
| 1147 | − // in Node.js | |
| 1148 | − return _; | |
| 1149 | − } | |
| 1150 | − | |
| 1151 | − if (!_.disableWorkerMessageHandler) { | |
| 1152 | − // In worker | |
| 1153 | − _self.addEventListener('message', function (evt) { | |
| 1154 | − var message = JSON.parse(evt.data); | |
| 1155 | − var lang = message.language; | |
| 1156 | − var code = message.code; | |
| 1157 | − var immediateClose = message.immediateClose; | |
| 1158 | − | |
| 1159 | − _self.postMessage(_.highlight(code, _.languages[lang], lang)); | |
| 1160 | − if (immediateClose) { | |
| 1161 | − _self.close(); | |
| 1162 | − } | |
| 1163 | − }, false); | |
| 1164 | − } | |
| 1165 | − | |
| 1166 | − return _; | |
| 1167 | − } | |
| 1168 | − | |
| 1169 | − // Get current script and highlight | |
| 1170 | − var script = _.util.currentScript(); | |
| 1171 | − | |
| 1172 | − if (script) { | |
| 1173 | − _.filename = script.src; | |
| 1174 | − | |
| 1175 | − if (script.hasAttribute('data-manual')) { | |
| 1176 | − _.manual = true; | |
| 1177 | − } | |
| 1178 | − } | |
| 1179 | − | |
| 1180 | − function highlightAutomaticallyCallback() { | |
| 1181 | − if (!_.manual) { | |
| 1182 | − _.highlightAll(); | |
| 1183 | − } | |
| 1184 | − } | |
| 1185 | − | |
| 1186 | − if (!_.manual) { | |
| 1187 | − // If the document state is "loading", then we'll use DOMContentLoaded. | |
| 1188 | − // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the | |
| 1189 | − // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they | |
| 1190 | − // might take longer one animation frame to execute which can create a race condition where only some plugins have | |
| 1191 | − // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. | |
| 1192 | − // See https://github.com/PrismJS/prism/issues/2102 | |
| 1193 | − var readyState = document.readyState; | |
| 1194 | − if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { | |
| 1195 | − document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); | |
| 1196 | − } else { | |
| 1197 | − if (window.requestAnimationFrame) { | |
| 1198 | − window.requestAnimationFrame(highlightAutomaticallyCallback); | |
| 1199 | − } else { | |
| 1200 | − window.setTimeout(highlightAutomaticallyCallback, 16); | |
| 1201 | − } | |
| 1202 | − } | |
| 1203 | − } | |
| 1204 | − | |
| 1205 | − return _; | |
| 1206 | − | |
| 1207 | −}(_self)); | |
| 1208 | − | |
| 1209 | −if (typeof module !== 'undefined' && module.exports) { | |
| 1210 | − module.exports = Prism; | |
| 22 | + // Private helper vars | |
| 23 | + var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; | |
| 24 | + var uniqueId = 0; | |
| 25 | + | |
| 26 | + // The grammar object for plaintext | |
| 27 | + var plainTextGrammar = {}; | |
| 28 | + | |
| 29 | + var _ = { | |
| 30 | + /** | |
| 31 | + * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the | |
| 32 | + * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load | |
| 33 | + * additional languages or plugins yourself. | |
| 34 | + * | |
| 35 | + * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. | |
| 36 | + * | |
| 37 | + * You obviously have to change this value before the automatic highlighting started. To do this, you can add an | |
| 38 | + * empty Prism object into the global scope before loading the Prism script like this: | |
| 39 | + * | |
| 40 | + * ```js | |
| 41 | + * window.Prism = window.Prism || {}; | |
| 42 | + * Prism.manual = true; | |
| 43 | + * // add a new <script> to load Prism's script | |
| 44 | + * ``` | |
| 45 | + * | |
| 46 | + * @default false | |
| 47 | + * @type {boolean} | |
| 48 | + * @memberof Prism | |
| 49 | + * @public | |
| 50 | + */ | |
| 51 | + manual: _self.Prism && _self.Prism.manual, | |
| 52 | + /** | |
| 53 | + * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses | |
| 54 | + * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your | |
| 55 | + * own worker, you don't want it to do this. | |
| 56 | + * | |
| 57 | + * By setting this value to `true`, Prism will not add its own listeners to the worker. | |
| 58 | + * | |
| 59 | + * You obviously have to change this value before Prism executes. To do this, you can add an | |
| 60 | + * empty Prism object into the global scope before loading the Prism script like this: | |
| 61 | + * | |
| 62 | + * ```js | |
| 63 | + * window.Prism = window.Prism || {}; | |
| 64 | + * Prism.disableWorkerMessageHandler = true; | |
| 65 | + * // Load Prism's script | |
| 66 | + * ``` | |
| 67 | + * | |
| 68 | + * @default false | |
| 69 | + * @type {boolean} | |
| 70 | + * @memberof Prism | |
| 71 | + * @public | |
| 72 | + */ | |
| 73 | + disableWorkerMessageHandler: | |
| 74 | + _self.Prism && _self.Prism.disableWorkerMessageHandler, | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * A namespace for utility methods. | |
| 78 | + * | |
| 79 | + * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may | |
| 80 | + * change or disappear at any time. | |
| 81 | + * | |
| 82 | + * @namespace | |
| 83 | + * @memberof Prism | |
| 84 | + */ | |
| 85 | + util: { | |
| 86 | + encode: function encode(tokens) { | |
| 87 | + if (tokens instanceof Token) { | |
| 88 | + return new Token(tokens.type, encode(tokens.content), tokens.alias); | |
| 89 | + } else if (Array.isArray(tokens)) { | |
| 90 | + return tokens.map(encode); | |
| 91 | + } else { | |
| 92 | + return tokens | |
| 93 | + .replace(/&/g, "&") | |
| 94 | + .replace(/</g, "<") | |
| 95 | + .replace(/\u00a0/g, " "); | |
| 96 | + } | |
| 97 | + }, | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Returns the name of the type of the given value. | |
| 101 | + * | |
| 102 | + * @param {any} o | |
| 103 | + * @returns {string} | |
| 104 | + * @example | |
| 105 | + * type(null) === 'Null' | |
| 106 | + * type(undefined) === 'Undefined' | |
| 107 | + * type(123) === 'Number' | |
| 108 | + * type('foo') === 'String' | |
| 109 | + * type(true) === 'Boolean' | |
| 110 | + * type([1, 2]) === 'Array' | |
| 111 | + * type({}) === 'Object' | |
| 112 | + * type(String) === 'Function' | |
| 113 | + * type(/abc+/) === 'RegExp' | |
| 114 | + */ | |
| 115 | + type: function (o) { | |
| 116 | + return Object.prototype.toString.call(o).slice(8, -1); | |
| 117 | + }, | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Returns a unique number for the given object. Later calls will still return the same number. | |
| 121 | + * | |
| 122 | + * @param {Object} obj | |
| 123 | + * @returns {number} | |
| 124 | + */ | |
| 125 | + objId: function (obj) { | |
| 126 | + if (!obj["__id"]) { | |
| 127 | + Object.defineProperty(obj, "__id", { value: ++uniqueId }); | |
| 128 | + } | |
| 129 | + return obj["__id"]; | |
| 130 | + }, | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * Creates a deep clone of the given object. | |
| 134 | + * | |
| 135 | + * The main intended use of this function is to clone language definitions. | |
| 136 | + * | |
| 137 | + * @param {T} o | |
| 138 | + * @param {Record<number, any>} [visited] | |
| 139 | + * @returns {T} | |
| 140 | + * @template T | |
| 141 | + */ | |
| 142 | + clone: function deepClone(o, visited) { | |
| 143 | + visited = visited || {}; | |
| 144 | + | |
| 145 | + var clone; | |
| 146 | + var id; | |
| 147 | + switch (_.util.type(o)) { | |
| 148 | + case "Object": | |
| 149 | + id = _.util.objId(o); | |
| 150 | + if (visited[id]) { | |
| 151 | + return visited[id]; | |
| 152 | + } | |
| 153 | + clone = /** @type {Record<string, any>} */ ({}); | |
| 154 | + visited[id] = clone; | |
| 155 | + | |
| 156 | + for (var key in o) { | |
| 157 | + if (o.hasOwnProperty(key)) { | |
| 158 | + clone[key] = deepClone(o[key], visited); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + return /** @type {any} */ (clone); | |
| 163 | + | |
| 164 | + case "Array": | |
| 165 | + id = _.util.objId(o); | |
| 166 | + if (visited[id]) { | |
| 167 | + return visited[id]; | |
| 168 | + } | |
| 169 | + clone = []; | |
| 170 | + visited[id] = clone; | |
| 171 | + | |
| 172 | + /** @type {Array} */ (/** @type {any} */ (o)).forEach( | |
| 173 | + function (v, i) { | |
| 174 | + clone[i] = deepClone(v, visited); | |
| 175 | + }, | |
| 176 | + ); | |
| 177 | + | |
| 178 | + return /** @type {any} */ (clone); | |
| 179 | + | |
| 180 | + default: | |
| 181 | + return o; | |
| 182 | + } | |
| 183 | + }, | |
| 184 | + | |
| 185 | + /** | |
| 186 | + * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. | |
| 187 | + * | |
| 188 | + * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. | |
| 189 | + * | |
| 190 | + * @param {Element} element | |
| 191 | + * @returns {string} | |
| 192 | + */ | |
| 193 | + getLanguage: function (element) { | |
| 194 | + while (element) { | |
| 195 | + var m = lang.exec(element.className); | |
| 196 | + if (m) { | |
| 197 | + return m[1].toLowerCase(); | |
| 198 | + } | |
| 199 | + element = element.parentElement; | |
| 200 | + } | |
| 201 | + return "none"; | |
| 202 | + }, | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Sets the Prism `language-xxxx` class of the given element. | |
| 206 | + * | |
| 207 | + * @param {Element} element | |
| 208 | + * @param {string} language | |
| 209 | + * @returns {void} | |
| 210 | + */ | |
| 211 | + setLanguage: function (element, language) { | |
| 212 | + // remove all `language-xxxx` classes | |
| 213 | + // (this might leave behind a leading space) | |
| 214 | + element.className = element.className.replace(RegExp(lang, "gi"), ""); | |
| 215 | + | |
| 216 | + // add the new `language-xxxx` class | |
| 217 | + // (using `classList` will automatically clean up spaces for us) | |
| 218 | + element.classList.add("language-" + language); | |
| 219 | + }, | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Returns the script element that is currently executing. | |
| 223 | + * | |
| 224 | + * This does __not__ work for line script element. | |
| 225 | + * | |
| 226 | + * @returns {HTMLScriptElement | null} | |
| 227 | + */ | |
| 228 | + currentScript: function () { | |
| 229 | + if (typeof document === "undefined") { | |
| 230 | + return null; | |
| 231 | + } | |
| 232 | + if ( | |
| 233 | + "currentScript" in document && | |
| 234 | + 1 < 2 /* hack to trip TS' flow analysis */ | |
| 235 | + ) { | |
| 236 | + return /** @type {any} */ (document.currentScript); | |
| 237 | + } | |
| 238 | + | |
| 239 | + // IE11 workaround | |
| 240 | + // we'll get the src of the current script by parsing IE11's error stack trace | |
| 241 | + // this will not work for inline scripts | |
| 242 | + | |
| 243 | + try { | |
| 244 | + throw new Error(); | |
| 245 | + } catch (err) { | |
| 246 | + // Get file src url from stack. Specifically works with the format of stack traces in IE. | |
| 247 | + // A stack will look like this: | |
| 248 | + // | |
| 249 | + // Error | |
| 250 | + // at _.util.currentScript (http://localhost/components/prism-core.js:119:5) | |
| 251 | + // at Global code (http://localhost/components/prism-core.js:606:1) | |
| 252 | + | |
| 253 | + var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || | |
| 254 | + [])[1]; | |
| 255 | + if (src) { | |
| 256 | + var scripts = document.getElementsByTagName("script"); | |
| 257 | + for (var i in scripts) { | |
| 258 | + if (scripts[i].src == src) { | |
| 259 | + return scripts[i]; | |
| 260 | + } | |
| 261 | + } | |
| 262 | + } | |
| 263 | + return null; | |
| 264 | + } | |
| 265 | + }, | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * Returns whether a given class is active for `element`. | |
| 269 | + * | |
| 270 | + * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated | |
| 271 | + * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the | |
| 272 | + * given class is just the given class with a `no-` prefix. | |
| 273 | + * | |
| 274 | + * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is | |
| 275 | + * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its | |
| 276 | + * ancestors have the given class or the negated version of it, then the default activation will be returned. | |
| 277 | + * | |
| 278 | + * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated | |
| 279 | + * version of it, the class is considered active. | |
| 280 | + * | |
| 281 | + * @param {Element} element | |
| 282 | + * @param {string} className | |
| 283 | + * @param {boolean} [defaultActivation=false] | |
| 284 | + * @returns {boolean} | |
| 285 | + */ | |
| 286 | + isActive: function (element, className, defaultActivation) { | |
| 287 | + var no = "no-" + className; | |
| 288 | + | |
| 289 | + while (element) { | |
| 290 | + var classList = element.classList; | |
| 291 | + if (classList.contains(className)) { | |
| 292 | + return true; | |
| 293 | + } | |
| 294 | + if (classList.contains(no)) { | |
| 295 | + return false; | |
| 296 | + } | |
| 297 | + element = element.parentElement; | |
| 298 | + } | |
| 299 | + return !!defaultActivation; | |
| 300 | + }, | |
| 301 | + }, | |
| 302 | + | |
| 303 | + /** | |
| 304 | + * This namespace contains all currently loaded languages and the some helper functions to create and modify languages. | |
| 305 | + * | |
| 306 | + * @namespace | |
| 307 | + * @memberof Prism | |
| 308 | + * @public | |
| 309 | + */ | |
| 310 | + languages: { | |
| 311 | + /** | |
| 312 | + * The grammar for plain, unformatted text. | |
| 313 | + */ | |
| 314 | + plain: plainTextGrammar, | |
| 315 | + plaintext: plainTextGrammar, | |
| 316 | + text: plainTextGrammar, | |
| 317 | + txt: plainTextGrammar, | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * Creates a deep copy of the language with the given id and appends the given tokens. | |
| 321 | + * | |
| 322 | + * If a token in `redef` also appears in the copied language, then the existing token in the copied language | |
| 323 | + * will be overwritten at its original position. | |
| 324 | + * | |
| 325 | + * ## Best practices | |
| 326 | + * | |
| 327 | + * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) | |
| 328 | + * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to | |
| 329 | + * understand the language definition because, normally, the order of tokens matters in Prism grammars. | |
| 330 | + * | |
| 331 | + * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. | |
| 332 | + * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. | |
| 333 | + * | |
| 334 | + * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. | |
| 335 | + * @param {Grammar} redef The new tokens to append. | |
| 336 | + * @returns {Grammar} The new language created. | |
| 337 | + * @public | |
| 338 | + * @example | |
| 339 | + * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { | |
| 340 | + * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token | |
| 341 | + * // at its original position | |
| 342 | + * 'comment': { ... }, | |
| 343 | + * // CSS doesn't have a 'color' token, so this token will be appended | |
| 344 | + * 'color': /\b(?:red|green|blue)\b/ | |
| 345 | + * }); | |
| 346 | + */ | |
| 347 | + extend: function (id, redef) { | |
| 348 | + var lang = _.util.clone(_.languages[id]); | |
| 349 | + | |
| 350 | + for (var key in redef) { | |
| 351 | + lang[key] = redef[key]; | |
| 352 | + } | |
| 353 | + | |
| 354 | + return lang; | |
| 355 | + }, | |
| 356 | + | |
| 357 | + /** | |
| 358 | + * Inserts tokens _before_ another token in a language definition or any other grammar. | |
| 359 | + * | |
| 360 | + * ## Usage | |
| 361 | + * | |
| 362 | + * This helper method makes it easy to modify existing languages. For example, the CSS language definition | |
| 363 | + * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded | |
| 364 | + * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the | |
| 365 | + * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do | |
| 366 | + * this: | |
| 367 | + * | |
| 368 | + * ```js | |
| 369 | + * Prism.languages.markup.style = { | |
| 370 | + * // token | |
| 371 | + * }; | |
| 372 | + * ``` | |
| 373 | + * | |
| 374 | + * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens | |
| 375 | + * before existing tokens. For the CSS example above, you would use it like this: | |
| 376 | + * | |
| 377 | + * ```js | |
| 378 | + * Prism.languages.insertBefore('markup', 'cdata', { | |
| 379 | + * 'style': { | |
| 380 | + * // token | |
| 381 | + * } | |
| 382 | + * }); | |
| 383 | + * ``` | |
| 384 | + * | |
| 385 | + * ## Special cases | |
| 386 | + * | |
| 387 | + * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar | |
| 388 | + * will be ignored. | |
| 389 | + * | |
| 390 | + * This behavior can be used to insert tokens after `before`: | |
| 391 | + * | |
| 392 | + * ```js | |
| 393 | + * Prism.languages.insertBefore('markup', 'comment', { | |
| 394 | + * 'comment': Prism.languages.markup.comment, | |
| 395 | + * // tokens after 'comment' | |
| 396 | + * }); | |
| 397 | + * ``` | |
| 398 | + * | |
| 399 | + * ## Limitations | |
| 400 | + * | |
| 401 | + * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object | |
| 402 | + * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave | |
| 403 | + * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily | |
| 404 | + * deleting properties which is necessary to insert at arbitrary positions. | |
| 405 | + * | |
| 406 | + * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. | |
| 407 | + * Instead, it will create a new object and replace all references to the target object with the new one. This | |
| 408 | + * can be done without temporarily deleting properties, so the iteration order is well-defined. | |
| 409 | + * | |
| 410 | + * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if | |
| 411 | + * you hold the target object in a variable, then the value of the variable will not change. | |
| 412 | + * | |
| 413 | + * ```js | |
| 414 | + * var oldMarkup = Prism.languages.markup; | |
| 415 | + * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); | |
| 416 | + * | |
| 417 | + * assert(oldMarkup !== Prism.languages.markup); | |
| 418 | + * assert(newMarkup === Prism.languages.markup); | |
| 419 | + * ``` | |
| 420 | + * | |
| 421 | + * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the | |
| 422 | + * object to be modified. | |
| 423 | + * @param {string} before The key to insert before. | |
| 424 | + * @param {Grammar} insert An object containing the key-value pairs to be inserted. | |
| 425 | + * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the | |
| 426 | + * object to be modified. | |
| 427 | + * | |
| 428 | + * Defaults to `Prism.languages`. | |
| 429 | + * @returns {Grammar} The new grammar object. | |
| 430 | + * @public | |
| 431 | + */ | |
| 432 | + insertBefore: function (inside, before, insert, root) { | |
| 433 | + root = root || /** @type {any} */ (_.languages); | |
| 434 | + var grammar = root[inside]; | |
| 435 | + /** @type {Grammar} */ | |
| 436 | + var ret = {}; | |
| 437 | + | |
| 438 | + for (var token in grammar) { | |
| 439 | + if (grammar.hasOwnProperty(token)) { | |
| 440 | + if (token == before) { | |
| 441 | + for (var newToken in insert) { | |
| 442 | + if (insert.hasOwnProperty(newToken)) { | |
| 443 | + ret[newToken] = insert[newToken]; | |
| 444 | + } | |
| 445 | + } | |
| 446 | + } | |
| 447 | + | |
| 448 | + // Do not insert token which also occur in insert. See #1525 | |
| 449 | + if (!insert.hasOwnProperty(token)) { | |
| 450 | + ret[token] = grammar[token]; | |
| 451 | + } | |
| 452 | + } | |
| 453 | + } | |
| 454 | + | |
| 455 | + var old = root[inside]; | |
| 456 | + root[inside] = ret; | |
| 457 | + | |
| 458 | + // Update references in other language definitions | |
| 459 | + _.languages.DFS(_.languages, function (key, value) { | |
| 460 | + if (value === old && key != inside) { | |
| 461 | + this[key] = ret; | |
| 462 | + } | |
| 463 | + }); | |
| 464 | + | |
| 465 | + return ret; | |
| 466 | + }, | |
| 467 | + | |
| 468 | + // Traverse a language definition with Depth First Search | |
| 469 | + DFS: function DFS(o, callback, type, visited) { | |
| 470 | + visited = visited || {}; | |
| 471 | + | |
| 472 | + var objId = _.util.objId; | |
| 473 | + | |
| 474 | + for (var i in o) { | |
| 475 | + if (o.hasOwnProperty(i)) { | |
| 476 | + callback.call(o, i, o[i], type || i); | |
| 477 | + | |
| 478 | + var property = o[i]; | |
| 479 | + var propertyType = _.util.type(property); | |
| 480 | + | |
| 481 | + if (propertyType === "Object" && !visited[objId(property)]) { | |
| 482 | + visited[objId(property)] = true; | |
| 483 | + DFS(property, callback, null, visited); | |
| 484 | + } else if (propertyType === "Array" && !visited[objId(property)]) { | |
| 485 | + visited[objId(property)] = true; | |
| 486 | + DFS(property, callback, i, visited); | |
| 487 | + } | |
| 488 | + } | |
| 489 | + } | |
| 490 | + }, | |
| 491 | + }, | |
| 492 | + | |
| 493 | + plugins: {}, | |
| 494 | + | |
| 495 | + /** | |
| 496 | + * This is the most high-level function in Prism’s API. | |
| 497 | + * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on | |
| 498 | + * each one of them. | |
| 499 | + * | |
| 500 | + * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. | |
| 501 | + * | |
| 502 | + * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. | |
| 503 | + * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. | |
| 504 | + * @memberof Prism | |
| 505 | + * @public | |
| 506 | + */ | |
| 507 | + highlightAll: function (async, callback) { | |
| 508 | + _.highlightAllUnder(document, async, callback); | |
| 509 | + }, | |
| 510 | + | |
| 511 | + /** | |
| 512 | + * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls | |
| 513 | + * {@link Prism.highlightElement} on each one of them. | |
| 514 | + * | |
| 515 | + * The following hooks will be run: | |
| 516 | + * 1. `before-highlightall` | |
| 517 | + * 2. `before-all-elements-highlight` | |
| 518 | + * 3. All hooks of {@link Prism.highlightElement} for each element. | |
| 519 | + * | |
| 520 | + * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. | |
| 521 | + * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. | |
| 522 | + * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. | |
| 523 | + * @memberof Prism | |
| 524 | + * @public | |
| 525 | + */ | |
| 526 | + highlightAllUnder: function (container, async, callback) { | |
| 527 | + var env = { | |
| 528 | + callback: callback, | |
| 529 | + container: container, | |
| 530 | + selector: | |
| 531 | + 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code', | |
| 532 | + }; | |
| 533 | + | |
| 534 | + _.hooks.run("before-highlightall", env); | |
| 535 | + | |
| 536 | + env.elements = Array.prototype.slice.apply( | |
| 537 | + env.container.querySelectorAll(env.selector), | |
| 538 | + ); | |
| 539 | + | |
| 540 | + _.hooks.run("before-all-elements-highlight", env); | |
| 541 | + | |
| 542 | + for (var i = 0, element; (element = env.elements[i++]); ) { | |
| 543 | + _.highlightElement(element, async === true, env.callback); | |
| 544 | + } | |
| 545 | + }, | |
| 546 | + | |
| 547 | + /** | |
| 548 | + * Highlights the code inside a single element. | |
| 549 | + * | |
| 550 | + * The following hooks will be run: | |
| 551 | + * 1. `before-sanity-check` | |
| 552 | + * 2. `before-highlight` | |
| 553 | + * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. | |
| 554 | + * 4. `before-insert` | |
| 555 | + * 5. `after-highlight` | |
| 556 | + * 6. `complete` | |
| 557 | + * | |
| 558 | + * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for | |
| 559 | + * the element's language. | |
| 560 | + * | |
| 561 | + * @param {Element} element The element containing the code. | |
| 562 | + * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. | |
| 563 | + * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers | |
| 564 | + * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is | |
| 565 | + * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). | |
| 566 | + * | |
| 567 | + * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for | |
| 568 | + * asynchronous highlighting to work. You can build your own bundle on the | |
| 569 | + * [Download page](https://prismjs.com/download.html). | |
| 570 | + * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. | |
| 571 | + * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. | |
| 572 | + * @memberof Prism | |
| 573 | + * @public | |
| 574 | + */ | |
| 575 | + highlightElement: function (element, async, callback) { | |
| 576 | + // Find language | |
| 577 | + var language = _.util.getLanguage(element); | |
| 578 | + var grammar = _.languages[language]; | |
| 579 | + | |
| 580 | + // Set language on the element, if not present | |
| 581 | + _.util.setLanguage(element, language); | |
| 582 | + | |
| 583 | + // Set language on the parent, for styling | |
| 584 | + var parent = element.parentElement; | |
| 585 | + if (parent && parent.nodeName.toLowerCase() === "pre") { | |
| 586 | + _.util.setLanguage(parent, language); | |
| 587 | + } | |
| 588 | + | |
| 589 | + var code = element.textContent; | |
| 590 | + | |
| 591 | + var env = { | |
| 592 | + element: element, | |
| 593 | + language: language, | |
| 594 | + grammar: grammar, | |
| 595 | + code: code, | |
| 596 | + }; | |
| 597 | + | |
| 598 | + function insertHighlightedCode(highlightedCode) { | |
| 599 | + env.highlightedCode = highlightedCode; | |
| 600 | + | |
| 601 | + _.hooks.run("before-insert", env); | |
| 602 | + | |
| 603 | + env.element.innerHTML = env.highlightedCode; | |
| 604 | + | |
| 605 | + _.hooks.run("after-highlight", env); | |
| 606 | + _.hooks.run("complete", env); | |
| 607 | + callback && callback.call(env.element); | |
| 608 | + } | |
| 609 | + | |
| 610 | + _.hooks.run("before-sanity-check", env); | |
| 611 | + | |
| 612 | + // plugins may change/add the parent/element | |
| 613 | + parent = env.element.parentElement; | |
| 614 | + if ( | |
| 615 | + parent && | |
| 616 | + parent.nodeName.toLowerCase() === "pre" && | |
| 617 | + !parent.hasAttribute("tabindex") | |
| 618 | + ) { | |
| 619 | + parent.setAttribute("tabindex", "0"); | |
| 620 | + } | |
| 621 | + | |
| 622 | + if (!env.code) { | |
| 623 | + _.hooks.run("complete", env); | |
| 624 | + callback && callback.call(env.element); | |
| 625 | + return; | |
| 626 | + } | |
| 627 | + | |
| 628 | + _.hooks.run("before-highlight", env); | |
| 629 | + | |
| 630 | + if (!env.grammar) { | |
| 631 | + insertHighlightedCode(_.util.encode(env.code)); | |
| 632 | + return; | |
| 633 | + } | |
| 634 | + | |
| 635 | + if (async && _self.Worker) { | |
| 636 | + var worker = new Worker(_.filename); | |
| 637 | + | |
| 638 | + worker.onmessage = function (evt) { | |
| 639 | + insertHighlightedCode(evt.data); | |
| 640 | + }; | |
| 641 | + | |
| 642 | + worker.postMessage( | |
| 643 | + JSON.stringify({ | |
| 644 | + language: env.language, | |
| 645 | + code: env.code, | |
| 646 | + immediateClose: true, | |
| 647 | + }), | |
| 648 | + ); | |
| 649 | + } else { | |
| 650 | + insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); | |
| 651 | + } | |
| 652 | + }, | |
| 653 | + | |
| 654 | + /** | |
| 655 | + * Low-level function, only use if you know what you’re doing. It accepts a string of text as input | |
| 656 | + * and the language definitions to use, and returns a string with the HTML produced. | |
| 657 | + * | |
| 658 | + * The following hooks will be run: | |
| 659 | + * 1. `before-tokenize` | |
| 660 | + * 2. `after-tokenize` | |
| 661 | + * 3. `wrap`: On each {@link Token}. | |
| 662 | + * | |
| 663 | + * @param {string} text A string with the code to be highlighted. | |
| 664 | + * @param {Grammar} grammar An object containing the tokens to use. | |
| 665 | + * | |
| 666 | + * Usually a language definition like `Prism.languages.markup`. | |
| 667 | + * @param {string} language The name of the language definition passed to `grammar`. | |
| 668 | + * @returns {string} The highlighted HTML. | |
| 669 | + * @memberof Prism | |
| 670 | + * @public | |
| 671 | + * @example | |
| 672 | + * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); | |
| 673 | + */ | |
| 674 | + highlight: function (text, grammar, language) { | |
| 675 | + var env = { | |
| 676 | + code: text, | |
| 677 | + grammar: grammar, | |
| 678 | + language: language, | |
| 679 | + }; | |
| 680 | + _.hooks.run("before-tokenize", env); | |
| 681 | + if (!env.grammar) { | |
| 682 | + throw new Error('The language "' + env.language + '" has no grammar.'); | |
| 683 | + } | |
| 684 | + env.tokens = _.tokenize(env.code, env.grammar); | |
| 685 | + _.hooks.run("after-tokenize", env); | |
| 686 | + return Token.stringify(_.util.encode(env.tokens), env.language); | |
| 687 | + }, | |
| 688 | + | |
| 689 | + /** | |
| 690 | + * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input | |
| 691 | + * and the language definitions to use, and returns an array with the tokenized code. | |
| 692 | + * | |
| 693 | + * When the language definition includes nested tokens, the function is called recursively on each of these tokens. | |
| 694 | + * | |
| 695 | + * This method could be useful in other contexts as well, as a very crude parser. | |
| 696 | + * | |
| 697 | + * @param {string} text A string with the code to be highlighted. | |
| 698 | + * @param {Grammar} grammar An object containing the tokens to use. | |
| 699 | + * | |
| 700 | + * Usually a language definition like `Prism.languages.markup`. | |
| 701 | + * @returns {TokenStream} An array of strings and tokens, a token stream. | |
| 702 | + * @memberof Prism | |
| 703 | + * @public | |
| 704 | + * @example | |
| 705 | + * let code = `var foo = 0;`; | |
| 706 | + * let tokens = Prism.tokenize(code, Prism.languages.javascript); | |
| 707 | + * tokens.forEach(token => { | |
| 708 | + * if (token instanceof Prism.Token && token.type === 'number') { | |
| 709 | + * console.log(`Found numeric literal: ${token.content}`); | |
| 710 | + * } | |
| 711 | + * }); | |
| 712 | + */ | |
| 713 | + tokenize: function (text, grammar) { | |
| 714 | + var rest = grammar.rest; | |
| 715 | + if (rest) { | |
| 716 | + for (var token in rest) { | |
| 717 | + grammar[token] = rest[token]; | |
| 718 | + } | |
| 719 | + | |
| 720 | + delete grammar.rest; | |
| 721 | + } | |
| 722 | + | |
| 723 | + var tokenList = new LinkedList(); | |
| 724 | + addAfter(tokenList, tokenList.head, text); | |
| 725 | + | |
| 726 | + matchGrammar(text, tokenList, grammar, tokenList.head, 0); | |
| 727 | + | |
| 728 | + return toArray(tokenList); | |
| 729 | + }, | |
| 730 | + | |
| 731 | + /** | |
| 732 | + * @namespace | |
| 733 | + * @memberof Prism | |
| 734 | + * @public | |
| 735 | + */ | |
| 736 | + hooks: { | |
| 737 | + all: {}, | |
| 738 | + | |
| 739 | + /** | |
| 740 | + * Adds the given callback to the list of callbacks for the given hook. | |
| 741 | + * | |
| 742 | + * The callback will be invoked when the hook it is registered for is run. | |
| 743 | + * Hooks are usually directly run by a highlight function but you can also run hooks yourself. | |
| 744 | + * | |
| 745 | + * One callback function can be registered to multiple hooks and the same hook multiple times. | |
| 746 | + * | |
| 747 | + * @param {string} name The name of the hook. | |
| 748 | + * @param {HookCallback} callback The callback function which is given environment variables. | |
| 749 | + * @public | |
| 750 | + */ | |
| 751 | + add: function (name, callback) { | |
| 752 | + var hooks = _.hooks.all; | |
| 753 | + | |
| 754 | + hooks[name] = hooks[name] || []; | |
| 755 | + | |
| 756 | + hooks[name].push(callback); | |
| 757 | + }, | |
| 758 | + | |
| 759 | + /** | |
| 760 | + * Runs a hook invoking all registered callbacks with the given environment variables. | |
| 761 | + * | |
| 762 | + * Callbacks will be invoked synchronously and in the order in which they were registered. | |
| 763 | + * | |
| 764 | + * @param {string} name The name of the hook. | |
| 765 | + * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. | |
| 766 | + * @public | |
| 767 | + */ | |
| 768 | + run: function (name, env) { | |
| 769 | + var callbacks = _.hooks.all[name]; | |
| 770 | + | |
| 771 | + if (!callbacks || !callbacks.length) { | |
| 772 | + return; | |
| 773 | + } | |
| 774 | + | |
| 775 | + for (var i = 0, callback; (callback = callbacks[i++]); ) { | |
| 776 | + callback(env); | |
| 777 | + } | |
| 778 | + }, | |
| 779 | + }, | |
| 780 | + | |
| 781 | + Token: Token, | |
| 782 | + }; | |
| 783 | + _self.Prism = _; | |
| 784 | + | |
| 785 | + // Typescript note: | |
| 786 | + // The following can be used to import the Token type in JSDoc: | |
| 787 | + // | |
| 788 | + // @typedef {InstanceType<import("./prism-core")["Token"]>} Token | |
| 789 | + | |
| 790 | + /** | |
| 791 | + * Creates a new token. | |
| 792 | + * | |
| 793 | + * @param {string} type See {@link Token#type type} | |
| 794 | + * @param {string | TokenStream} content See {@link Token#content content} | |
| 795 | + * @param {string|string[]} [alias] The alias(es) of the token. | |
| 796 | + * @param {string} [matchedStr=""] A copy of the full string this token was created from. | |
| 797 | + * @class | |
| 798 | + * @global | |
| 799 | + * @public | |
| 800 | + */ | |
| 801 | + function Token(type, content, alias, matchedStr) { | |
| 802 | + /** | |
| 803 | + * The type of the token. | |
| 804 | + * | |
| 805 | + * This is usually the key of a pattern in a {@link Grammar}. | |
| 806 | + * | |
| 807 | + * @type {string} | |
| 808 | + * @see GrammarToken | |
| 809 | + * @public | |
| 810 | + */ | |
| 811 | + this.type = type; | |
| 812 | + /** | |
| 813 | + * The strings or tokens contained by this token. | |
| 814 | + * | |
| 815 | + * This will be a token stream if the pattern matched also defined an `inside` grammar. | |
| 816 | + * | |
| 817 | + * @type {string | TokenStream} | |
| 818 | + * @public | |
| 819 | + */ | |
| 820 | + this.content = content; | |
| 821 | + /** | |
| 822 | + * The alias(es) of the token. | |
| 823 | + * | |
| 824 | + * @type {string|string[]} | |
| 825 | + * @see GrammarToken | |
| 826 | + * @public | |
| 827 | + */ | |
| 828 | + this.alias = alias; | |
| 829 | + // Copy of the full string this token was created from | |
| 830 | + this.length = (matchedStr || "").length | 0; | |
| 831 | + } | |
| 832 | + | |
| 833 | + /** | |
| 834 | + * A token stream is an array of strings and {@link Token Token} objects. | |
| 835 | + * | |
| 836 | + * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process | |
| 837 | + * them. | |
| 838 | + * | |
| 839 | + * 1. No adjacent strings. | |
| 840 | + * 2. No empty strings. | |
| 841 | + * | |
| 842 | + * The only exception here is the token stream that only contains the empty string and nothing else. | |
| 843 | + * | |
| 844 | + * @typedef {Array<string | Token>} TokenStream | |
| 845 | + * @global | |
| 846 | + * @public | |
| 847 | + */ | |
| 848 | + | |
| 849 | + /** | |
| 850 | + * Converts the given token or token stream to an HTML representation. | |
| 851 | + * | |
| 852 | + * The following hooks will be run: | |
| 853 | + * 1. `wrap`: On each {@link Token}. | |
| 854 | + * | |
| 855 | + * @param {string | Token | TokenStream} o The token or token stream to be converted. | |
| 856 | + * @param {string} language The name of current language. | |
| 857 | + * @returns {string} The HTML representation of the token or token stream. | |
| 858 | + * @memberof Token | |
| 859 | + * @static | |
| 860 | + */ | |
| 861 | + Token.stringify = function stringify(o, language) { | |
| 862 | + if (typeof o == "string") { | |
| 863 | + return o; | |
| 864 | + } | |
| 865 | + if (Array.isArray(o)) { | |
| 866 | + var s = ""; | |
| 867 | + o.forEach(function (e) { | |
| 868 | + s += stringify(e, language); | |
| 869 | + }); | |
| 870 | + return s; | |
| 871 | + } | |
| 872 | + | |
| 873 | + var env = { | |
| 874 | + type: o.type, | |
| 875 | + content: stringify(o.content, language), | |
| 876 | + tag: "span", | |
| 877 | + classes: ["token", o.type], | |
| 878 | + attributes: {}, | |
| 879 | + language: language, | |
| 880 | + }; | |
| 881 | + | |
| 882 | + var aliases = o.alias; | |
| 883 | + if (aliases) { | |
| 884 | + if (Array.isArray(aliases)) { | |
| 885 | + Array.prototype.push.apply(env.classes, aliases); | |
| 886 | + } else { | |
| 887 | + env.classes.push(aliases); | |
| 888 | + } | |
| 889 | + } | |
| 890 | + | |
| 891 | + _.hooks.run("wrap", env); | |
| 892 | + | |
| 893 | + var attributes = ""; | |
| 894 | + for (var name in env.attributes) { | |
| 895 | + attributes += | |
| 896 | + " " + | |
| 897 | + name + | |
| 898 | + '="' + | |
| 899 | + (env.attributes[name] || "").replace(/"/g, """) + | |
| 900 | + '"'; | |
| 901 | + } | |
| 902 | + | |
| 903 | + return ( | |
| 904 | + "<" + | |
| 905 | + env.tag + | |
| 906 | + ' class="' + | |
| 907 | + env.classes.join(" ") + | |
| 908 | + '"' + | |
| 909 | + attributes + | |
| 910 | + ">" + | |
| 911 | + env.content + | |
| 912 | + "</" + | |
| 913 | + env.tag + | |
| 914 | + ">" | |
| 915 | + ); | |
| 916 | + }; | |
| 917 | + | |
| 918 | + /** | |
| 919 | + * @param {RegExp} pattern | |
| 920 | + * @param {number} pos | |
| 921 | + * @param {string} text | |
| 922 | + * @param {boolean} lookbehind | |
| 923 | + * @returns {RegExpExecArray | null} | |
| 924 | + */ | |
| 925 | + function matchPattern(pattern, pos, text, lookbehind) { | |
| 926 | + pattern.lastIndex = pos; | |
| 927 | + var match = pattern.exec(text); | |
| 928 | + if (match && lookbehind && match[1]) { | |
| 929 | + // change the match to remove the text matched by the Prism lookbehind group | |
| 930 | + var lookbehindLength = match[1].length; | |
| 931 | + match.index += lookbehindLength; | |
| 932 | + match[0] = match[0].slice(lookbehindLength); | |
| 933 | + } | |
| 934 | + return match; | |
| 935 | + } | |
| 936 | + | |
| 937 | + /** | |
| 938 | + * @param {string} text | |
| 939 | + * @param {LinkedList<string | Token>} tokenList | |
| 940 | + * @param {any} grammar | |
| 941 | + * @param {LinkedListNode<string | Token>} startNode | |
| 942 | + * @param {number} startPos | |
| 943 | + * @param {RematchOptions} [rematch] | |
| 944 | + * @returns {void} | |
| 945 | + * @private | |
| 946 | + * | |
| 947 | + * @typedef RematchOptions | |
| 948 | + * @property {string} cause | |
| 949 | + * @property {number} reach | |
| 950 | + */ | |
| 951 | + function matchGrammar( | |
| 952 | + text, | |
| 953 | + tokenList, | |
| 954 | + grammar, | |
| 955 | + startNode, | |
| 956 | + startPos, | |
| 957 | + rematch, | |
| 958 | + ) { | |
| 959 | + for (var token in grammar) { | |
| 960 | + if (!grammar.hasOwnProperty(token) || !grammar[token]) { | |
| 961 | + continue; | |
| 962 | + } | |
| 963 | + | |
| 964 | + var patterns = grammar[token]; | |
| 965 | + patterns = Array.isArray(patterns) ? patterns : [patterns]; | |
| 966 | + | |
| 967 | + for (var j = 0; j < patterns.length; ++j) { | |
| 968 | + if (rematch && rematch.cause == token + "," + j) { | |
| 969 | + return; | |
| 970 | + } | |
| 971 | + | |
| 972 | + var patternObj = patterns[j]; | |
| 973 | + var inside = patternObj.inside; | |
| 974 | + var lookbehind = !!patternObj.lookbehind; | |
| 975 | + var greedy = !!patternObj.greedy; | |
| 976 | + var alias = patternObj.alias; | |
| 977 | + | |
| 978 | + if (greedy && !patternObj.pattern.global) { | |
| 979 | + // Without the global flag, lastIndex won't work | |
| 980 | + var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; | |
| 981 | + patternObj.pattern = RegExp(patternObj.pattern.source, flags + "g"); | |
| 982 | + } | |
| 983 | + | |
| 984 | + /** @type {RegExp} */ | |
| 985 | + var pattern = patternObj.pattern || patternObj; | |
| 986 | + | |
| 987 | + for ( | |
| 988 | + // iterate the token list and keep track of the current token/string position | |
| 989 | + var currentNode = startNode.next, pos = startPos; | |
| 990 | + currentNode !== tokenList.tail; | |
| 991 | + pos += currentNode.value.length, currentNode = currentNode.next | |
| 992 | + ) { | |
| 993 | + if (rematch && pos >= rematch.reach) { | |
| 994 | + break; | |
| 995 | + } | |
| 996 | + | |
| 997 | + var str = currentNode.value; | |
| 998 | + | |
| 999 | + if (tokenList.length > text.length) { | |
| 1000 | + // Something went terribly wrong, ABORT, ABORT! | |
| 1001 | + return; | |
| 1002 | + } | |
| 1003 | + | |
| 1004 | + if (str instanceof Token) { | |
| 1005 | + continue; | |
| 1006 | + } | |
| 1007 | + | |
| 1008 | + var removeCount = 1; // this is the to parameter of removeBetween | |
| 1009 | + var match; | |
| 1010 | + | |
| 1011 | + if (greedy) { | |
| 1012 | + match = matchPattern(pattern, pos, text, lookbehind); | |
| 1013 | + if (!match || match.index >= text.length) { | |
| 1014 | + break; | |
| 1015 | + } | |
| 1016 | + | |
| 1017 | + var from = match.index; | |
| 1018 | + var to = match.index + match[0].length; | |
| 1019 | + var p = pos; | |
| 1020 | + | |
| 1021 | + // find the node that contains the match | |
| 1022 | + p += currentNode.value.length; | |
| 1023 | + while (from >= p) { | |
| 1024 | + currentNode = currentNode.next; | |
| 1025 | + p += currentNode.value.length; | |
| 1026 | + } | |
| 1027 | + // adjust pos (and p) | |
| 1028 | + p -= currentNode.value.length; | |
| 1029 | + pos = p; | |
| 1030 | + | |
| 1031 | + // the current node is a Token, then the match starts inside another Token, which is invalid | |
| 1032 | + if (currentNode.value instanceof Token) { | |
| 1033 | + continue; | |
| 1034 | + } | |
| 1035 | + | |
| 1036 | + // find the last node which is affected by this match | |
| 1037 | + for ( | |
| 1038 | + var k = currentNode; | |
| 1039 | + k !== tokenList.tail && (p < to || typeof k.value === "string"); | |
| 1040 | + k = k.next | |
| 1041 | + ) { | |
| 1042 | + removeCount++; | |
| 1043 | + p += k.value.length; | |
| 1044 | + } | |
| 1045 | + removeCount--; | |
| 1046 | + | |
| 1047 | + // replace with the new match | |
| 1048 | + str = text.slice(pos, p); | |
| 1049 | + match.index -= pos; | |
| 1050 | + } else { | |
| 1051 | + match = matchPattern(pattern, 0, str, lookbehind); | |
| 1052 | + if (!match) { | |
| 1053 | + continue; | |
| 1054 | + } | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + // eslint-disable-next-line no-redeclare | |
| 1058 | + var from = match.index; | |
| 1059 | + var matchStr = match[0]; | |
| 1060 | + var before = str.slice(0, from); | |
| 1061 | + var after = str.slice(from + matchStr.length); | |
| 1062 | + | |
| 1063 | + var reach = pos + str.length; | |
| 1064 | + if (rematch && reach > rematch.reach) { | |
| 1065 | + rematch.reach = reach; | |
| 1066 | + } | |
| 1067 | + | |
| 1068 | + var removeFrom = currentNode.prev; | |
| 1069 | + | |
| 1070 | + if (before) { | |
| 1071 | + removeFrom = addAfter(tokenList, removeFrom, before); | |
| 1072 | + pos += before.length; | |
| 1073 | + } | |
| 1074 | + | |
| 1075 | + removeRange(tokenList, removeFrom, removeCount); | |
| 1076 | + | |
| 1077 | + var wrapped = new Token( | |
| 1078 | + token, | |
| 1079 | + inside ? _.tokenize(matchStr, inside) : matchStr, | |
| 1080 | + alias, | |
| 1081 | + matchStr, | |
| 1082 | + ); | |
| 1083 | + currentNode = addAfter(tokenList, removeFrom, wrapped); | |
| 1084 | + | |
| 1085 | + if (after) { | |
| 1086 | + addAfter(tokenList, currentNode, after); | |
| 1087 | + } | |
| 1088 | + | |
| 1089 | + if (removeCount > 1) { | |
| 1090 | + // at least one Token object was removed, so we have to do some rematching | |
| 1091 | + // this can only happen if the current pattern is greedy | |
| 1092 | + | |
| 1093 | + /** @type {RematchOptions} */ | |
| 1094 | + var nestedRematch = { | |
| 1095 | + cause: token + "," + j, | |
| 1096 | + reach: reach, | |
| 1097 | + }; | |
| 1098 | + matchGrammar( | |
| 1099 | + text, | |
| 1100 | + tokenList, | |
| 1101 | + grammar, | |
| 1102 | + currentNode.prev, | |
| 1103 | + pos, | |
| 1104 | + nestedRematch, | |
| 1105 | + ); | |
| 1106 | + | |
| 1107 | + // the reach might have been extended because of the rematching | |
| 1108 | + if (rematch && nestedRematch.reach > rematch.reach) { | |
| 1109 | + rematch.reach = nestedRematch.reach; | |
| 1110 | + } | |
| 1111 | + } | |
| 1112 | + } | |
| 1113 | + } | |
| 1114 | + } | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + /** | |
| 1118 | + * @typedef LinkedListNode | |
| 1119 | + * @property {T} value | |
| 1120 | + * @property {LinkedListNode<T> | null} prev The previous node. | |
| 1121 | + * @property {LinkedListNode<T> | null} next The next node. | |
| 1122 | + * @template T | |
| 1123 | + * @private | |
| 1124 | + */ | |
| 1125 | + | |
| 1126 | + /** | |
| 1127 | + * @template T | |
| 1128 | + * @private | |
| 1129 | + */ | |
| 1130 | + function LinkedList() { | |
| 1131 | + /** @type {LinkedListNode<T>} */ | |
| 1132 | + var head = { value: null, prev: null, next: null }; | |
| 1133 | + /** @type {LinkedListNode<T>} */ | |
| 1134 | + var tail = { value: null, prev: head, next: null }; | |
| 1135 | + head.next = tail; | |
| 1136 | + | |
| 1137 | + /** @type {LinkedListNode<T>} */ | |
| 1138 | + this.head = head; | |
| 1139 | + /** @type {LinkedListNode<T>} */ | |
| 1140 | + this.tail = tail; | |
| 1141 | + this.length = 0; | |
| 1142 | + } | |
| 1143 | + | |
| 1144 | + /** | |
| 1145 | + * Adds a new node with the given value to the list. | |
| 1146 | + * | |
| 1147 | + * @param {LinkedList<T>} list | |
| 1148 | + * @param {LinkedListNode<T>} node | |
| 1149 | + * @param {T} value | |
| 1150 | + * @returns {LinkedListNode<T>} The added node. | |
| 1151 | + * @template T | |
| 1152 | + */ | |
| 1153 | + function addAfter(list, node, value) { | |
| 1154 | + // assumes that node != list.tail && values.length >= 0 | |
| 1155 | + var next = node.next; | |
| 1156 | + | |
| 1157 | + var newNode = { value: value, prev: node, next: next }; | |
| 1158 | + node.next = newNode; | |
| 1159 | + next.prev = newNode; | |
| 1160 | + list.length++; | |
| 1161 | + | |
| 1162 | + return newNode; | |
| 1163 | + } | |
| 1164 | + /** | |
| 1165 | + * Removes `count` nodes after the given node. The given node will not be removed. | |
| 1166 | + * | |
| 1167 | + * @param {LinkedList<T>} list | |
| 1168 | + * @param {LinkedListNode<T>} node | |
| 1169 | + * @param {number} count | |
| 1170 | + * @template T | |
| 1171 | + */ | |
| 1172 | + function removeRange(list, node, count) { | |
| 1173 | + var next = node.next; | |
| 1174 | + for (var i = 0; i < count && next !== list.tail; i++) { | |
| 1175 | + next = next.next; | |
| 1176 | + } | |
| 1177 | + node.next = next; | |
| 1178 | + next.prev = node; | |
| 1179 | + list.length -= i; | |
| 1180 | + } | |
| 1181 | + /** | |
| 1182 | + * @param {LinkedList<T>} list | |
| 1183 | + * @returns {T[]} | |
| 1184 | + * @template T | |
| 1185 | + */ | |
| 1186 | + function toArray(list) { | |
| 1187 | + var array = []; | |
| 1188 | + var node = list.head.next; | |
| 1189 | + while (node !== list.tail) { | |
| 1190 | + array.push(node.value); | |
| 1191 | + node = node.next; | |
| 1192 | + } | |
| 1193 | + return array; | |
| 1194 | + } | |
| 1195 | + | |
| 1196 | + if (!_self.document) { | |
| 1197 | + if (!_self.addEventListener) { | |
| 1198 | + // in Node.js | |
| 1199 | + return _; | |
| 1200 | + } | |
| 1201 | + | |
| 1202 | + if (!_.disableWorkerMessageHandler) { | |
| 1203 | + // In worker | |
| 1204 | + _self.addEventListener( | |
| 1205 | + "message", | |
| 1206 | + function (evt) { | |
| 1207 | + var message = JSON.parse(evt.data); | |
| 1208 | + var lang = message.language; | |
| 1209 | + var code = message.code; | |
| 1210 | + var immediateClose = message.immediateClose; | |
| 1211 | + | |
| 1212 | + _self.postMessage(_.highlight(code, _.languages[lang], lang)); | |
| 1213 | + if (immediateClose) { | |
| 1214 | + _self.close(); | |
| 1215 | + } | |
| 1216 | + }, | |
| 1217 | + false, | |
| 1218 | + ); | |
| 1219 | + } | |
| 1220 | + | |
| 1221 | + return _; | |
| 1222 | + } | |
| 1223 | + | |
| 1224 | + // Get current script and highlight | |
| 1225 | + var script = _.util.currentScript(); | |
| 1226 | + | |
| 1227 | + if (script) { | |
| 1228 | + _.filename = script.src; | |
| 1229 | + | |
| 1230 | + if (script.hasAttribute("data-manual")) { | |
| 1231 | + _.manual = true; | |
| 1232 | + } | |
| 1233 | + } | |
| 1234 | + | |
| 1235 | + function highlightAutomaticallyCallback() { | |
| 1236 | + if (!_.manual) { | |
| 1237 | + _.highlightAll(); | |
| 1238 | + } | |
| 1239 | + } | |
| 1240 | + | |
| 1241 | + if (!_.manual) { | |
| 1242 | + // If the document state is "loading", then we'll use DOMContentLoaded. | |
| 1243 | + // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the | |
| 1244 | + // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they | |
| 1245 | + // might take longer one animation frame to execute which can create a race condition where only some plugins have | |
| 1246 | + // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. | |
| 1247 | + // See https://github.com/PrismJS/prism/issues/2102 | |
| 1248 | + var readyState = document.readyState; | |
| 1249 | + if ( | |
| 1250 | + readyState === "loading" || | |
| 1251 | + (readyState === "interactive" && script && script.defer) | |
| 1252 | + ) { | |
| 1253 | + document.addEventListener( | |
| 1254 | + "DOMContentLoaded", | |
| 1255 | + highlightAutomaticallyCallback, | |
| 1256 | + ); | |
| 1257 | + } else { | |
| 1258 | + if (window.requestAnimationFrame) { | |
| 1259 | + window.requestAnimationFrame(highlightAutomaticallyCallback); | |
| 1260 | + } else { | |
| 1261 | + window.setTimeout(highlightAutomaticallyCallback, 16); | |
| 1262 | + } | |
| 1263 | + } | |
| 1264 | + } | |
| 1265 | + | |
| 1266 | + return _; | |
| 1267 | +})(_self); | |
| 1268 | + | |
| 1269 | +if (typeof module !== "undefined" && module.exports) { | |
| 1270 | + module.exports = Prism; | |
| 1211 | 1271 | } |
| 1212 | 1272 | |
| 1213 | 1273 | // hack for components to work correctly in node.js |
| 1214 | −if (typeof global !== 'undefined') { | |
| 1215 | − global.Prism = Prism; | |
| 1274 | +if (typeof global !== "undefined") { | |
| 1275 | + global.Prism = Prism; | |
| 1216 | 1276 | } |
| 1217 | 1277 | |
| 1218 | 1278 | // some additional documentation/types |
| @@ -1263,1007 +1323,1096 @@ if (typeof global !== 'undefined') { · 44 unmodified lines | ||
| 1263 | 1323 | * @global |
| 1264 | 1324 | * @public |
| 1265 | 1325 | */ |
| 1266 | −; | |
| 1267 | 1326 | Prism.languages.markup = { |
| 1268 | − 'comment': { | |
| 1269 | − pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, | |
| 1270 | − greedy: true | |
| 1271 | − }, | |
| 1272 | − 'prolog': { | |
| 1273 | − pattern: /<\?[\s\S]+?\?>/, | |
| 1274 | − greedy: true | |
| 1275 | − }, | |
| 1276 | − 'doctype': { | |
| 1277 | − // https://www.w3.org/TR/xml/#NT-doctypedecl | |
| 1278 | − pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, | |
| 1279 | − greedy: true, | |
| 1280 | − inside: { | |
| 1281 | − 'internal-subset': { | |
| 1282 | − pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, | |
| 1283 | − lookbehind: true, | |
| 1284 | − greedy: true, | |
| 1285 | − inside: null // see below | |
| 1286 | − }, | |
| 1287 | − 'string': { | |
| 1288 | − pattern: /"[^"]*"|'[^']*'/, | |
| 1289 | − greedy: true | |
| 1290 | − }, | |
| 1291 | − 'punctuation': /^<!|>$|[[\]]/, | |
| 1292 | − 'doctype-tag': /^DOCTYPE/i, | |
| 1293 | − 'name': /[^\s<>'"]+/ | |
| 1294 | − } | |
| 1295 | − }, | |
| 1296 | − 'cdata': { | |
| 1297 | − pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, | |
| 1298 | − greedy: true | |
| 1299 | − }, | |
| 1300 | − 'tag': { | |
| 1301 | − pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, | |
| 1302 | − greedy: true, | |
| 1303 | − inside: { | |
| 1304 | − 'tag': { | |
| 1305 | − pattern: /^<\/?[^\s>\/]+/, | |
| 1306 | − inside: { | |
| 1307 | − 'punctuation': /^<\/?/, | |
| 1308 | − 'namespace': /^[^\s>\/:]+:/ | |
| 1309 | − } | |
| 1310 | − }, | |
| 1311 | − 'special-attr': [], | |
| 1312 | − 'attr-value': { | |
| 1313 | − pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, | |
| 1314 | − inside: { | |
| 1315 | − 'punctuation': [ | |
| 1316 | − { | |
| 1317 | − pattern: /^=/, | |
| 1318 | − alias: 'attr-equals' | |
| 1319 | − }, | |
| 1320 | − { | |
| 1321 | − pattern: /^(\s*)["']|["']$/, | |
| 1322 | − lookbehind: true | |
| 1323 | − } | |
| 1324 | − ] | |
| 1325 | − } | |
| 1326 | − }, | |
| 1327 | − 'punctuation': /\/?>/, | |
| 1328 | − 'attr-name': { | |
| 1329 | − pattern: /[^\s>\/]+/, | |
| 1330 | − inside: { | |
| 1331 | − 'namespace': /^[^\s>\/:]+:/ | |
| 1332 | − } | |
| 1333 | − } | |
| 1334 | − | |
| 1335 | − } | |
| 1336 | − }, | |
| 1337 | − 'entity': [ | |
| 1338 | − { | |
| 1339 | − pattern: /&[\da-z]{1,8};/i, | |
| 1340 | − alias: 'named-entity' | |
| 1341 | − }, | |
| 1342 | − /&#x?[\da-f]{1,8};/i | |
| 1343 | − ] | |
| 1327 | + comment: { | |
| 1328 | + pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, | |
| 1329 | + greedy: true, | |
| 1330 | + }, | |
| 1331 | + prolog: { | |
| 1332 | + pattern: /<\?[\s\S]+?\?>/, | |
| 1333 | + greedy: true, | |
| 1334 | + }, | |
| 1335 | + doctype: { | |
| 1336 | + // https://www.w3.org/TR/xml/#NT-doctypedecl | |
| 1337 | + pattern: | |
| 1338 | + /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, | |
| 1339 | + greedy: true, | |
| 1340 | + inside: { | |
| 1341 | + "internal-subset": { | |
| 1342 | + pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, | |
| 1343 | + lookbehind: true, | |
| 1344 | + greedy: true, | |
| 1345 | + inside: null, // see below | |
| 1346 | + }, | |
| 1347 | + string: { | |
| 1348 | + pattern: /"[^"]*"|'[^']*'/, | |
| 1349 | + greedy: true, | |
| 1350 | + }, | |
| 1351 | + punctuation: /^<!|>$|[[\]]/, | |
| 1352 | + "doctype-tag": /^DOCTYPE/i, | |
| 1353 | + name: /[^\s<>'"]+/, | |
| 1354 | + }, | |
| 1355 | + }, | |
| 1356 | + cdata: { | |
| 1357 | + pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, | |
| 1358 | + greedy: true, | |
| 1359 | + }, | |
| 1360 | + tag: { | |
| 1361 | + pattern: | |
| 1362 | + /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, | |
| 1363 | + greedy: true, | |
| 1364 | + inside: { | |
| 1365 | + tag: { | |
| 1366 | + pattern: /^<\/?[^\s>\/]+/, | |
| 1367 | + inside: { | |
| 1368 | + punctuation: /^<\/?/, | |
| 1369 | + namespace: /^[^\s>\/:]+:/, | |
| 1370 | + }, | |
| 1371 | + }, | |
| 1372 | + "special-attr": [], | |
| 1373 | + "attr-value": { | |
| 1374 | + pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, | |
| 1375 | + inside: { | |
| 1376 | + punctuation: [ | |
| 1377 | + { | |
| 1378 | + pattern: /^=/, | |
| 1379 | + alias: "attr-equals", | |
| 1380 | + }, | |
| 1381 | + { | |
| 1382 | + pattern: /^(\s*)["']|["']$/, | |
| 1383 | + lookbehind: true, | |
| 1384 | + }, | |
| 1385 | + ], | |
| 1386 | + }, | |
| 1387 | + }, | |
| 1388 | + punctuation: /\/?>/, | |
| 1389 | + "attr-name": { | |
| 1390 | + pattern: /[^\s>\/]+/, | |
| 1391 | + inside: { | |
| 1392 | + namespace: /^[^\s>\/:]+:/, | |
| 1393 | + }, | |
| 1394 | + }, | |
| 1395 | + }, | |
| 1396 | + }, | |
| 1397 | + entity: [ | |
| 1398 | + { | |
| 1399 | + pattern: /&[\da-z]{1,8};/i, | |
| 1400 | + alias: "named-entity", | |
| 1401 | + }, | |
| 1402 | + /&#x?[\da-f]{1,8};/i, | |
| 1403 | + ], | |
| 1344 | 1404 | }; |
| 1345 | 1405 | |
| 1346 | −Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] = | |
| 1347 | − Prism.languages.markup['entity']; | |
| 1348 | −Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup; | |
| 1406 | +Prism.languages.markup["tag"].inside["attr-value"].inside["entity"] = | |
| 1407 | + Prism.languages.markup["entity"]; | |
| 1408 | +Prism.languages.markup["doctype"].inside["internal-subset"].inside = | |
| 1409 | + Prism.languages.markup; | |
| 1349 | 1410 | |
| 1350 | 1411 | // Plugin to make entity title show the real entity, idea by Roman Komarov |
| 1351 | −Prism.hooks.add('wrap', function (env) { | |
| 1352 | − | |
| 1353 | − if (env.type === 'entity') { | |
| 1354 | − env.attributes['title'] = env.content.replace(/&/, '&'); | |
| 1355 | − } | |
| 1412 | +Prism.hooks.add("wrap", function (env) { | |
| 1413 | + if (env.type === "entity") { | |
| 1414 | + env.attributes["title"] = env.content.replace(/&/, "&"); | |
| 1415 | + } | |
| 1356 | 1416 | }); |
| 1357 | 1417 | |
| 1358 | −Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { | |
| 1359 | − /** | |
| 1360 | − * Adds an inlined language to markup. | |
| 1361 | − * | |
| 1362 | − * An example of an inlined language is CSS with `<style>` tags. | |
| 1363 | − * | |
| 1364 | − * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as | |
| 1365 | − * case insensitive. | |
| 1366 | − * @param {string} lang The language key. | |
| 1367 | − * @example | |
| 1368 | − * addInlined('style', 'css'); | |
| 1369 | − */ | |
| 1370 | − value: function addInlined(tagName, lang) { | |
| 1371 | − var includedCdataInside = {}; | |
| 1372 | − includedCdataInside['language-' + lang] = { | |
| 1373 | − pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, | |
| 1374 | − lookbehind: true, | |
| 1375 | − inside: Prism.languages[lang] | |
| 1376 | − }; | |
| 1377 | − includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i; | |
| 1378 | − | |
| 1379 | − var inside = { | |
| 1380 | − 'included-cdata': { | |
| 1381 | − pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, | |
| 1382 | − inside: includedCdataInside | |
| 1383 | − } | |
| 1384 | − }; | |
| 1385 | − inside['language-' + lang] = { | |
| 1386 | − pattern: /[\s\S]+/, | |
| 1387 | − inside: Prism.languages[lang] | |
| 1388 | − }; | |
| 1389 | − | |
| 1390 | − var def = {}; | |
| 1391 | − def[tagName] = { | |
| 1392 | − pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'), | |
| 1393 | − lookbehind: true, | |
| 1394 | − greedy: true, | |
| 1395 | − inside: inside | |
| 1396 | − }; | |
| 1397 | − | |
| 1398 | − Prism.languages.insertBefore('markup', 'cdata', def); | |
| 1399 | − } | |
| 1418 | +Object.defineProperty(Prism.languages.markup.tag, "addInlined", { | |
| 1419 | + /** | |
| 1420 | + * Adds an inlined language to markup. | |
| 1421 | + * | |
| 1422 | + * An example of an inlined language is CSS with `<style>` tags. | |
| 1423 | + * | |
| 1424 | + * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as | |
| 1425 | + * case insensitive. | |
| 1426 | + * @param {string} lang The language key. | |
| 1427 | + * @example | |
| 1428 | + * addInlined('style', 'css'); | |
| 1429 | + */ | |
| 1430 | + value: function addInlined(tagName, lang) { | |
| 1431 | + var includedCdataInside = {}; | |
| 1432 | + includedCdataInside["language-" + lang] = { | |
| 1433 | + pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, | |
| 1434 | + lookbehind: true, | |
| 1435 | + inside: Prism.languages[lang], | |
| 1436 | + }; | |
| 1437 | + includedCdataInside["cdata"] = /^<!\[CDATA\[|\]\]>$/i; | |
| 1438 | + | |
| 1439 | + var inside = { | |
| 1440 | + "included-cdata": { | |
| 1441 | + pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, | |
| 1442 | + inside: includedCdataInside, | |
| 1443 | + }, | |
| 1444 | + }; | |
| 1445 | + inside["language-" + lang] = { | |
| 1446 | + pattern: /[\s\S]+/, | |
| 1447 | + inside: Prism.languages[lang], | |
| 1448 | + }; | |
| 1449 | + | |
| 1450 | + var def = {}; | |
| 1451 | + def[tagName] = { | |
| 1452 | + pattern: RegExp( | |
| 1453 | + /(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace( | |
| 1454 | + /__/g, | |
| 1455 | + function () { | |
| 1456 | + return tagName; | |
| 1457 | + }, | |
| 1458 | + ), | |
| 1459 | + "i", | |
| 1460 | + ), | |
| 1461 | + lookbehind: true, | |
| 1462 | + greedy: true, | |
| 1463 | + inside: inside, | |
| 1464 | + }; | |
| 1465 | + | |
| 1466 | + Prism.languages.insertBefore("markup", "cdata", def); | |
| 1467 | + }, | |
| 1400 | 1468 | }); |
| 1401 | −Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', { | |
| 1402 | − /** | |
| 1403 | − * Adds an pattern to highlight languages embedded in HTML attributes. | |
| 1404 | − * | |
| 1405 | − * An example of an inlined language is CSS with `style` attributes. | |
| 1406 | − * | |
| 1407 | − * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as | |
| 1408 | − * case insensitive. | |
| 1409 | − * @param {string} lang The language key. | |
| 1410 | − * @example | |
| 1411 | − * addAttribute('style', 'css'); | |
| 1412 | − */ | |
| 1413 | − value: function (attrName, lang) { | |
| 1414 | − Prism.languages.markup.tag.inside['special-attr'].push({ | |
| 1415 | − pattern: RegExp( | |
| 1416 | − /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, | |
| 1417 | − 'i' | |
| 1418 | − ), | |
| 1419 | − lookbehind: true, | |
| 1420 | − inside: { | |
| 1421 | − 'attr-name': /^[^\s=]+/, | |
| 1422 | − 'attr-value': { | |
| 1423 | − pattern: /=[\s\S]+/, | |
| 1424 | − inside: { | |
| 1425 | − 'value': { | |
| 1426 | − pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, | |
| 1427 | − lookbehind: true, | |
| 1428 | − alias: [lang, 'language-' + lang], | |
| 1429 | − inside: Prism.languages[lang] | |
| 1430 | − }, | |
| 1431 | − 'punctuation': [ | |
| 1432 | − { | |
| 1433 | − pattern: /^=/, | |
| 1434 | − alias: 'attr-equals' | |
| 1435 | − }, | |
| 1436 | − /"|'/ | |
| 1437 | − ] | |
| 1438 | − } | |
| 1439 | − } | |
| 1440 | − } | |
| 1441 | − }); | |
| 1442 | − } | |
| 1469 | +Object.defineProperty(Prism.languages.markup.tag, "addAttribute", { | |
| 1470 | + /** | |
| 1471 | + * Adds an pattern to highlight languages embedded in HTML attributes. | |
| 1472 | + * | |
| 1473 | + * An example of an inlined language is CSS with `style` attributes. | |
| 1474 | + * | |
| 1475 | + * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as | |
| 1476 | + * case insensitive. | |
| 1477 | + * @param {string} lang The language key. | |
| 1478 | + * @example | |
| 1479 | + * addAttribute('style', 'css'); | |
| 1480 | + */ | |
| 1481 | + value: function (attrName, lang) { | |
| 1482 | + Prism.languages.markup.tag.inside["special-attr"].push({ | |
| 1483 | + pattern: RegExp( | |
| 1484 | + /(^|["'\s])/.source + | |
| 1485 | + "(?:" + | |
| 1486 | + attrName + | |
| 1487 | + ")" + | |
| 1488 | + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, | |
| 1489 | + "i", | |
| 1490 | + ), | |
| 1491 | + lookbehind: true, | |
| 1492 | + inside: { | |
| 1493 | + "attr-name": /^[^\s=]+/, | |
| 1494 | + "attr-value": { | |
| 1495 | + pattern: /=[\s\S]+/, | |
| 1496 | + inside: { | |
| 1497 | + value: { | |
| 1498 | + pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, | |
| 1499 | + lookbehind: true, | |
| 1500 | + alias: [lang, "language-" + lang], | |
| 1501 | + inside: Prism.languages[lang], | |
| 1502 | + }, | |
| 1503 | + punctuation: [ | |
| 1504 | + { | |
| 1505 | + pattern: /^=/, | |
| 1506 | + alias: "attr-equals", | |
| 1507 | + }, | |
| 1508 | + /"|'/, | |
| 1509 | + ], | |
| 1510 | + }, | |
| 1511 | + }, | |
| 1512 | + }, | |
| 1513 | + }); | |
| 1514 | + }, | |
| 1443 | 1515 | }); |
| 1444 | 1516 | |
| 1445 | 1517 | Prism.languages.html = Prism.languages.markup; |
| 1446 | 1518 | Prism.languages.mathml = Prism.languages.markup; |
| 1447 | 1519 | Prism.languages.svg = Prism.languages.markup; |
| 1448 | 1520 | |
| 1449 | −Prism.languages.xml = Prism.languages.extend('markup', {}); | |
| 1521 | +Prism.languages.xml = Prism.languages.extend("markup", {}); | |
| 1450 | 1522 | Prism.languages.ssml = Prism.languages.xml; |
| 1451 | 1523 | Prism.languages.atom = Prism.languages.xml; |
| 1452 | 1524 | Prism.languages.rss = Prism.languages.xml; |
| 1453 | 1525 | |
| 1454 | 1526 | (function (Prism) { |
| 1455 | − | |
| 1456 | − var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; | |
| 1457 | − | |
| 1458 | − Prism.languages.css = { | |
| 1459 | − 'comment': /\/\*[\s\S]*?\*\//, | |
| 1460 | − 'atrule': { | |
| 1461 | − pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source), | |
| 1462 | − inside: { | |
| 1463 | − 'rule': /^@[\w-]+/, | |
| 1464 | − 'selector-function-argument': { | |
| 1465 | − pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, | |
| 1466 | − lookbehind: true, | |
| 1467 | − alias: 'selector' | |
| 1468 | − }, | |
| 1469 | − 'keyword': { | |
| 1470 | − pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, | |
| 1471 | − lookbehind: true | |
| 1472 | − } | |
| 1473 | − // See rest below | |
| 1474 | − } | |
| 1475 | − }, | |
| 1476 | − 'url': { | |
| 1477 | − // https://drafts.csswg.org/css-values-3/#urls | |
| 1478 | − pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'), | |
| 1479 | − greedy: true, | |
| 1480 | − inside: { | |
| 1481 | − 'function': /^url/i, | |
| 1482 | − 'punctuation': /^\(|\)$/, | |
| 1483 | − 'string': { | |
| 1484 | − pattern: RegExp('^' + string.source + '$'), | |
| 1485 | − alias: 'url' | |
| 1486 | − } | |
| 1487 | − } | |
| 1488 | − }, | |
| 1489 | − 'selector': { | |
| 1490 | − pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'), | |
| 1491 | − lookbehind: true | |
| 1492 | − }, | |
| 1493 | − 'string': { | |
| 1494 | − pattern: string, | |
| 1495 | − greedy: true | |
| 1496 | − }, | |
| 1497 | − 'property': { | |
| 1498 | − pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, | |
| 1499 | − lookbehind: true | |
| 1500 | − }, | |
| 1501 | − 'important': /!important\b/i, | |
| 1502 | − 'function': { | |
| 1503 | − pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, | |
| 1504 | − lookbehind: true | |
| 1505 | − }, | |
| 1506 | − 'punctuation': /[(){};:,]/ | |
| 1507 | − }; | |
| 1508 | − | |
| 1509 | − Prism.languages.css['atrule'].inside.rest = Prism.languages.css; | |
| 1510 | − | |
| 1511 | − var markup = Prism.languages.markup; | |
| 1512 | − if (markup) { | |
| 1513 | − markup.tag.addInlined('style', 'css'); | |
| 1514 | − markup.tag.addAttribute('style', 'css'); | |
| 1515 | − } | |
| 1516 | − | |
| 1517 | −}(Prism)); | |
| 1527 | + var string = | |
| 1528 | + /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; | |
| 1529 | + | |
| 1530 | + Prism.languages.css = { | |
| 1531 | + comment: /\/\*[\s\S]*?\*\//, | |
| 1532 | + atrule: { | |
| 1533 | + pattern: RegExp( | |
| 1534 | + "@[\\w-](?:" + | |
| 1535 | + /[^;{\s"']|\s+(?!\s)/.source + | |
| 1536 | + "|" + | |
| 1537 | + string.source + | |
| 1538 | + ")*?" + | |
| 1539 | + /(?:;|(?=\s*\{))/.source, | |
| 1540 | + ), | |
| 1541 | + inside: { | |
| 1542 | + rule: /^@[\w-]+/, | |
| 1543 | + "selector-function-argument": { | |
| 1544 | + pattern: | |
| 1545 | + /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, | |
| 1546 | + lookbehind: true, | |
| 1547 | + alias: "selector", | |
| 1548 | + }, | |
| 1549 | + keyword: { | |
| 1550 | + pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, | |
| 1551 | + lookbehind: true, | |
| 1552 | + }, | |
| 1553 | + // See rest below | |
| 1554 | + }, | |
| 1555 | + }, | |
| 1556 | + url: { | |
| 1557 | + // https://drafts.csswg.org/css-values-3/#urls | |
| 1558 | + pattern: RegExp( | |
| 1559 | + "\\burl\\((?:" + | |
| 1560 | + string.source + | |
| 1561 | + "|" + | |
| 1562 | + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + | |
| 1563 | + ")\\)", | |
| 1564 | + "i", | |
| 1565 | + ), | |
| 1566 | + greedy: true, | |
| 1567 | + inside: { | |
| 1568 | + function: /^url/i, | |
| 1569 | + punctuation: /^\(|\)$/, | |
| 1570 | + string: { | |
| 1571 | + pattern: RegExp("^" + string.source + "$"), | |
| 1572 | + alias: "url", | |
| 1573 | + }, | |
| 1574 | + }, | |
| 1575 | + }, | |
| 1576 | + selector: { | |
| 1577 | + pattern: RegExp( | |
| 1578 | + "(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|" + | |
| 1579 | + string.source + | |
| 1580 | + ")*(?=\\s*\\{)", | |
| 1581 | + ), | |
| 1582 | + lookbehind: true, | |
| 1583 | + }, | |
| 1584 | + string: { | |
| 1585 | + pattern: string, | |
| 1586 | + greedy: true, | |
| 1587 | + }, | |
| 1588 | + property: { | |
| 1589 | + pattern: | |
| 1590 | + /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, | |
| 1591 | + lookbehind: true, | |
| 1592 | + }, | |
| 1593 | + important: /!important\b/i, | |
| 1594 | + function: { | |
| 1595 | + pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, | |
| 1596 | + lookbehind: true, | |
| 1597 | + }, | |
| 1598 | + punctuation: /[(){};:,]/, | |
| 1599 | + }; | |
| 1600 | + | |
| 1601 | + Prism.languages.css["atrule"].inside.rest = Prism.languages.css; | |
| 1602 | + | |
| 1603 | + var markup = Prism.languages.markup; | |
| 1604 | + if (markup) { | |
| 1605 | + markup.tag.addInlined("style", "css"); | |
| 1606 | + markup.tag.addAttribute("style", "css"); | |
| 1607 | + } | |
| 1608 | +})(Prism); | |
| 1518 | 1609 | |
| 1519 | 1610 | Prism.languages.clike = { |
| 1520 | − 'comment': [ | |
| 1521 | − { | |
| 1522 | − pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, | |
| 1523 | − lookbehind: true, | |
| 1524 | − greedy: true | |
| 1525 | − }, | |
| 1526 | − { | |
| 1527 | − pattern: /(^|[^\\:])\/\/.*/, | |
| 1528 | − lookbehind: true, | |
| 1529 | − greedy: true | |
| 1530 | − } | |
| 1531 | − ], | |
| 1532 | − 'string': { | |
| 1533 | − pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, | |
| 1534 | − greedy: true | |
| 1535 | − }, | |
| 1536 | − 'class-name': { | |
| 1537 | − pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, | |
| 1538 | − lookbehind: true, | |
| 1539 | − inside: { | |
| 1540 | − 'punctuation': /[.\\]/ | |
| 1541 | − } | |
| 1542 | − }, | |
| 1543 | − 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, | |
| 1544 | − 'boolean': /\b(?:false|true)\b/, | |
| 1545 | − 'function': /\b\w+(?=\()/, | |
| 1546 | − 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, | |
| 1547 | − 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, | |
| 1548 | − 'punctuation': /[{}[\];(),.:]/ | |
| 1611 | + comment: [ | |
| 1612 | + { | |
| 1613 | + pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, | |
| 1614 | + lookbehind: true, | |
| 1615 | + greedy: true, | |
| 1616 | + }, | |
| 1617 | + { | |
| 1618 | + pattern: /(^|[^\\:])\/\/.*/, | |
| 1619 | + lookbehind: true, | |
| 1620 | + greedy: true, | |
| 1621 | + }, | |
| 1622 | + ], | |
| 1623 | + string: { | |
| 1624 | + pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, | |
| 1625 | + greedy: true, | |
| 1626 | + }, | |
| 1627 | + "class-name": { | |
| 1628 | + pattern: | |
| 1629 | + /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, | |
| 1630 | + lookbehind: true, | |
| 1631 | + inside: { | |
| 1632 | + punctuation: /[.\\]/, | |
| 1633 | + }, | |
| 1634 | + }, | |
| 1635 | + keyword: | |
| 1636 | + /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, | |
| 1637 | + boolean: /\b(?:false|true)\b/, | |
| 1638 | + function: /\b\w+(?=\()/, | |
| 1639 | + number: /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, | |
| 1640 | + operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, | |
| 1641 | + punctuation: /[{}[\];(),.:]/, | |
| 1549 | 1642 | }; |
| 1550 | 1643 | |
| 1551 | −Prism.languages.javascript = Prism.languages.extend('clike', { | |
| 1552 | − 'class-name': [ | |
| 1553 | − Prism.languages.clike['class-name'], | |
| 1554 | − { | |
| 1555 | − pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, | |
| 1556 | − lookbehind: true | |
| 1557 | − } | |
| 1558 | − ], | |
| 1559 | − 'keyword': [ | |
| 1560 | − { | |
| 1561 | − pattern: /((?:^|\})\s*)catch\b/, | |
| 1562 | − lookbehind: true | |
| 1563 | − }, | |
| 1564 | − { | |
| 1565 | − pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, | |
| 1566 | − lookbehind: true | |
| 1567 | − }, | |
| 1568 | − ], | |
| 1569 | − // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) | |
| 1570 | − 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, | |
| 1571 | − 'number': { | |
| 1572 | − pattern: RegExp( | |
| 1573 | − /(^|[^\w$])/.source + | |
| 1574 | − '(?:' + | |
| 1575 | − ( | |
| 1576 | − // constant | |
| 1577 | − /NaN|Infinity/.source + | |
| 1578 | − '|' + | |
| 1579 | − // binary integer | |
| 1580 | − /0[bB][01]+(?:_[01]+)*n?/.source + | |
| 1581 | − '|' + | |
| 1582 | − // octal integer | |
| 1583 | − /0[oO][0-7]+(?:_[0-7]+)*n?/.source + | |
| 1584 | − '|' + | |
| 1585 | − // hexadecimal integer | |
| 1586 | − /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + | |
| 1587 | − '|' + | |
| 1588 | − // decimal bigint | |
| 1589 | − /\d+(?:_\d+)*n/.source + | |
| 1590 | − '|' + | |
| 1591 | − // decimal number (integer or float) but no bigint | |
| 1592 | − /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source | |
| 1593 | − ) + | |
| 1594 | − ')' + | |
| 1595 | − /(?![\w$])/.source | |
| 1596 | − ), | |
| 1597 | − lookbehind: true | |
| 1598 | − }, | |
| 1599 | − 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ | |
| 1644 | +Prism.languages.javascript = Prism.languages.extend("clike", { | |
| 1645 | + "class-name": [ | |
| 1646 | + Prism.languages.clike["class-name"], | |
| 1647 | + { | |
| 1648 | + pattern: | |
| 1649 | + /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, | |
| 1650 | + lookbehind: true, | |
| 1651 | + }, | |
| 1652 | + ], | |
| 1653 | + keyword: [ | |
| 1654 | + { | |
| 1655 | + pattern: /((?:^|\})\s*)catch\b/, | |
| 1656 | + lookbehind: true, | |
| 1657 | + }, | |
| 1658 | + { | |
| 1659 | + pattern: | |
| 1660 | + /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, | |
| 1661 | + lookbehind: true, | |
| 1662 | + }, | |
| 1663 | + ], | |
| 1664 | + // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) | |
| 1665 | + function: | |
| 1666 | + /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, | |
| 1667 | + number: { | |
| 1668 | + pattern: RegExp( | |
| 1669 | + /(^|[^\w$])/.source + | |
| 1670 | + "(?:" + | |
| 1671 | + // constant | |
| 1672 | + (/NaN|Infinity/.source + | |
| 1673 | + "|" + | |
| 1674 | + // binary integer | |
| 1675 | + /0[bB][01]+(?:_[01]+)*n?/.source + | |
| 1676 | + "|" + | |
| 1677 | + // octal integer | |
| 1678 | + /0[oO][0-7]+(?:_[0-7]+)*n?/.source + | |
| 1679 | + "|" + | |
| 1680 | + // hexadecimal integer | |
| 1681 | + /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + | |
| 1682 | + "|" + | |
| 1683 | + // decimal bigint | |
| 1684 | + /\d+(?:_\d+)*n/.source + | |
| 1685 | + "|" + | |
| 1686 | + // decimal number (integer or float) but no bigint | |
| 1687 | + /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/ | |
| 1688 | + .source) + | |
| 1689 | + ")" + | |
| 1690 | + /(?![\w$])/.source, | |
| 1691 | + ), | |
| 1692 | + lookbehind: true, | |
| 1693 | + }, | |
| 1694 | + operator: | |
| 1695 | + /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/, | |
| 1600 | 1696 | }); |
| 1601 | 1697 | |
| 1602 | −Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; | |
| 1603 | − | |
| 1604 | −Prism.languages.insertBefore('javascript', 'keyword', { | |
| 1605 | − 'regex': { | |
| 1606 | − pattern: RegExp( | |
| 1607 | − // lookbehind | |
| 1608 | − // eslint-disable-next-line regexp/no-dupe-characters-character-class | |
| 1609 | − /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + | |
| 1610 | − // Regex pattern: | |
| 1611 | − // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character | |
| 1612 | − // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible | |
| 1613 | − // with the only syntax, so we have to define 2 different regex patterns. | |
| 1614 | − /\//.source + | |
| 1615 | − '(?:' + | |
| 1616 | − /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + | |
| 1617 | − '|' + | |
| 1618 | − // `v` flag syntax. This supports 3 levels of nested character classes. | |
| 1619 | − /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + | |
| 1620 | − ')' + | |
| 1621 | − // lookahead | |
| 1622 | − /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source | |
| 1623 | − ), | |
| 1624 | − lookbehind: true, | |
| 1625 | − greedy: true, | |
| 1626 | − inside: { | |
| 1627 | − 'regex-source': { | |
| 1628 | − pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, | |
| 1629 | − lookbehind: true, | |
| 1630 | − alias: 'language-regex', | |
| 1631 | − inside: Prism.languages.regex | |
| 1632 | − }, | |
| 1633 | − 'regex-delimiter': /^\/|\/$/, | |
| 1634 | − 'regex-flags': /^[a-z]+$/, | |
| 1635 | − } | |
| 1636 | − }, | |
| 1637 | − // This must be declared before keyword because we use "function" inside the look-forward | |
| 1638 | − 'function-variable': { | |
| 1639 | − pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, | |
| 1640 | − alias: 'function' | |
| 1641 | − }, | |
| 1642 | − 'parameter': [ | |
| 1643 | − { | |
| 1644 | − pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, | |
| 1645 | − lookbehind: true, | |
| 1646 | − inside: Prism.languages.javascript | |
| 1647 | − }, | |
| 1648 | − { | |
| 1649 | − pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, | |
| 1650 | − lookbehind: true, | |
| 1651 | − inside: Prism.languages.javascript | |
| 1652 | − }, | |
| 1653 | − { | |
| 1654 | − pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, | |
| 1655 | − lookbehind: true, | |
| 1656 | − inside: Prism.languages.javascript | |
| 1657 | − }, | |
| 1658 | − { | |
| 1659 | − pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, | |
| 1660 | − lookbehind: true, | |
| 1661 | − inside: Prism.languages.javascript | |
| 1662 | − } | |
| 1663 | − ], | |
| 1664 | − 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/ | |
| 1698 | +Prism.languages.javascript["class-name"][0].pattern = | |
| 1699 | + /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; | |
| 1700 | + | |
| 1701 | +Prism.languages.insertBefore("javascript", "keyword", { | |
| 1702 | + regex: { | |
| 1703 | + pattern: RegExp( | |
| 1704 | + // lookbehind | |
| 1705 | + // eslint-disable-next-line regexp/no-dupe-characters-character-class | |
| 1706 | + /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + | |
| 1707 | + // Regex pattern: | |
| 1708 | + // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character | |
| 1709 | + // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible | |
| 1710 | + // with the only syntax, so we have to define 2 different regex patterns. | |
| 1711 | + /\//.source + | |
| 1712 | + "(?:" + | |
| 1713 | + /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/ | |
| 1714 | + .source + | |
| 1715 | + "|" + | |
| 1716 | + // `v` flag syntax. This supports 3 levels of nested character classes. | |
| 1717 | + /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/ | |
| 1718 | + .source + | |
| 1719 | + ")" + | |
| 1720 | + // lookahead | |
| 1721 | + /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/ | |
| 1722 | + .source, | |
| 1723 | + ), | |
| 1724 | + lookbehind: true, | |
| 1725 | + greedy: true, | |
| 1726 | + inside: { | |
| 1727 | + "regex-source": { | |
| 1728 | + pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, | |
| 1729 | + lookbehind: true, | |
| 1730 | + alias: "language-regex", | |
| 1731 | + inside: Prism.languages.regex, | |
| 1732 | + }, | |
| 1733 | + "regex-delimiter": /^\/|\/$/, | |
| 1734 | + "regex-flags": /^[a-z]+$/, | |
| 1735 | + }, | |
| 1736 | + }, | |
| 1737 | + // This must be declared before keyword because we use "function" inside the look-forward | |
| 1738 | + "function-variable": { | |
| 1739 | + pattern: | |
| 1740 | + /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, | |
| 1741 | + alias: "function", | |
| 1742 | + }, | |
| 1743 | + parameter: [ | |
| 1744 | + { | |
| 1745 | + pattern: | |
| 1746 | + /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, | |
| 1747 | + lookbehind: true, | |
| 1748 | + inside: Prism.languages.javascript, | |
| 1749 | + }, | |
| 1750 | + { | |
| 1751 | + pattern: | |
| 1752 | + /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, | |
| 1753 | + lookbehind: true, | |
| 1754 | + inside: Prism.languages.javascript, | |
| 1755 | + }, | |
| 1756 | + { | |
| 1757 | + pattern: | |
| 1758 | + /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, | |
| 1759 | + lookbehind: true, | |
| 1760 | + inside: Prism.languages.javascript, | |
| 1761 | + }, | |
| 1762 | + { | |
| 1763 | + pattern: | |
| 1764 | + /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, | |
| 1765 | + lookbehind: true, | |
| 1766 | + inside: Prism.languages.javascript, | |
| 1767 | + }, | |
| 1768 | + ], | |
| 1769 | + constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/, | |
| 1665 | 1770 | }); |
| 1666 | 1771 | |
| 1667 | −Prism.languages.insertBefore('javascript', 'string', { | |
| 1668 | − 'hashbang': { | |
| 1669 | − pattern: /^#!.*/, | |
| 1670 | − greedy: true, | |
| 1671 | − alias: 'comment' | |
| 1672 | − }, | |
| 1673 | − 'template-string': { | |
| 1674 | − pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, | |
| 1675 | − greedy: true, | |
| 1676 | − inside: { | |
| 1677 | − 'template-punctuation': { | |
| 1678 | − pattern: /^`|`$/, | |
| 1679 | − alias: 'string' | |
| 1680 | − }, | |
| 1681 | − 'interpolation': { | |
| 1682 | − pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, | |
| 1683 | − lookbehind: true, | |
| 1684 | − inside: { | |
| 1685 | − 'interpolation-punctuation': { | |
| 1686 | − pattern: /^\$\{|\}$/, | |
| 1687 | − alias: 'punctuation' | |
| 1688 | − }, | |
| 1689 | − rest: Prism.languages.javascript | |
| 1690 | − } | |
| 1691 | − }, | |
| 1692 | − 'string': /[\s\S]+/ | |
| 1693 | − } | |
| 1694 | − }, | |
| 1695 | − 'string-property': { | |
| 1696 | − pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, | |
| 1697 | − lookbehind: true, | |
| 1698 | − greedy: true, | |
| 1699 | − alias: 'property' | |
| 1700 | − } | |
| 1772 | +Prism.languages.insertBefore("javascript", "string", { | |
| 1773 | + hashbang: { | |
| 1774 | + pattern: /^#!.*/, | |
| 1775 | + greedy: true, | |
| 1776 | + alias: "comment", | |
| 1777 | + }, | |
| 1778 | + "template-string": { | |
| 1779 | + pattern: | |
| 1780 | + /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, | |
| 1781 | + greedy: true, | |
| 1782 | + inside: { | |
| 1783 | + "template-punctuation": { | |
| 1784 | + pattern: /^`|`$/, | |
| 1785 | + alias: "string", | |
| 1786 | + }, | |
| 1787 | + interpolation: { | |
| 1788 | + pattern: | |
| 1789 | + /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, | |
| 1790 | + lookbehind: true, | |
| 1791 | + inside: { | |
| 1792 | + "interpolation-punctuation": { | |
| 1793 | + pattern: /^\$\{|\}$/, | |
| 1794 | + alias: "punctuation", | |
| 1795 | + }, | |
| 1796 | + rest: Prism.languages.javascript, | |
| 1797 | + }, | |
| 1798 | + }, | |
| 1799 | + string: /[\s\S]+/, | |
| 1800 | + }, | |
| 1801 | + }, | |
| 1802 | + "string-property": { | |
| 1803 | + pattern: | |
| 1804 | + /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, | |
| 1805 | + lookbehind: true, | |
| 1806 | + greedy: true, | |
| 1807 | + alias: "property", | |
| 1808 | + }, | |
| 1701 | 1809 | }); |
| 1702 | 1810 | |
| 1703 | −Prism.languages.insertBefore('javascript', 'operator', { | |
| 1704 | − 'literal-property': { | |
| 1705 | − pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, | |
| 1706 | − lookbehind: true, | |
| 1707 | − alias: 'property' | |
| 1708 | − }, | |
| 1811 | +Prism.languages.insertBefore("javascript", "operator", { | |
| 1812 | + "literal-property": { | |
| 1813 | + pattern: | |
| 1814 | + /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, | |
| 1815 | + lookbehind: true, | |
| 1816 | + alias: "property", | |
| 1817 | + }, | |
| 1709 | 1818 | }); |
| 1710 | 1819 | |
| 1711 | 1820 | if (Prism.languages.markup) { |
| 1712 | − Prism.languages.markup.tag.addInlined('script', 'javascript'); | |
| 1713 | − | |
| 1714 | − // add attribute support for all DOM events. | |
| 1715 | − // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events | |
| 1716 | − Prism.languages.markup.tag.addAttribute( | |
| 1717 | − /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, | |
| 1718 | − 'javascript' | |
| 1719 | − ); | |
| 1821 | + Prism.languages.markup.tag.addInlined("script", "javascript"); | |
| 1822 | + | |
| 1823 | + // add attribute support for all DOM events. | |
| 1824 | + // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events | |
| 1825 | + Prism.languages.markup.tag.addAttribute( | |
| 1826 | + /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/ | |
| 1827 | + .source, | |
| 1828 | + "javascript", | |
| 1829 | + ); | |
| 1720 | 1830 | } |
| 1721 | 1831 | |
| 1722 | 1832 | Prism.languages.js = Prism.languages.javascript; |
| 1723 | 1833 | |
| 1724 | 1834 | (function (Prism) { |
| 1725 | − // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|' | |
| 1726 | − // + LC_ALL, RANDOM, REPLY, SECONDS. | |
| 1727 | − // + make sure PS1..4 are here as they are not always set, | |
| 1728 | − // - some useless things. | |
| 1729 | − var envVars = '\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b'; | |
| 1730 | − | |
| 1731 | − var commandAfterHeredoc = { | |
| 1732 | − pattern: /(^(["']?)\w+\2)[ \t]+\S.*/, | |
| 1733 | − lookbehind: true, | |
| 1734 | − alias: 'punctuation', // this looks reasonably well in all themes | |
| 1735 | − inside: null // see below | |
| 1736 | − }; | |
| 1737 | − | |
| 1738 | − var insideString = { | |
| 1739 | − 'bash': commandAfterHeredoc, | |
| 1740 | − 'environment': { | |
| 1741 | − pattern: RegExp('\\$' + envVars), | |
| 1742 | − alias: 'constant' | |
| 1743 | − }, | |
| 1744 | − 'variable': [ | |
| 1745 | − // [0]: Arithmetic Environment | |
| 1746 | − { | |
| 1747 | − pattern: /\$?\(\([\s\S]+?\)\)/, | |
| 1748 | − greedy: true, | |
| 1749 | − inside: { | |
| 1750 | − // If there is a $ sign at the beginning highlight $(( and )) as variable | |
| 1751 | − 'variable': [ | |
| 1752 | − { | |
| 1753 | − pattern: /(^\$\(\([\s\S]+)\)\)/, | |
| 1754 | − lookbehind: true | |
| 1755 | − }, | |
| 1756 | − /^\$\(\(/ | |
| 1757 | − ], | |
| 1758 | − 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/, | |
| 1759 | − // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic | |
| 1760 | − 'operator': /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/, | |
| 1761 | − // If there is no $ sign at the beginning highlight (( and )) as punctuation | |
| 1762 | − 'punctuation': /\(\(?|\)\)?|,|;/ | |
| 1763 | − } | |
| 1764 | − }, | |
| 1765 | − // [1]: Command Substitution | |
| 1766 | − { | |
| 1767 | − pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/, | |
| 1768 | − greedy: true, | |
| 1769 | − inside: { | |
| 1770 | − 'variable': /^\$\(|^`|\)$|`$/ | |
| 1771 | − } | |
| 1772 | − }, | |
| 1773 | − // [2]: Brace expansion | |
| 1774 | − { | |
| 1775 | − pattern: /\$\{[^}]+\}/, | |
| 1776 | − greedy: true, | |
| 1777 | − inside: { | |
| 1778 | − 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, | |
| 1779 | − 'punctuation': /[\[\]]/, | |
| 1780 | − 'environment': { | |
| 1781 | − pattern: RegExp('(\\{)' + envVars), | |
| 1782 | − lookbehind: true, | |
| 1783 | − alias: 'constant' | |
| 1784 | − } | |
| 1785 | − } | |
| 1786 | − }, | |
| 1787 | − /\$(?:\w+|[#?*!@$])/ | |
| 1788 | − ], | |
| 1789 | − // Escape sequences from echo and printf's manuals, and escaped quotes. | |
| 1790 | − 'entity': /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/ | |
| 1791 | − }; | |
| 1792 | − | |
| 1793 | − Prism.languages.bash = { | |
| 1794 | − 'shebang': { | |
| 1795 | − pattern: /^#!\s*\/.*/, | |
| 1796 | − alias: 'important' | |
| 1797 | − }, | |
| 1798 | − 'comment': { | |
| 1799 | − pattern: /(^|[^"{\\$])#.*/, | |
| 1800 | − lookbehind: true | |
| 1801 | − }, | |
| 1802 | − 'function-name': [ | |
| 1803 | − // a) function foo { | |
| 1804 | − // b) foo() { | |
| 1805 | − // c) function foo() { | |
| 1806 | − // but not “foo {” | |
| 1807 | − { | |
| 1808 | − // a) and c) | |
| 1809 | − pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/, | |
| 1810 | − lookbehind: true, | |
| 1811 | − alias: 'function' | |
| 1812 | − }, | |
| 1813 | − { | |
| 1814 | − // b) | |
| 1815 | − pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/, | |
| 1816 | − alias: 'function' | |
| 1817 | − } | |
| 1818 | − ], | |
| 1819 | − // Highlight variable names as variables in for and select beginnings. | |
| 1820 | − 'for-or-select': { | |
| 1821 | − pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/, | |
| 1822 | − alias: 'variable', | |
| 1823 | − lookbehind: true | |
| 1824 | − }, | |
| 1825 | − // Highlight variable names as variables in the left-hand part | |
| 1826 | − // of assignments (“=” and “+=”). | |
| 1827 | − 'assign-left': { | |
| 1828 | − pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/, | |
| 1829 | − inside: { | |
| 1830 | − 'environment': { | |
| 1831 | − pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars), | |
| 1832 | − lookbehind: true, | |
| 1833 | − alias: 'constant' | |
| 1834 | − } | |
| 1835 | − }, | |
| 1836 | − alias: 'variable', | |
| 1837 | − lookbehind: true | |
| 1838 | − }, | |
| 1839 | − // Highlight parameter names as variables | |
| 1840 | − 'parameter': { | |
| 1841 | − pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/, | |
| 1842 | − alias: 'variable', | |
| 1843 | − lookbehind: true | |
| 1844 | − }, | |
| 1845 | − 'string': [ | |
| 1846 | − // Support for Here-documents https://en.wikipedia.org/wiki/Here_document | |
| 1847 | − { | |
| 1848 | − pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/, | |
| 1849 | − lookbehind: true, | |
| 1850 | − greedy: true, | |
| 1851 | − inside: insideString | |
| 1852 | − }, | |
| 1853 | − // Here-document with quotes around the tag | |
| 1854 | − // → No expansion (so no “inside”). | |
| 1855 | − { | |
| 1856 | − pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/, | |
| 1857 | − lookbehind: true, | |
| 1858 | − greedy: true, | |
| 1859 | − inside: { | |
| 1860 | − 'bash': commandAfterHeredoc | |
| 1861 | − } | |
| 1862 | − }, | |
| 1863 | − // “Normal” string | |
| 1864 | − { | |
| 1865 | − // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html | |
| 1866 | − pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/, | |
| 1867 | − lookbehind: true, | |
| 1868 | − greedy: true, | |
| 1869 | − inside: insideString | |
| 1870 | − }, | |
| 1871 | − { | |
| 1872 | − // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html | |
| 1873 | − pattern: /(^|[^$\\])'[^']*'/, | |
| 1874 | − lookbehind: true, | |
| 1875 | − greedy: true | |
| 1876 | − }, | |
| 1877 | − { | |
| 1878 | − // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html | |
| 1879 | − pattern: /\$'(?:[^'\\]|\\[\s\S])*'/, | |
| 1880 | − greedy: true, | |
| 1881 | − inside: { | |
| 1882 | − 'entity': insideString.entity | |
| 1883 | − } | |
| 1884 | − } | |
| 1885 | − ], | |
| 1886 | − 'environment': { | |
| 1887 | − pattern: RegExp('\\$?' + envVars), | |
| 1888 | − alias: 'constant' | |
| 1889 | − }, | |
| 1890 | − 'variable': insideString.variable, | |
| 1891 | − 'function': { | |
| 1892 | − pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/, | |
| 1893 | − lookbehind: true | |
| 1894 | − }, | |
| 1895 | − 'keyword': { | |
| 1896 | − pattern: /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/, | |
| 1897 | − lookbehind: true | |
| 1898 | − }, | |
| 1899 | − // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html | |
| 1900 | − 'builtin': { | |
| 1901 | − pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/, | |
| 1902 | − lookbehind: true, | |
| 1903 | − // Alias added to make those easier to distinguish from strings. | |
| 1904 | − alias: 'class-name' | |
| 1905 | − }, | |
| 1906 | − 'boolean': { | |
| 1907 | − pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/, | |
| 1908 | − lookbehind: true | |
| 1909 | − }, | |
| 1910 | − 'file-descriptor': { | |
| 1911 | − pattern: /\B&\d\b/, | |
| 1912 | − alias: 'important' | |
| 1913 | − }, | |
| 1914 | − 'operator': { | |
| 1915 | − // Lots of redirections here, but not just that. | |
| 1916 | − pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/, | |
| 1917 | − inside: { | |
| 1918 | − 'file-descriptor': { | |
| 1919 | − pattern: /^\d/, | |
| 1920 | − alias: 'important' | |
| 1921 | − } | |
| 1922 | − } | |
| 1923 | − }, | |
| 1924 | − 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/, | |
| 1925 | − 'number': { | |
| 1926 | − pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/, | |
| 1927 | − lookbehind: true | |
| 1928 | − } | |
| 1929 | − }; | |
| 1930 | − | |
| 1931 | − commandAfterHeredoc.inside = Prism.languages.bash; | |
| 1932 | − | |
| 1933 | − /* Patterns in command substitution. */ | |
| 1934 | − var toBeCopied = [ | |
| 1935 | − 'comment', | |
| 1936 | − 'function-name', | |
| 1937 | − 'for-or-select', | |
| 1938 | − 'assign-left', | |
| 1939 | − 'parameter', | |
| 1940 | − 'string', | |
| 1941 | − 'environment', | |
| 1942 | − 'function', | |
| 1943 | − 'keyword', | |
| 1944 | − 'builtin', | |
| 1945 | − 'boolean', | |
| 1946 | − 'file-descriptor', | |
| 1947 | − 'operator', | |
| 1948 | − 'punctuation', | |
| 1949 | − 'number' | |
| 1950 | − ]; | |
| 1951 | − var inside = insideString.variable[1].inside; | |
| 1952 | − for (var i = 0; i < toBeCopied.length; i++) { | |
| 1953 | − inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]]; | |
| 1954 | − } | |
| 1955 | − | |
| 1956 | − Prism.languages.sh = Prism.languages.bash; | |
| 1957 | − Prism.languages.shell = Prism.languages.bash; | |
| 1958 | −}(Prism)); | |
| 1959 | − | |
| 1960 | −Prism.languages.c = Prism.languages.extend('clike', { | |
| 1961 | − 'comment': { | |
| 1962 | − pattern: /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/, | |
| 1963 | − greedy: true | |
| 1964 | − }, | |
| 1965 | − 'string': { | |
| 1966 | − // https://en.cppreference.com/w/c/language/string_literal | |
| 1967 | − pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, | |
| 1968 | − greedy: true | |
| 1969 | − }, | |
| 1970 | − 'class-name': { | |
| 1971 | − pattern: /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/, | |
| 1972 | − lookbehind: true | |
| 1973 | − }, | |
| 1974 | − 'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/, | |
| 1975 | − 'function': /\b[a-z_]\w*(?=\s*\()/i, | |
| 1976 | − 'number': /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i, | |
| 1977 | − 'operator': />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/ | |
| 1835 | + // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|' | |
| 1836 | + // + LC_ALL, RANDOM, REPLY, SECONDS. | |
| 1837 | + // + make sure PS1..4 are here as they are not always set, | |
| 1838 | + // - some useless things. | |
| 1839 | + var envVars = | |
| 1840 | + "\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b"; | |
| 1841 | + | |
| 1842 | + var commandAfterHeredoc = { | |
| 1843 | + pattern: /(^(["']?)\w+\2)[ \t]+\S.*/, | |
| 1844 | + lookbehind: true, | |
| 1845 | + alias: "punctuation", // this looks reasonably well in all themes | |
| 1846 | + inside: null, // see below | |
| 1847 | + }; | |
| 1848 | + | |
| 1849 | + var insideString = { | |
| 1850 | + bash: commandAfterHeredoc, | |
| 1851 | + environment: { | |
| 1852 | + pattern: RegExp("\\$" + envVars), | |
| 1853 | + alias: "constant", | |
| 1854 | + }, | |
| 1855 | + variable: [ | |
| 1856 | + // [0]: Arithmetic Environment | |
| 1857 | + { | |
| 1858 | + pattern: /\$?\(\([\s\S]+?\)\)/, | |
| 1859 | + greedy: true, | |
| 1860 | + inside: { | |
| 1861 | + // If there is a $ sign at the beginning highlight $(( and )) as variable | |
| 1862 | + variable: [ | |
| 1863 | + { | |
| 1864 | + pattern: /(^\$\(\([\s\S]+)\)\)/, | |
| 1865 | + lookbehind: true, | |
| 1866 | + }, | |
| 1867 | + /^\$\(\(/, | |
| 1868 | + ], | |
| 1869 | + number: /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/, | |
| 1870 | + // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic | |
| 1871 | + operator: /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/, | |
| 1872 | + // If there is no $ sign at the beginning highlight (( and )) as punctuation | |
| 1873 | + punctuation: /\(\(?|\)\)?|,|;/, | |
| 1874 | + }, | |
| 1875 | + }, | |
| 1876 | + // [1]: Command Substitution | |
| 1877 | + { | |
| 1878 | + pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/, | |
| 1879 | + greedy: true, | |
| 1880 | + inside: { | |
| 1881 | + variable: /^\$\(|^`|\)$|`$/, | |
| 1882 | + }, | |
| 1883 | + }, | |
| 1884 | + // [2]: Brace expansion | |
| 1885 | + { | |
| 1886 | + pattern: /\$\{[^}]+\}/, | |
| 1887 | + greedy: true, | |
| 1888 | + inside: { | |
| 1889 | + operator: /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, | |
| 1890 | + punctuation: /[\[\]]/, | |
| 1891 | + environment: { | |
| 1892 | + pattern: RegExp("(\\{)" + envVars), | |
| 1893 | + lookbehind: true, | |
| 1894 | + alias: "constant", | |
| 1895 | + }, | |
| 1896 | + }, | |
| 1897 | + }, | |
| 1898 | + /\$(?:\w+|[#?*!@$])/, | |
| 1899 | + ], | |
| 1900 | + // Escape sequences from echo and printf's manuals, and escaped quotes. | |
| 1901 | + entity: | |
| 1902 | + /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/, | |
| 1903 | + }; | |
| 1904 | + | |
| 1905 | + Prism.languages.bash = { | |
| 1906 | + shebang: { | |
| 1907 | + pattern: /^#!\s*\/.*/, | |
| 1908 | + alias: "important", | |
| 1909 | + }, | |
| 1910 | + comment: { | |
| 1911 | + pattern: /(^|[^"{\\$])#.*/, | |
| 1912 | + lookbehind: true, | |
| 1913 | + }, | |
| 1914 | + "function-name": [ | |
| 1915 | + // a) function foo { | |
| 1916 | + // b) foo() { | |
| 1917 | + // c) function foo() { | |
| 1918 | + // but not “foo {” | |
| 1919 | + { | |
| 1920 | + // a) and c) | |
| 1921 | + pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/, | |
| 1922 | + lookbehind: true, | |
| 1923 | + alias: "function", | |
| 1924 | + }, | |
| 1925 | + { | |
| 1926 | + // b) | |
| 1927 | + pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/, | |
| 1928 | + alias: "function", | |
| 1929 | + }, | |
| 1930 | + ], | |
| 1931 | + // Highlight variable names as variables in for and select beginnings. | |
| 1932 | + "for-or-select": { | |
| 1933 | + pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/, | |
| 1934 | + alias: "variable", | |
| 1935 | + lookbehind: true, | |
| 1936 | + }, | |
| 1937 | + // Highlight variable names as variables in the left-hand part | |
| 1938 | + // of assignments (“=” and “+=”). | |
| 1939 | + "assign-left": { | |
| 1940 | + pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/, | |
| 1941 | + inside: { | |
| 1942 | + environment: { | |
| 1943 | + pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars), | |
| 1944 | + lookbehind: true, | |
| 1945 | + alias: "constant", | |
| 1946 | + }, | |
| 1947 | + }, | |
| 1948 | + alias: "variable", | |
| 1949 | + lookbehind: true, | |
| 1950 | + }, | |
| 1951 | + // Highlight parameter names as variables | |
| 1952 | + parameter: { | |
| 1953 | + pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/, | |
| 1954 | + alias: "variable", | |
| 1955 | + lookbehind: true, | |
| 1956 | + }, | |
| 1957 | + string: [ | |
| 1958 | + // Support for Here-documents https://en.wikipedia.org/wiki/Here_document | |
| 1959 | + { | |
| 1960 | + pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/, | |
| 1961 | + lookbehind: true, | |
| 1962 | + greedy: true, | |
| 1963 | + inside: insideString, | |
| 1964 | + }, | |
| 1965 | + // Here-document with quotes around the tag | |
| 1966 | + // → No expansion (so no “inside”). | |
| 1967 | + { | |
| 1968 | + pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/, | |
| 1969 | + lookbehind: true, | |
| 1970 | + greedy: true, | |
| 1971 | + inside: { | |
| 1972 | + bash: commandAfterHeredoc, | |
| 1973 | + }, | |
| 1974 | + }, | |
| 1975 | + // “Normal” string | |
| 1976 | + { | |
| 1977 | + // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html | |
| 1978 | + pattern: | |
| 1979 | + /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/, | |
| 1980 | + lookbehind: true, | |
| 1981 | + greedy: true, | |
| 1982 | + inside: insideString, | |
| 1983 | + }, | |
| 1984 | + { | |
| 1985 | + // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html | |
| 1986 | + pattern: /(^|[^$\\])'[^']*'/, | |
| 1987 | + lookbehind: true, | |
| 1988 | + greedy: true, | |
| 1989 | + }, | |
| 1990 | + { | |
| 1991 | + // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html | |
| 1992 | + pattern: /\$'(?:[^'\\]|\\[\s\S])*'/, | |
| 1993 | + greedy: true, | |
| 1994 | + inside: { | |
| 1995 | + entity: insideString.entity, | |
| 1996 | + }, | |
| 1997 | + }, | |
| 1998 | + ], | |
| 1999 | + environment: { | |
| 2000 | + pattern: RegExp("\\$?" + envVars), | |
| 2001 | + alias: "constant", | |
| 2002 | + }, | |
| 2003 | + variable: insideString.variable, | |
| 2004 | + function: { | |
| 2005 | + pattern: | |
| 2006 | + /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/, | |
| 2007 | + lookbehind: true, | |
| 2008 | + }, | |
| 2009 | + keyword: { | |
| 2010 | + pattern: | |
| 2011 | + /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/, | |
| 2012 | + lookbehind: true, | |
| 2013 | + }, | |
| 2014 | + // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html | |
| 2015 | + builtin: { | |
| 2016 | + pattern: | |
| 2017 | + /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/, | |
| 2018 | + lookbehind: true, | |
| 2019 | + // Alias added to make those easier to distinguish from strings. | |
| 2020 | + alias: "class-name", | |
| 2021 | + }, | |
| 2022 | + boolean: { | |
| 2023 | + pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/, | |
| 2024 | + lookbehind: true, | |
| 2025 | + }, | |
| 2026 | + "file-descriptor": { | |
| 2027 | + pattern: /\B&\d\b/, | |
| 2028 | + alias: "important", | |
| 2029 | + }, | |
| 2030 | + operator: { | |
| 2031 | + // Lots of redirections here, but not just that. | |
| 2032 | + pattern: | |
| 2033 | + /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/, | |
| 2034 | + inside: { | |
| 2035 | + "file-descriptor": { | |
| 2036 | + pattern: /^\d/, | |
| 2037 | + alias: "important", | |
| 2038 | + }, | |
| 2039 | + }, | |
| 2040 | + }, | |
| 2041 | + punctuation: /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/, | |
| 2042 | + number: { | |
| 2043 | + pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/, | |
| 2044 | + lookbehind: true, | |
| 2045 | + }, | |
| 2046 | + }; | |
| 2047 | + | |
| 2048 | + commandAfterHeredoc.inside = Prism.languages.bash; | |
| 2049 | + | |
| 2050 | + /* Patterns in command substitution. */ | |
| 2051 | + var toBeCopied = [ | |
| 2052 | + "comment", | |
| 2053 | + "function-name", | |
| 2054 | + "for-or-select", | |
| 2055 | + "assign-left", | |
| 2056 | + "parameter", | |
| 2057 | + "string", | |
| 2058 | + "environment", | |
| 2059 | + "function", | |
| 2060 | + "keyword", | |
| 2061 | + "builtin", | |
| 2062 | + "boolean", | |
| 2063 | + "file-descriptor", | |
| 2064 | + "operator", | |
| 2065 | + "punctuation", | |
| 2066 | + "number", | |
| 2067 | + ]; | |
| 2068 | + var inside = insideString.variable[1].inside; | |
| 2069 | + for (var i = 0; i < toBeCopied.length; i++) { | |
| 2070 | + inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]]; | |
| 2071 | + } | |
| 2072 | + | |
| 2073 | + Prism.languages.sh = Prism.languages.bash; | |
| 2074 | + Prism.languages.shell = Prism.languages.bash; | |
| 2075 | +})(Prism); | |
| 2076 | + | |
| 2077 | +Prism.languages.c = Prism.languages.extend("clike", { | |
| 2078 | + comment: { | |
| 2079 | + pattern: | |
| 2080 | + /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/, | |
| 2081 | + greedy: true, | |
| 2082 | + }, | |
| 2083 | + string: { | |
| 2084 | + // https://en.cppreference.com/w/c/language/string_literal | |
| 2085 | + pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, | |
| 2086 | + greedy: true, | |
| 2087 | + }, | |
| 2088 | + "class-name": { | |
| 2089 | + pattern: | |
| 2090 | + /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/, | |
| 2091 | + lookbehind: true, | |
| 2092 | + }, | |
| 2093 | + keyword: | |
| 2094 | + /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/, | |
| 2095 | + function: /\b[a-z_]\w*(?=\s*\()/i, | |
| 2096 | + number: | |
| 2097 | + /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i, | |
| 2098 | + operator: />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/, | |
| 1978 | 2099 | }); |
| 1979 | 2100 | |
| 1980 | −Prism.languages.insertBefore('c', 'string', { | |
| 1981 | − 'char': { | |
| 1982 | − // https://en.cppreference.com/w/c/language/character_constant | |
| 1983 | − pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/, | |
| 1984 | − greedy: true | |
| 1985 | − } | |
| 2101 | +Prism.languages.insertBefore("c", "string", { | |
| 2102 | + char: { | |
| 2103 | + // https://en.cppreference.com/w/c/language/character_constant | |
| 2104 | + pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/, | |
| 2105 | + greedy: true, | |
| 2106 | + }, | |
| 1986 | 2107 | }); |
| 1987 | 2108 | |
| 1988 | −Prism.languages.insertBefore('c', 'string', { | |
| 1989 | − 'macro': { | |
| 1990 | − // allow for multiline macro definitions | |
| 1991 | − // spaces after the # character compile fine with gcc | |
| 1992 | − pattern: /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im, | |
| 1993 | − lookbehind: true, | |
| 1994 | − greedy: true, | |
| 1995 | − alias: 'property', | |
| 1996 | − inside: { | |
| 1997 | − 'string': [ | |
| 1998 | − { | |
| 1999 | − // highlight the path of the include statement as a string | |
| 2000 | − pattern: /^(#\s*include\s*)<[^>]+>/, | |
| 2001 | − lookbehind: true | |
| 2002 | − }, | |
| 2003 | − Prism.languages.c['string'] | |
| 2004 | − ], | |
| 2005 | − 'char': Prism.languages.c['char'], | |
| 2006 | − 'comment': Prism.languages.c['comment'], | |
| 2007 | − 'macro-name': [ | |
| 2008 | − { | |
| 2009 | − pattern: /(^#\s*define\s+)\w+\b(?!\()/i, | |
| 2010 | − lookbehind: true | |
| 2011 | − }, | |
| 2012 | − { | |
| 2013 | − pattern: /(^#\s*define\s+)\w+\b(?=\()/i, | |
| 2014 | − lookbehind: true, | |
| 2015 | − alias: 'function' | |
| 2016 | − } | |
| 2017 | − ], | |
| 2018 | − // highlight macro directives as keywords | |
| 2019 | − 'directive': { | |
| 2020 | − pattern: /^(#\s*)[a-z]+/, | |
| 2021 | − lookbehind: true, | |
| 2022 | − alias: 'keyword' | |
| 2023 | − }, | |
| 2024 | − 'directive-hash': /^#/, | |
| 2025 | − 'punctuation': /##|\\(?=[\r\n])/, | |
| 2026 | − 'expression': { | |
| 2027 | − pattern: /\S[\s\S]*/, | |
| 2028 | − inside: Prism.languages.c | |
| 2029 | − } | |
| 2030 | − } | |
| 2031 | − } | |
| 2109 | +Prism.languages.insertBefore("c", "string", { | |
| 2110 | + macro: { | |
| 2111 | + // allow for multiline macro definitions | |
| 2112 | + // spaces after the # character compile fine with gcc | |
| 2113 | + pattern: | |
| 2114 | + /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im, | |
| 2115 | + lookbehind: true, | |
| 2116 | + greedy: true, | |
| 2117 | + alias: "property", | |
| 2118 | + inside: { | |
| 2119 | + string: [ | |
| 2120 | + { | |
| 2121 | + // highlight the path of the include statement as a string | |
| 2122 | + pattern: /^(#\s*include\s*)<[^>]+>/, | |
| 2123 | + lookbehind: true, | |
| 2124 | + }, | |
| 2125 | + Prism.languages.c["string"], | |
| 2126 | + ], | |
| 2127 | + char: Prism.languages.c["char"], | |
| 2128 | + comment: Prism.languages.c["comment"], | |
| 2129 | + "macro-name": [ | |
| 2130 | + { | |
| 2131 | + pattern: /(^#\s*define\s+)\w+\b(?!\()/i, | |
| 2132 | + lookbehind: true, | |
| 2133 | + }, | |
| 2134 | + { | |
| 2135 | + pattern: /(^#\s*define\s+)\w+\b(?=\()/i, | |
| 2136 | + lookbehind: true, | |
| 2137 | + alias: "function", | |
| 2138 | + }, | |
| 2139 | + ], | |
| 2140 | + // highlight macro directives as keywords | |
| 2141 | + directive: { | |
| 2142 | + pattern: /^(#\s*)[a-z]+/, | |
| 2143 | + lookbehind: true, | |
| 2144 | + alias: "keyword", | |
| 2145 | + }, | |
| 2146 | + "directive-hash": /^#/, | |
| 2147 | + punctuation: /##|\\(?=[\r\n])/, | |
| 2148 | + expression: { | |
| 2149 | + pattern: /\S[\s\S]*/, | |
| 2150 | + inside: Prism.languages.c, | |
| 2151 | + }, | |
| 2152 | + }, | |
| 2153 | + }, | |
| 2032 | 2154 | }); |
| 2033 | 2155 | |
| 2034 | −Prism.languages.insertBefore('c', 'function', { | |
| 2035 | − // highlight predefined macros as constants | |
| 2036 | − 'constant': /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/ | |
| 2156 | +Prism.languages.insertBefore("c", "function", { | |
| 2157 | + // highlight predefined macros as constants | |
| 2158 | + constant: | |
| 2159 | + /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/, | |
| 2037 | 2160 | }); |
| 2038 | 2161 | |
| 2039 | −delete Prism.languages.c['boolean']; | |
| 2162 | +delete Prism.languages.c["boolean"]; | |
| 2040 | 2163 | |
| 2041 | 2164 | (function (Prism) { |
| 2042 | − | |
| 2043 | − var keyword = /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/; | |
| 2044 | − var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function () { return keyword.source; }); | |
| 2045 | − | |
| 2046 | − Prism.languages.cpp = Prism.languages.extend('c', { | |
| 2047 | − 'class-name': [ | |
| 2048 | − { | |
| 2049 | − pattern: RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source | |
| 2050 | − .replace(/<keyword>/g, function () { return keyword.source; })), | |
| 2051 | − lookbehind: true | |
| 2052 | − }, | |
| 2053 | − // This is intended to capture the class name of method implementations like: | |
| 2054 | − // void foo::bar() const {} | |
| 2055 | − // However! The `foo` in the above example could also be a namespace, so we only capture the class name if | |
| 2056 | − // it starts with an uppercase letter. This approximation should give decent results. | |
| 2057 | − /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/, | |
| 2058 | − // This will capture the class name before destructors like: | |
| 2059 | − // Foo::~Foo() {} | |
| 2060 | − /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i, | |
| 2061 | − // This also intends to capture the class name of method implementations but here the class has template | |
| 2062 | − // parameters, so it can't be a namespace (until C++ adds generic namespaces). | |
| 2063 | − /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/ | |
| 2064 | − ], | |
| 2065 | − 'keyword': keyword, | |
| 2066 | − 'number': { | |
| 2067 | − pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i, | |
| 2068 | − greedy: true | |
| 2069 | − }, | |
| 2070 | − 'operator': />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/, | |
| 2071 | − 'boolean': /\b(?:false|true)\b/ | |
| 2072 | − }); | |
| 2073 | − | |
| 2074 | − Prism.languages.insertBefore('cpp', 'string', { | |
| 2075 | − 'module': { | |
| 2076 | − // https://en.cppreference.com/w/cpp/language/modules | |
| 2077 | − pattern: RegExp( | |
| 2078 | − /(\b(?:import|module)\s+)/.source + | |
| 2079 | − '(?:' + | |
| 2080 | − // header-name | |
| 2081 | − /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source + | |
| 2082 | − '|' + | |
| 2083 | − // module name or partition or both | |
| 2084 | − /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function () { return modName; }) + | |
| 2085 | − ')' | |
| 2086 | − ), | |
| 2087 | − lookbehind: true, | |
| 2088 | − greedy: true, | |
| 2089 | − inside: { | |
| 2090 | − 'string': /^[<"][\s\S]+/, | |
| 2091 | − 'operator': /:/, | |
| 2092 | − 'punctuation': /\./ | |
| 2093 | − } | |
| 2094 | − }, | |
| 2095 | − 'raw-string': { | |
| 2096 | − pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, | |
| 2097 | − alias: 'string', | |
| 2098 | − greedy: true | |
| 2099 | − } | |
| 2100 | − }); | |
| 2101 | − | |
| 2102 | − Prism.languages.insertBefore('cpp', 'keyword', { | |
| 2103 | − 'generic-function': { | |
| 2104 | − pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i, | |
| 2105 | − inside: { | |
| 2106 | − 'function': /^\w+/, | |
| 2107 | − 'generic': { | |
| 2108 | − pattern: /<[\s\S]+/, | |
| 2109 | − alias: 'class-name', | |
| 2110 | − inside: Prism.languages.cpp | |
| 2111 | − } | |
| 2112 | − } | |
| 2113 | − } | |
| 2114 | − }); | |
| 2115 | − | |
| 2116 | − Prism.languages.insertBefore('cpp', 'operator', { | |
| 2117 | − 'double-colon': { | |
| 2118 | − pattern: /::/, | |
| 2119 | − alias: 'punctuation' | |
| 2120 | − } | |
| 2121 | − }); | |
| 2122 | − | |
| 2123 | − Prism.languages.insertBefore('cpp', 'class-name', { | |
| 2124 | − // the base clause is an optional list of parent classes | |
| 2125 | − // https://en.cppreference.com/w/cpp/language/class | |
| 2126 | − 'base-clause': { | |
| 2127 | − pattern: /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/, | |
| 2128 | − lookbehind: true, | |
| 2129 | − greedy: true, | |
| 2130 | − inside: Prism.languages.extend('cpp', {}) | |
| 2131 | − } | |
| 2132 | − }); | |
| 2133 | − | |
| 2134 | − Prism.languages.insertBefore('inside', 'double-colon', { | |
| 2135 | − // All untokenized words that are not namespaces should be class names | |
| 2136 | − 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i | |
| 2137 | − }, Prism.languages.cpp['base-clause']); | |
| 2138 | − | |
| 2139 | −}(Prism)); | |
| 2165 | + var keyword = | |
| 2166 | + /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/; | |
| 2167 | + var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace( | |
| 2168 | + /<keyword>/g, | |
| 2169 | + function () { | |
| 2170 | + return keyword.source; | |
| 2171 | + }, | |
| 2172 | + ); | |
| 2173 | + | |
| 2174 | + Prism.languages.cpp = Prism.languages.extend("c", { | |
| 2175 | + "class-name": [ | |
| 2176 | + { | |
| 2177 | + pattern: RegExp( | |
| 2178 | + /(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace( | |
| 2179 | + /<keyword>/g, | |
| 2180 | + function () { | |
| 2181 | + return keyword.source; | |
| 2182 | + }, | |
| 2183 | + ), | |
| 2184 | + ), | |
| 2185 | + lookbehind: true, | |
| 2186 | + }, | |
| 2187 | + // This is intended to capture the class name of method implementations like: | |
| 2188 | + // void foo::bar() const {} | |
| 2189 | + // However! The `foo` in the above example could also be a namespace, so we only capture the class name if | |
| 2190 | + // it starts with an uppercase letter. This approximation should give decent results. | |
| 2191 | + /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/, | |
| 2192 | + // This will capture the class name before destructors like: | |
| 2193 | + // Foo::~Foo() {} | |
| 2194 | + /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i, | |
| 2195 | + // This also intends to capture the class name of method implementations but here the class has template | |
| 2196 | + // parameters, so it can't be a namespace (until C++ adds generic namespaces). | |
| 2197 | + /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/, | |
| 2198 | + ], | |
| 2199 | + keyword: keyword, | |
| 2200 | + number: { | |
| 2201 | + pattern: | |
| 2202 | + /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i, | |
| 2203 | + greedy: true, | |
| 2204 | + }, | |
| 2205 | + operator: | |
| 2206 | + />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/, | |
| 2207 | + boolean: /\b(?:false|true)\b/, | |
| 2208 | + }); | |
| 2209 | + | |
| 2210 | + Prism.languages.insertBefore("cpp", "string", { | |
| 2211 | + module: { | |
| 2212 | + // https://en.cppreference.com/w/cpp/language/modules | |
| 2213 | + pattern: RegExp( | |
| 2214 | + /(\b(?:import|module)\s+)/.source + | |
| 2215 | + "(?:" + | |
| 2216 | + // header-name | |
| 2217 | + /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source + | |
| 2218 | + "|" + | |
| 2219 | + // module name or partition or both | |
| 2220 | + /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace( | |
| 2221 | + /<mod-name>/g, | |
| 2222 | + function () { | |
| 2223 | + return modName; | |
| 2224 | + }, | |
| 2225 | + ) + | |
| 2226 | + ")", | |
| 2227 | + ), | |
| 2228 | + lookbehind: true, | |
| 2229 | + greedy: true, | |
| 2230 | + inside: { | |
| 2231 | + string: /^[<"][\s\S]+/, | |
| 2232 | + operator: /:/, | |
| 2233 | + punctuation: /\./, | |
| 2234 | + }, | |
| 2235 | + }, | |
| 2236 | + "raw-string": { | |
| 2237 | + pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, | |
| 2238 | + alias: "string", | |
| 2239 | + greedy: true, | |
| 2240 | + }, | |
| 2241 | + }); | |
| 2242 | + | |
| 2243 | + Prism.languages.insertBefore("cpp", "keyword", { | |
| 2244 | + "generic-function": { | |
| 2245 | + pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i, | |
| 2246 | + inside: { | |
| 2247 | + function: /^\w+/, | |
| 2248 | + generic: { | |
| 2249 | + pattern: /<[\s\S]+/, | |
| 2250 | + alias: "class-name", | |
| 2251 | + inside: Prism.languages.cpp, | |
| 2252 | + }, | |
| 2253 | + }, | |
| 2254 | + }, | |
| 2255 | + }); | |
| 2256 | + | |
| 2257 | + Prism.languages.insertBefore("cpp", "operator", { | |
| 2258 | + "double-colon": { | |
| 2259 | + pattern: /::/, | |
| 2260 | + alias: "punctuation", | |
| 2261 | + }, | |
| 2262 | + }); | |
| 2263 | + | |
| 2264 | + Prism.languages.insertBefore("cpp", "class-name", { | |
| 2265 | + // the base clause is an optional list of parent classes | |
| 2266 | + // https://en.cppreference.com/w/cpp/language/class | |
| 2267 | + "base-clause": { | |
| 2268 | + pattern: | |
| 2269 | + /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/, | |
| 2270 | + lookbehind: true, | |
| 2271 | + greedy: true, | |
| 2272 | + inside: Prism.languages.extend("cpp", {}), | |
| 2273 | + }, | |
| 2274 | + }); | |
| 2275 | + | |
| 2276 | + Prism.languages.insertBefore( | |
| 2277 | + "inside", | |
| 2278 | + "double-colon", | |
| 2279 | + { | |
| 2280 | + // All untokenized words that are not namespaces should be class names | |
| 2281 | + "class-name": /\b[a-z_]\w*\b(?!\s*::)/i, | |
| 2282 | + }, | |
| 2283 | + Prism.languages.cpp["base-clause"], | |
| 2284 | + ); | |
| 2285 | +})(Prism); | |
| 2140 | 2286 | |
| 2141 | 2287 | Prism.languages.cmake = { |
| 2142 | − 'comment': /#.*/, | |
| 2143 | − 'string': { | |
| 2144 | − pattern: /"(?:[^\\"]|\\.)*"/, | |
| 2145 | − greedy: true, | |
| 2146 | − inside: { | |
| 2147 | − 'interpolation': { | |
| 2148 | − pattern: /\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/, | |
| 2149 | − inside: { | |
| 2150 | − 'punctuation': /\$\{|\}/, | |
| 2151 | − 'variable': /\w+/ | |
| 2152 | − } | |
| 2153 | − } | |
| 2154 | − } | |
| 2155 | − }, | |
| 2156 | − 'variable': /\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/, | |
| 2157 | − 'property': /\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/, | |
| 2158 | − 'keyword': /\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/, | |
| 2159 | − 'boolean': /\b(?:FALSE|OFF|ON|TRUE)\b/, | |
| 2160 | − 'namespace': /\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/, | |
| 2161 | − 'operator': /\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/, | |
| 2162 | − 'inserted': { | |
| 2163 | − pattern: /\b\w+::\w+\b/, | |
| 2164 | − alias: 'class-name' | |
| 2165 | − }, | |
| 2166 | − 'number': /\b\d+(?:\.\d+)*\b/, | |
| 2167 | − 'function': /\b[a-z_]\w*(?=\s*\()\b/i, | |
| 2168 | − 'punctuation': /[()>}]|\$[<{]/ | |
| 2288 | + comment: /#.*/, | |
| 2289 | + string: { | |
| 2290 | + pattern: /"(?:[^\\"]|\\.)*"/, | |
| 2291 | + greedy: true, | |
| 2292 | + inside: { | |
| 2293 | + interpolation: { | |
| 2294 | + pattern: /\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/, | |
| 2295 | + inside: { | |
| 2296 | + punctuation: /\$\{|\}/, | |
| 2297 | + variable: /\w+/, | |
| 2298 | + }, | |
| 2299 | + }, | |
| 2300 | + }, | |
| 2301 | + }, | |
| 2302 | + variable: | |
| 2303 | + /\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/, | |
| 2304 | + property: | |
| 2305 | + /\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/, | |
| 2306 | + keyword: | |
| 2307 | + /\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/, | |
| 2308 | + boolean: /\b(?:FALSE|OFF|ON|TRUE)\b/, | |
| 2309 | + namespace: | |
| 2310 | + /\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/, | |
| 2311 | + operator: | |
| 2312 | + /\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/, | |
| 2313 | + inserted: { | |
| 2314 | + pattern: /\b\w+::\w+\b/, | |
| 2315 | + alias: "class-name", | |
| 2316 | + }, | |
| 2317 | + number: /\b\d+(?:\.\d+)*\b/, | |
| 2318 | + function: /\b[a-z_]\w*(?=\s*\()\b/i, | |
| 2319 | + punctuation: /[()>}]|\$[<{]/, | |
| 2169 | 2320 | }; |
| 2170 | 2321 | |
| 2171 | 2322 | (function (Prism) { |
| 2172 | − | |
| 2173 | − // Ignore comments starting with { to privilege string interpolation highlighting | |
| 2174 | − var comment = /#(?!\{).+/; | |
| 2175 | − var interpolation = { | |
| 2176 | − pattern: /#\{[^}]+\}/, | |
| 2177 | − alias: 'variable' | |
| 2178 | − }; | |
| 2179 | − | |
| 2180 | − Prism.languages.coffeescript = Prism.languages.extend('javascript', { | |
| 2181 | − 'comment': comment, | |
| 2182 | − 'string': [ | |
| 2183 | − | |
| 2184 | − // Strings are multiline | |
| 2185 | − { | |
| 2186 | − pattern: /'(?:\\[\s\S]|[^\\'])*'/, | |
| 2187 | − greedy: true | |
| 2188 | − }, | |
| 2189 | − | |
| 2190 | − { | |
| 2191 | − // Strings are multiline | |
| 2192 | − pattern: /"(?:\\[\s\S]|[^\\"])*"/, | |
| 2193 | − greedy: true, | |
| 2194 | − inside: { | |
| 2195 | − 'interpolation': interpolation | |
| 2196 | − } | |
| 2197 | − } | |
| 2198 | − ], | |
| 2199 | − 'keyword': /\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/, | |
| 2200 | − 'class-member': { | |
| 2201 | − pattern: /@(?!\d)\w+/, | |
| 2202 | − alias: 'variable' | |
| 2203 | − } | |
| 2204 | − }); | |
| 2205 | − | |
| 2206 | − Prism.languages.insertBefore('coffeescript', 'comment', { | |
| 2207 | − 'multiline-comment': { | |
| 2208 | − pattern: /###[\s\S]+?###/, | |
| 2209 | − alias: 'comment' | |
| 2210 | − }, | |
| 2211 | − | |
| 2212 | − // Block regexp can contain comments and interpolation | |
| 2213 | − 'block-regex': { | |
| 2214 | − pattern: /\/{3}[\s\S]*?\/{3}/, | |
| 2215 | − alias: 'regex', | |
| 2216 | − inside: { | |
| 2217 | − 'comment': comment, | |
| 2218 | − 'interpolation': interpolation | |
| 2219 | − } | |
| 2220 | − } | |
| 2221 | − }); | |
| 2222 | − | |
| 2223 | − Prism.languages.insertBefore('coffeescript', 'string', { | |
| 2224 | − 'inline-javascript': { | |
| 2225 | − pattern: /`(?:\\[\s\S]|[^\\`])*`/, | |
| 2226 | − inside: { | |
| 2227 | − 'delimiter': { | |
| 2228 | − pattern: /^`|`$/, | |
| 2229 | − alias: 'punctuation' | |
| 2230 | − }, | |
| 2231 | − 'script': { | |
| 2232 | − pattern: /[\s\S]+/, | |
| 2233 | − alias: 'language-javascript', | |
| 2234 | − inside: Prism.languages.javascript | |
| 2235 | − } | |
| 2236 | − } | |
| 2237 | − }, | |
| 2238 | − | |
| 2239 | − // Block strings | |
| 2240 | − 'multiline-string': [ | |
| 2241 | − { | |
| 2242 | − pattern: /'''[\s\S]*?'''/, | |
| 2243 | − greedy: true, | |
| 2244 | − alias: 'string' | |
| 2245 | − }, | |
| 2246 | − { | |
| 2247 | − pattern: /"""[\s\S]*?"""/, | |
| 2248 | − greedy: true, | |
| 2249 | − alias: 'string', | |
| 2250 | − inside: { | |
| 2251 | − interpolation: interpolation | |
| 2252 | − } | |
| 2253 | − } | |
| 2254 | − ] | |
| 2255 | − | |
| 2256 | − }); | |
| 2257 | − | |
| 2258 | − Prism.languages.insertBefore('coffeescript', 'keyword', { | |
| 2259 | − // Object property | |
| 2260 | − 'property': /(?!\d)\w+(?=\s*:(?!:))/ | |
| 2261 | − }); | |
| 2262 | − | |
| 2263 | − delete Prism.languages.coffeescript['template-string']; | |
| 2264 | − | |
| 2265 | − Prism.languages.coffee = Prism.languages.coffeescript; | |
| 2266 | −}(Prism)); | |
| 2323 | + // Ignore comments starting with { to privilege string interpolation highlighting | |
| 2324 | + var comment = /#(?!\{).+/; | |
| 2325 | + var interpolation = { | |
| 2326 | + pattern: /#\{[^}]+\}/, | |
| 2327 | + alias: "variable", | |
| 2328 | + }; | |
| 2329 | + | |
| 2330 | + Prism.languages.coffeescript = Prism.languages.extend("javascript", { | |
| 2331 | + comment: comment, | |
| 2332 | + string: [ | |
| 2333 | + // Strings are multiline | |
| 2334 | + { | |
| 2335 | + pattern: /'(?:\\[\s\S]|[^\\'])*'/, | |
| 2336 | + greedy: true, | |
| 2337 | + }, | |
| 2338 | + | |
| 2339 | + { | |
| 2340 | + // Strings are multiline | |
| 2341 | + pattern: /"(?:\\[\s\S]|[^\\"])*"/, | |
| 2342 | + greedy: true, | |
| 2343 | + inside: { | |
| 2344 | + interpolation: interpolation, | |
| 2345 | + }, | |
| 2346 | + }, | |
| 2347 | + ], | |
| 2348 | + keyword: | |
| 2349 | + /\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/, | |
| 2350 | + "class-member": { | |
| 2351 | + pattern: /@(?!\d)\w+/, | |
| 2352 | + alias: "variable", | |
| 2353 | + }, | |
| 2354 | + }); | |
| 2355 | + | |
| 2356 | + Prism.languages.insertBefore("coffeescript", "comment", { | |
| 2357 | + "multiline-comment": { | |
| 2358 | + pattern: /###[\s\S]+?###/, | |
| 2359 | + alias: "comment", | |
| 2360 | + }, | |
| 2361 | + | |
| 2362 | + // Block regexp can contain comments and interpolation | |
| 2363 | + "block-regex": { | |
| 2364 | + pattern: /\/{3}[\s\S]*?\/{3}/, | |
| 2365 | + alias: "regex", | |
| 2366 | + inside: { | |
| 2367 | + comment: comment, | |
| 2368 | + interpolation: interpolation, | |
| 2369 | + }, | |
| 2370 | + }, | |
| 2371 | + }); | |
| 2372 | + | |
| 2373 | + Prism.languages.insertBefore("coffeescript", "string", { | |
| 2374 | + "inline-javascript": { | |
| 2375 | + pattern: /`(?:\\[\s\S]|[^\\`])*`/, | |
| 2376 | + inside: { | |
| 2377 | + delimiter: { | |
| 2378 | + pattern: /^`|`$/, | |
| 2379 | + alias: "punctuation", | |
| 2380 | + }, | |
| 2381 | + script: { | |
| 2382 | + pattern: /[\s\S]+/, | |
| 2383 | + alias: "language-javascript", | |
| 2384 | + inside: Prism.languages.javascript, | |
| 2385 | + }, | |
| 2386 | + }, | |
| 2387 | + }, | |
| 2388 | + | |
| 2389 | + // Block strings | |
| 2390 | + "multiline-string": [ | |
| 2391 | + { | |
| 2392 | + pattern: /'''[\s\S]*?'''/, | |
| 2393 | + greedy: true, | |
| 2394 | + alias: "string", | |
| 2395 | + }, | |
| 2396 | + { | |
| 2397 | + pattern: /"""[\s\S]*?"""/, | |
| 2398 | + greedy: true, | |
| 2399 | + alias: "string", | |
| 2400 | + inside: { | |
| 2401 | + interpolation: interpolation, | |
| 2402 | + }, | |
| 2403 | + }, | |
| 2404 | + ], | |
| 2405 | + }); | |
| 2406 | + | |
| 2407 | + Prism.languages.insertBefore("coffeescript", "keyword", { | |
| 2408 | + // Object property | |
| 2409 | + property: /(?!\d)\w+(?=\s*:(?!:))/, | |
| 2410 | + }); | |
| 2411 | + | |
| 2412 | + delete Prism.languages.coffeescript["template-string"]; | |
| 2413 | + | |
| 2414 | + Prism.languages.coffee = Prism.languages.coffeescript; | |
| 2415 | +})(Prism); | |
| 2267 | 2416 | |
| 2268 | 2417 | /** |
| 2269 | 2418 | * Original by Samuel Flores |
| @@ -2272,1833 +2421,1968 @@ Prism.languages.cmake = { · 2 unmodified lines | ||
| 2272 | 2421 | * constant, builtin, variable, symbol, regex |
| 2273 | 2422 | */ |
| 2274 | 2423 | (function (Prism) { |
| 2275 | − Prism.languages.ruby = Prism.languages.extend('clike', { | |
| 2276 | − 'comment': { | |
| 2277 | − pattern: /#.*|^=begin\s[\s\S]*?^=end/m, | |
| 2278 | − greedy: true | |
| 2279 | − }, | |
| 2280 | − 'class-name': { | |
| 2281 | − pattern: /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/, | |
| 2282 | − lookbehind: true, | |
| 2283 | − inside: { | |
| 2284 | − 'punctuation': /[.\\]/ | |
| 2285 | − } | |
| 2286 | − }, | |
| 2287 | − 'keyword': /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/, | |
| 2288 | − 'operator': /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/, | |
| 2289 | − 'punctuation': /[(){}[\].,;]/, | |
| 2290 | − }); | |
| 2291 | − | |
| 2292 | − Prism.languages.insertBefore('ruby', 'operator', { | |
| 2293 | − 'double-colon': { | |
| 2294 | − pattern: /::/, | |
| 2295 | − alias: 'punctuation' | |
| 2296 | − }, | |
| 2297 | − }); | |
| 2298 | − | |
| 2299 | − var interpolation = { | |
| 2300 | − pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/, | |
| 2301 | − lookbehind: true, | |
| 2302 | − inside: { | |
| 2303 | − 'content': { | |
| 2304 | − pattern: /^(#\{)[\s\S]+(?=\}$)/, | |
| 2305 | − lookbehind: true, | |
| 2306 | − inside: Prism.languages.ruby | |
| 2307 | − }, | |
| 2308 | − 'delimiter': { | |
| 2309 | − pattern: /^#\{|\}$/, | |
| 2310 | − alias: 'punctuation' | |
| 2311 | − } | |
| 2312 | − } | |
| 2313 | − }; | |
| 2314 | − | |
| 2315 | − delete Prism.languages.ruby.function; | |
| 2316 | − | |
| 2317 | − var percentExpression = '(?:' + [ | |
| 2318 | − /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, | |
| 2319 | − /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source, | |
| 2320 | − /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source, | |
| 2321 | − /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source, | |
| 2322 | − /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source | |
| 2323 | − ].join('|') + ')'; | |
| 2324 | − | |
| 2325 | − var symbolName = /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source; | |
| 2326 | − | |
| 2327 | − Prism.languages.insertBefore('ruby', 'keyword', { | |
| 2328 | − 'regex-literal': [ | |
| 2329 | − { | |
| 2330 | − pattern: RegExp(/%r/.source + percentExpression + /[egimnosux]{0,6}/.source), | |
| 2331 | − greedy: true, | |
| 2332 | − inside: { | |
| 2333 | − 'interpolation': interpolation, | |
| 2334 | − 'regex': /[\s\S]+/ | |
| 2335 | − } | |
| 2336 | − }, | |
| 2337 | − { | |
| 2338 | − pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/, | |
| 2339 | − lookbehind: true, | |
| 2340 | − greedy: true, | |
| 2341 | − inside: { | |
| 2342 | − 'interpolation': interpolation, | |
| 2343 | − 'regex': /[\s\S]+/ | |
| 2344 | − } | |
| 2345 | − } | |
| 2346 | − ], | |
| 2347 | − 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, | |
| 2348 | − 'symbol': [ | |
| 2349 | − { | |
| 2350 | − pattern: RegExp(/(^|[^:]):/.source + symbolName), | |
| 2351 | − lookbehind: true, | |
| 2352 | − greedy: true | |
| 2353 | − }, | |
| 2354 | − { | |
| 2355 | − pattern: RegExp(/([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source), | |
| 2356 | − lookbehind: true, | |
| 2357 | − greedy: true | |
| 2358 | − }, | |
| 2359 | − ], | |
| 2360 | − 'method-definition': { | |
| 2361 | − pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/, | |
| 2362 | − lookbehind: true, | |
| 2363 | − inside: { | |
| 2364 | − 'function': /\b\w+$/, | |
| 2365 | − 'keyword': /^self\b/, | |
| 2366 | − 'class-name': /^\w+/, | |
| 2367 | − 'punctuation': /\./ | |
| 2368 | − } | |
| 2369 | − } | |
| 2370 | − }); | |
| 2371 | − | |
| 2372 | − Prism.languages.insertBefore('ruby', 'string', { | |
| 2373 | − 'string-literal': [ | |
| 2374 | − { | |
| 2375 | − pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression), | |
| 2376 | − greedy: true, | |
| 2377 | − inside: { | |
| 2378 | − 'interpolation': interpolation, | |
| 2379 | − 'string': /[\s\S]+/ | |
| 2380 | − } | |
| 2381 | − }, | |
| 2382 | − { | |
| 2383 | − pattern: /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/, | |
| 2384 | − greedy: true, | |
| 2385 | − inside: { | |
| 2386 | − 'interpolation': interpolation, | |
| 2387 | − 'string': /[\s\S]+/ | |
| 2388 | − } | |
| 2389 | − }, | |
| 2390 | − { | |
| 2391 | − pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, | |
| 2392 | − alias: 'heredoc-string', | |
| 2393 | − greedy: true, | |
| 2394 | − inside: { | |
| 2395 | − 'delimiter': { | |
| 2396 | − pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i, | |
| 2397 | − inside: { | |
| 2398 | − 'symbol': /\b\w+/, | |
| 2399 | − 'punctuation': /^<<[-~]?/ | |
| 2400 | − } | |
| 2401 | − }, | |
| 2402 | − 'interpolation': interpolation, | |
| 2403 | − 'string': /[\s\S]+/ | |
| 2404 | − } | |
| 2405 | − }, | |
| 2406 | − { | |
| 2407 | − pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, | |
| 2408 | − alias: 'heredoc-string', | |
| 2409 | − greedy: true, | |
| 2410 | − inside: { | |
| 2411 | − 'delimiter': { | |
| 2412 | − pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i, | |
| 2413 | − inside: { | |
| 2414 | − 'symbol': /\b\w+/, | |
| 2415 | − 'punctuation': /^<<[-~]?'|'$/, | |
| 2416 | − } | |
| 2417 | − }, | |
| 2418 | − 'string': /[\s\S]+/ | |
| 2419 | − } | |
| 2420 | − } | |
| 2421 | − ], | |
| 2422 | − 'command-literal': [ | |
| 2423 | − { | |
| 2424 | − pattern: RegExp(/%x/.source + percentExpression), | |
| 2425 | − greedy: true, | |
| 2426 | − inside: { | |
| 2427 | − 'interpolation': interpolation, | |
| 2428 | − 'command': { | |
| 2429 | − pattern: /[\s\S]+/, | |
| 2430 | − alias: 'string' | |
| 2431 | − } | |
| 2432 | − } | |
| 2433 | − }, | |
| 2434 | − { | |
| 2435 | − pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/, | |
| 2436 | − greedy: true, | |
| 2437 | − inside: { | |
| 2438 | − 'interpolation': interpolation, | |
| 2439 | − 'command': { | |
| 2440 | − pattern: /[\s\S]+/, | |
| 2441 | − alias: 'string' | |
| 2442 | − } | |
| 2443 | − } | |
| 2444 | − } | |
| 2445 | − ] | |
| 2446 | − }); | |
| 2447 | − | |
| 2448 | − delete Prism.languages.ruby.string; | |
| 2449 | − | |
| 2450 | − Prism.languages.insertBefore('ruby', 'number', { | |
| 2451 | − 'builtin': /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/, | |
| 2452 | − 'constant': /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/ | |
| 2453 | − }); | |
| 2454 | − | |
| 2455 | − Prism.languages.rb = Prism.languages.ruby; | |
| 2456 | −}(Prism)); | |
| 2424 | + Prism.languages.ruby = Prism.languages.extend("clike", { | |
| 2425 | + comment: { | |
| 2426 | + pattern: /#.*|^=begin\s[\s\S]*?^=end/m, | |
| 2427 | + greedy: true, | |
| 2428 | + }, | |
| 2429 | + "class-name": { | |
| 2430 | + pattern: | |
| 2431 | + /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/, | |
| 2432 | + lookbehind: true, | |
| 2433 | + inside: { | |
| 2434 | + punctuation: /[.\\]/, | |
| 2435 | + }, | |
| 2436 | + }, | |
| 2437 | + keyword: | |
| 2438 | + /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/, | |
| 2439 | + operator: | |
| 2440 | + /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/, | |
| 2441 | + punctuation: /[(){}[\].,;]/, | |
| 2442 | + }); | |
| 2443 | + | |
| 2444 | + Prism.languages.insertBefore("ruby", "operator", { | |
| 2445 | + "double-colon": { | |
| 2446 | + pattern: /::/, | |
| 2447 | + alias: "punctuation", | |
| 2448 | + }, | |
| 2449 | + }); | |
| 2450 | + | |
| 2451 | + var interpolation = { | |
| 2452 | + pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/, | |
| 2453 | + lookbehind: true, | |
| 2454 | + inside: { | |
| 2455 | + content: { | |
| 2456 | + pattern: /^(#\{)[\s\S]+(?=\}$)/, | |
| 2457 | + lookbehind: true, | |
| 2458 | + inside: Prism.languages.ruby, | |
| 2459 | + }, | |
| 2460 | + delimiter: { | |
| 2461 | + pattern: /^#\{|\}$/, | |
| 2462 | + alias: "punctuation", | |
| 2463 | + }, | |
| 2464 | + }, | |
| 2465 | + }; | |
| 2466 | + | |
| 2467 | + delete Prism.languages.ruby.function; | |
| 2468 | + | |
| 2469 | + var percentExpression = | |
| 2470 | + "(?:" + | |
| 2471 | + [ | |
| 2472 | + /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, | |
| 2473 | + /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source, | |
| 2474 | + /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source, | |
| 2475 | + /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source, | |
| 2476 | + /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source, | |
| 2477 | + ].join("|") + | |
| 2478 | + ")"; | |
| 2479 | + | |
| 2480 | + var symbolName = | |
| 2481 | + /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/ | |
| 2482 | + .source; | |
| 2483 | + | |
| 2484 | + Prism.languages.insertBefore("ruby", "keyword", { | |
| 2485 | + "regex-literal": [ | |
| 2486 | + { | |
| 2487 | + pattern: RegExp( | |
| 2488 | + /%r/.source + percentExpression + /[egimnosux]{0,6}/.source, | |
| 2489 | + ), | |
| 2490 | + greedy: true, | |
| 2491 | + inside: { | |
| 2492 | + interpolation: interpolation, | |
| 2493 | + regex: /[\s\S]+/, | |
| 2494 | + }, | |
| 2495 | + }, | |
| 2496 | + { | |
| 2497 | + pattern: | |
| 2498 | + /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/, | |
| 2499 | + lookbehind: true, | |
| 2500 | + greedy: true, | |
| 2501 | + inside: { | |
| 2502 | + interpolation: interpolation, | |
| 2503 | + regex: /[\s\S]+/, | |
| 2504 | + }, | |
| 2505 | + }, | |
| 2506 | + ], | |
| 2507 | + variable: /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, | |
| 2508 | + symbol: [ | |
| 2509 | + { | |
| 2510 | + pattern: RegExp(/(^|[^:]):/.source + symbolName), | |
| 2511 | + lookbehind: true, | |
| 2512 | + greedy: true, | |
| 2513 | + }, | |
| 2514 | + { | |
| 2515 | + pattern: RegExp( | |
| 2516 | + /([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source, | |
| 2517 | + ), | |
| 2518 | + lookbehind: true, | |
| 2519 | + greedy: true, | |
| 2520 | + }, | |
| 2521 | + ], | |
| 2522 | + "method-definition": { | |
| 2523 | + pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/, | |
| 2524 | + lookbehind: true, | |
| 2525 | + inside: { | |
| 2526 | + function: /\b\w+$/, | |
| 2527 | + keyword: /^self\b/, | |
| 2528 | + "class-name": /^\w+/, | |
| 2529 | + punctuation: /\./, | |
| 2530 | + }, | |
| 2531 | + }, | |
| 2532 | + }); | |
| 2533 | + | |
| 2534 | + Prism.languages.insertBefore("ruby", "string", { | |
| 2535 | + "string-literal": [ | |
| 2536 | + { | |
| 2537 | + pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression), | |
| 2538 | + greedy: true, | |
| 2539 | + inside: { | |
| 2540 | + interpolation: interpolation, | |
| 2541 | + string: /[\s\S]+/, | |
| 2542 | + }, | |
| 2543 | + }, | |
| 2544 | + { | |
| 2545 | + pattern: | |
| 2546 | + /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/, | |
| 2547 | + greedy: true, | |
| 2548 | + inside: { | |
| 2549 | + interpolation: interpolation, | |
| 2550 | + string: /[\s\S]+/, | |
| 2551 | + }, | |
| 2552 | + }, | |
| 2553 | + { | |
| 2554 | + pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, | |
| 2555 | + alias: "heredoc-string", | |
| 2556 | + greedy: true, | |
| 2557 | + inside: { | |
| 2558 | + delimiter: { | |
| 2559 | + pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i, | |
| 2560 | + inside: { | |
| 2561 | + symbol: /\b\w+/, | |
| 2562 | + punctuation: /^<<[-~]?/, | |
| 2563 | + }, | |
| 2564 | + }, | |
| 2565 | + interpolation: interpolation, | |
| 2566 | + string: /[\s\S]+/, | |
| 2567 | + }, | |
| 2568 | + }, | |
| 2569 | + { | |
| 2570 | + pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, | |
| 2571 | + alias: "heredoc-string", | |
| 2572 | + greedy: true, | |
| 2573 | + inside: { | |
| 2574 | + delimiter: { | |
| 2575 | + pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i, | |
| 2576 | + inside: { | |
| 2577 | + symbol: /\b\w+/, | |
| 2578 | + punctuation: /^<<[-~]?'|'$/, | |
| 2579 | + }, | |
| 2580 | + }, | |
| 2581 | + string: /[\s\S]+/, | |
| 2582 | + }, | |
| 2583 | + }, | |
| 2584 | + ], | |
| 2585 | + "command-literal": [ | |
| 2586 | + { | |
| 2587 | + pattern: RegExp(/%x/.source + percentExpression), | |
| 2588 | + greedy: true, | |
| 2589 | + inside: { | |
| 2590 | + interpolation: interpolation, | |
| 2591 | + command: { | |
| 2592 | + pattern: /[\s\S]+/, | |
| 2593 | + alias: "string", | |
| 2594 | + }, | |
| 2595 | + }, | |
| 2596 | + }, | |
| 2597 | + { | |
| 2598 | + pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/, | |
| 2599 | + greedy: true, | |
| 2600 | + inside: { | |
| 2601 | + interpolation: interpolation, | |
| 2602 | + command: { | |
| 2603 | + pattern: /[\s\S]+/, | |
| 2604 | + alias: "string", | |
| 2605 | + }, | |
| 2606 | + }, | |
| 2607 | + }, | |
| 2608 | + ], | |
| 2609 | + }); | |
| 2610 | + | |
| 2611 | + delete Prism.languages.ruby.string; | |
| 2612 | + | |
| 2613 | + Prism.languages.insertBefore("ruby", "number", { | |
| 2614 | + builtin: | |
| 2615 | + /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/, | |
| 2616 | + constant: /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/, | |
| 2617 | + }); | |
| 2618 | + | |
| 2619 | + Prism.languages.rb = Prism.languages.ruby; | |
| 2620 | +})(Prism); | |
| 2457 | 2621 | |
| 2458 | 2622 | (function (Prism) { |
| 2459 | − Prism.languages.crystal = Prism.languages.extend('ruby', { | |
| 2460 | − 'keyword': [ | |
| 2461 | − /\b(?:__DIR__|__END_LINE__|__FILE__|__LINE__|abstract|alias|annotation|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|ifdef|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|ptr|require|rescue|return|select|self|sizeof|struct|super|then|type|typeof|undef|uninitialized|union|unless|until|when|while|with|yield)\b/, | |
| 2462 | − { | |
| 2463 | − pattern: /(\.\s*)(?:is_a|responds_to)\?/, | |
| 2464 | − lookbehind: true | |
| 2465 | − } | |
| 2466 | − ], | |
| 2467 | − 'number': /\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[\da-fA-F_]*[\da-fA-F]|(?:\d(?:[\d_]*\d)?)(?:\.[\d_]*\d)?(?:[eE][+-]?[\d_]*\d)?)(?:_(?:[uif](?:8|16|32|64))?)?\b/, | |
| 2468 | − 'operator': [ | |
| 2469 | − /->/, | |
| 2470 | − Prism.languages.ruby.operator, | |
| 2471 | − ], | |
| 2472 | − 'punctuation': /[(){}[\].,;\\]/, | |
| 2473 | − }); | |
| 2474 | − | |
| 2475 | − Prism.languages.insertBefore('crystal', 'string-literal', { | |
| 2476 | − 'attribute': { | |
| 2477 | − pattern: /@\[.*?\]/, | |
| 2478 | − inside: { | |
| 2479 | − 'delimiter': { | |
| 2480 | − pattern: /^@\[|\]$/, | |
| 2481 | − alias: 'punctuation' | |
| 2482 | − }, | |
| 2483 | − 'attribute': { | |
| 2484 | − pattern: /^(\s*)\w+/, | |
| 2485 | − lookbehind: true, | |
| 2486 | − alias: 'class-name' | |
| 2487 | − }, | |
| 2488 | − 'args': { | |
| 2489 | − pattern: /\S(?:[\s\S]*\S)?/, | |
| 2490 | − inside: Prism.languages.crystal | |
| 2491 | − }, | |
| 2492 | − } | |
| 2493 | − }, | |
| 2494 | − 'expansion': { | |
| 2495 | − pattern: /\{(?:\{.*?\}|%.*?%)\}/, | |
| 2496 | − inside: { | |
| 2497 | − 'content': { | |
| 2498 | − pattern: /^(\{.)[\s\S]+(?=.\}$)/, | |
| 2499 | − lookbehind: true, | |
| 2500 | − inside: Prism.languages.crystal | |
| 2501 | − }, | |
| 2502 | − 'delimiter': { | |
| 2503 | − pattern: /^\{[\{%]|[\}%]\}$/, | |
| 2504 | − alias: 'operator' | |
| 2505 | − } | |
| 2506 | − } | |
| 2507 | − }, | |
| 2508 | − 'char': { | |
| 2509 | − pattern: /'(?:[^\\\r\n]{1,2}|\\(?:.|u(?:[A-Fa-f0-9]{1,4}|\{[A-Fa-f0-9]{1,6}\})))'/, | |
| 2510 | − greedy: true | |
| 2511 | − } | |
| 2512 | − }); | |
| 2513 | − | |
| 2514 | −}(Prism)); | |
| 2515 | − | |
| 2516 | −Prism.languages.d = Prism.languages.extend('clike', { | |
| 2517 | − 'comment': [ | |
| 2518 | − { | |
| 2519 | − // Shebang | |
| 2520 | − pattern: /^\s*#!.+/, | |
| 2521 | − greedy: true | |
| 2522 | − }, | |
| 2523 | − { | |
| 2524 | − pattern: RegExp(/(^|[^\\])/.source + '(?:' + [ | |
| 2525 | − // /+ comment +/ | |
| 2526 | − // Allow one level of nesting | |
| 2527 | − /\/\+(?:\/\+(?:[^+]|\+(?!\/))*\+\/|(?!\/\+)[\s\S])*?\+\//.source, | |
| 2528 | − // // comment | |
| 2529 | − /\/\/.*/.source, | |
| 2530 | − // /* comment */ | |
| 2531 | − /\/\*[\s\S]*?\*\//.source | |
| 2532 | − ].join('|') + ')'), | |
| 2533 | − lookbehind: true, | |
| 2534 | − greedy: true | |
| 2535 | − } | |
| 2536 | − ], | |
| 2537 | − 'string': [ | |
| 2538 | − { | |
| 2539 | − pattern: RegExp([ | |
| 2540 | − // r"", x"" | |
| 2541 | − /\b[rx]"(?:\\[\s\S]|[^\\"])*"[cwd]?/.source, | |
| 2542 | − | |
| 2543 | − // q"[]", q"()", q"<>", q"{}" | |
| 2544 | − /\bq"(?:\[[\s\S]*?\]|\([\s\S]*?\)|<[\s\S]*?>|\{[\s\S]*?\})"/.source, | |
| 2545 | − | |
| 2546 | − // q"IDENT | |
| 2547 | − // ... | |
| 2548 | − // IDENT" | |
| 2549 | − /\bq"((?!\d)\w+)$[\s\S]*?^\1"/.source, | |
| 2550 | − | |
| 2551 | − // q"//", q"||", etc. | |
| 2552 | − // eslint-disable-next-line regexp/strict | |
| 2553 | − /\bq"(.)[\s\S]*?\2"/.source, | |
| 2554 | − | |
6302 more lines aren’t shown here.
| @@ -10,2457 +10,2776 @@ · 9 unmodified lines | ||
| 10 | 10 | * |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | −(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Raven = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | |
| 14 | −function RavenConfigError(message) { | |
| 15 | − this.name = 'RavenConfigError'; | |
| 16 | − this.message = message; | |
| 17 | −} | |
| 18 | −RavenConfigError.prototype = new Error(); | |
| 19 | −RavenConfigError.prototype.constructor = RavenConfigError; | |
| 20 | − | |
| 21 | −module.exports = RavenConfigError; | |
| 22 | − | |
| 23 | −},{}],2:[function(_dereq_,module,exports){ | |
| 24 | −var wrapMethod = function(console, level, callback) { | |
| 25 | − var originalConsoleLevel = console[level]; | |
| 26 | − var originalConsole = console; | |
| 27 | − | |
| 28 | − if (!(level in console)) { | |
| 29 | − return; | |
| 13 | +(function (f) { | |
| 14 | + if (typeof exports === "object" && typeof module !== "undefined") { | |
| 15 | + module.exports = f(); | |
| 16 | + } else if (typeof define === "function" && define.amd) { | |
| 17 | + define([], f); | |
| 18 | + } else { | |
| 19 | + var g; | |
| 20 | + if (typeof window !== "undefined") { | |
| 21 | + g = window; | |
| 22 | + } else if (typeof global !== "undefined") { | |
| 23 | + g = global; | |
| 24 | + } else if (typeof self !== "undefined") { | |
| 25 | + g = self; | |
| 26 | + } else { | |
| 27 | + g = this; | |
| 28 | + } | |
| 29 | + g.Raven = f(); | |
| 30 | 30 | } |
| 31 | +})(function () { | |
| 32 | + var define, module, exports; | |
| 33 | + return (function e(t, n, r) { | |
| 34 | + function s(o, u) { | |
| 35 | + if (!n[o]) { | |
| 36 | + if (!t[o]) { | |
| 37 | + var a = typeof require == "function" && require; | |
| 38 | + if (!u && a) return a(o, !0); | |
| 39 | + if (i) return i(o, !0); | |
| 40 | + var f = new Error("Cannot find module '" + o + "'"); | |
| 41 | + throw ((f.code = "MODULE_NOT_FOUND"), f); | |
| 42 | + } | |
| 43 | + var l = (n[o] = { exports: {} }); | |
| 44 | + t[o][0].call( | |
| 45 | + l.exports, | |
| 46 | + function (e) { | |
| 47 | + var n = t[o][1][e]; | |
| 48 | + return s(n ? n : e); | |
| 49 | + }, | |
| 50 | + l, | |
| 51 | + l.exports, | |
| 52 | + e, | |
| 53 | + t, | |
| 54 | + n, | |
| 55 | + r, | |
| 56 | + ); | |
| 57 | + } | |
| 58 | + return n[o].exports; | |
| 59 | + } | |
| 60 | + var i = typeof require == "function" && require; | |
| 61 | + for (var o = 0; o < r.length; o++) s(r[o]); | |
| 62 | + return s; | |
| 63 | + })( | |
| 64 | + { | |
| 65 | + 1: [ | |
| 66 | + function (_dereq_, module, exports) { | |
| 67 | + function RavenConfigError(message) { | |
| 68 | + this.name = "RavenConfigError"; | |
| 69 | + this.message = message; | |
| 70 | + } | |
| 71 | + RavenConfigError.prototype = new Error(); | |
| 72 | + RavenConfigError.prototype.constructor = RavenConfigError; | |
| 31 | 73 | |
| 32 | − var sentryLevel = level === 'warn' ? 'warning' : level; | |
| 74 | + module.exports = RavenConfigError; | |
| 75 | + }, | |
| 76 | + {}, | |
| 77 | + ], | |
| 78 | + 2: [ | |
| 79 | + function (_dereq_, module, exports) { | |
| 80 | + var wrapMethod = function (console, level, callback) { | |
| 81 | + var originalConsoleLevel = console[level]; | |
| 82 | + var originalConsole = console; | |
| 83 | + | |
| 84 | + if (!(level in console)) { | |
| 85 | + return; | |
| 86 | + } | |
| 33 | 87 | |
| 34 | − console[level] = function() { | |
| 35 | − var args = [].slice.call(arguments); | |
| 88 | + var sentryLevel = level === "warn" ? "warning" : level; | |
| 36 | 89 | |
| 37 | − var msg = '' + args.join(' '); | |
| 38 | − var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}}; | |
| 90 | + console[level] = function () { | |
| 91 | + var args = [].slice.call(arguments); | |
| 39 | 92 | |
| 40 | − if (level === 'assert') { | |
| 41 | − if (args[0] === false) { | |
| 42 | − // Default browsers message | |
| 43 | − msg = 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert'); | |
| 44 | − data.extra.arguments = args.slice(1); | |
| 45 | − callback && callback(msg, data); | |
| 46 | − } | |
| 47 | − } else { | |
| 48 | − callback && callback(msg, data); | |
| 49 | − } | |
| 93 | + var msg = "" + args.join(" "); | |
| 94 | + var data = { | |
| 95 | + level: sentryLevel, | |
| 96 | + logger: "console", | |
| 97 | + extra: { arguments: args }, | |
| 98 | + }; | |
| 50 | 99 | |
| 51 | − // this fails for some browsers. :( | |
| 52 | − if (originalConsoleLevel) { | |
| 53 | − // IE9 doesn't allow calling apply on console functions directly | |
| 54 | − // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193 | |
| 55 | − Function.prototype.apply.call(originalConsoleLevel, originalConsole, args); | |
| 56 | − } | |
| 57 | − }; | |
| 58 | −}; | |
| 59 | − | |
| 60 | −module.exports = { | |
| 61 | − wrapMethod: wrapMethod | |
| 62 | −}; | |
| 63 | − | |
| 64 | −},{}],3:[function(_dereq_,module,exports){ | |
| 65 | −(function (global){ | |
| 66 | −/*global XDomainRequest:false */ | |
| 67 | − | |
| 68 | −var TraceKit = _dereq_(6); | |
| 69 | −var stringify = _dereq_(7); | |
| 70 | −var RavenConfigError = _dereq_(1); | |
| 71 | − | |
| 72 | −var utils = _dereq_(5); | |
| 73 | −var isError = utils.isError; | |
| 74 | −var isObject = utils.isObject; | |
| 75 | −var isErrorEvent = utils.isErrorEvent; | |
| 76 | −var isUndefined = utils.isUndefined; | |
| 77 | −var isFunction = utils.isFunction; | |
| 78 | −var isString = utils.isString; | |
| 79 | −var isArray = utils.isArray; | |
| 80 | −var isEmptyObject = utils.isEmptyObject; | |
| 81 | −var each = utils.each; | |
| 82 | −var objectMerge = utils.objectMerge; | |
| 83 | −var truncate = utils.truncate; | |
| 84 | −var objectFrozen = utils.objectFrozen; | |
| 85 | −var hasKey = utils.hasKey; | |
| 86 | −var joinRegExp = utils.joinRegExp; | |
| 87 | −var urlencode = utils.urlencode; | |
| 88 | −var uuid4 = utils.uuid4; | |
| 89 | −var htmlTreeAsString = utils.htmlTreeAsString; | |
| 90 | −var isSameException = utils.isSameException; | |
| 91 | −var isSameStacktrace = utils.isSameStacktrace; | |
| 92 | −var parseUrl = utils.parseUrl; | |
| 93 | −var fill = utils.fill; | |
| 94 | − | |
| 95 | −var wrapConsoleMethod = _dereq_(2).wrapMethod; | |
| 96 | − | |
| 97 | −var dsnKeys = 'source protocol user pass host port path'.split(' '), | |
| 98 | − dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/; | |
| 99 | − | |
| 100 | −function now() { | |
| 101 | − return +new Date(); | |
| 102 | −} | |
| 103 | − | |
| 104 | −// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785) | |
| 105 | −var _window = | |
| 106 | − typeof window !== 'undefined' | |
| 107 | − ? window | |
| 108 | − : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
| 109 | −var _document = _window.document; | |
| 110 | −var _navigator = _window.navigator; | |
| 111 | − | |
| 112 | −function keepOriginalCallback(original, callback) { | |
| 113 | − return isFunction(callback) | |
| 114 | − ? function(data) { | |
| 115 | − return callback(data, original); | |
| 116 | − } | |
| 117 | − : callback; | |
| 118 | −} | |
| 119 | − | |
| 120 | −// First, check for JSON support | |
| 121 | −// If there is no JSON, we no-op the core features of Raven | |
| 122 | −// since JSON is required to encode the payload | |
| 123 | −function Raven() { | |
| 124 | − this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify); | |
| 125 | − // Raven can run in contexts where there's no document (react-native) | |
| 126 | − this._hasDocument = !isUndefined(_document); | |
| 127 | − this._hasNavigator = !isUndefined(_navigator); | |
| 128 | − this._lastCapturedException = null; | |
| 129 | − this._lastData = null; | |
| 130 | − this._lastEventId = null; | |
| 131 | − this._globalServer = null; | |
| 132 | − this._globalKey = null; | |
| 133 | − this._globalProject = null; | |
| 134 | − this._globalContext = {}; | |
| 135 | − this._globalOptions = { | |
| 136 | − logger: 'javascript', | |
| 137 | − ignoreErrors: [], | |
| 138 | − ignoreUrls: [], | |
| 139 | − whitelistUrls: [], | |
| 140 | − includePaths: [], | |
| 141 | − collectWindowErrors: true, | |
| 142 | − maxMessageLength: 0, | |
| 143 | − | |
| 144 | − // By default, truncates URL values to 250 chars | |
| 145 | − maxUrlLength: 250, | |
| 146 | − stackTraceLimit: 50, | |
| 147 | − autoBreadcrumbs: true, | |
| 148 | − instrument: true, | |
| 149 | − sampleRate: 1 | |
| 150 | − }; | |
| 151 | − this._ignoreOnError = 0; | |
| 152 | − this._isRavenInstalled = false; | |
| 153 | − this._originalErrorStackTraceLimit = Error.stackTraceLimit; | |
| 154 | − // capture references to window.console *and* all its methods first | |
| 155 | − // before the console plugin has a chance to monkey patch | |
| 156 | − this._originalConsole = _window.console || {}; | |
| 157 | − this._originalConsoleMethods = {}; | |
| 158 | − this._plugins = []; | |
| 159 | − this._startTime = now(); | |
| 160 | − this._wrappedBuiltIns = []; | |
| 161 | − this._breadcrumbs = []; | |
| 162 | − this._lastCapturedEvent = null; | |
| 163 | − this._keypressTimeout; | |
| 164 | − this._location = _window.location; | |
| 165 | − this._lastHref = this._location && this._location.href; | |
| 166 | − this._resetBackoff(); | |
| 167 | − | |
| 168 | − // eslint-disable-next-line guard-for-in | |
| 169 | − for (var method in this._originalConsole) { | |
| 170 | − this._originalConsoleMethods[method] = this._originalConsole[method]; | |
| 171 | − } | |
| 172 | −} | |
| 100 | + if (level === "assert") { | |
| 101 | + if (args[0] === false) { | |
| 102 | + // Default browsers message | |
| 103 | + msg = | |
| 104 | + "Assertion failed: " + | |
| 105 | + (args.slice(1).join(" ") || "console.assert"); | |
| 106 | + data.extra.arguments = args.slice(1); | |
| 107 | + callback && callback(msg, data); | |
| 108 | + } | |
| 109 | + } else { | |
| 110 | + callback && callback(msg, data); | |
| 111 | + } | |
| 173 | 112 | |
| 174 | −/* | |
| 175 | − * The core Raven singleton | |
| 176 | − * | |
| 177 | − * @this {Raven} | |
| 178 | − */ | |
| 113 | + // this fails for some browsers. :( | |
| 114 | + if (originalConsoleLevel) { | |
| 115 | + // IE9 doesn't allow calling apply on console functions directly | |
| 116 | + // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193 | |
| 117 | + Function.prototype.apply.call( | |
| 118 | + originalConsoleLevel, | |
| 119 | + originalConsole, | |
| 120 | + args, | |
| 121 | + ); | |
| 122 | + } | |
| 123 | + }; | |
| 124 | + }; | |
| 179 | 125 | |
| 180 | −Raven.prototype = { | |
| 181 | − // Hardcode version string so that raven source can be loaded directly via | |
| 182 | − // webpack (using a build step causes webpack #1617). Grunt verifies that | |
| 183 | − // this value matches package.json during build. | |
| 184 | − // See: https://github.com/getsentry/raven-js/issues/465 | |
| 185 | − VERSION: '3.20.1', | |
| 186 | − | |
| 187 | − debug: false, | |
| 188 | − | |
| 189 | − TraceKit: TraceKit, // alias to TraceKit | |
| 190 | − | |
| 191 | − /* | |
| 192 | − * Configure Raven with a DSN and extra options | |
| 193 | − * | |
| 194 | − * @param {string} dsn The public Sentry DSN | |
| 195 | − * @param {object} options Set of global options [optional] | |
| 196 | − * @return {Raven} | |
| 197 | − */ | |
| 198 | − config: function(dsn, options) { | |
| 199 | − var self = this; | |
| 200 | − | |
| 201 | − if (self._globalServer) { | |
| 202 | − this._logDebug('error', 'Error: Raven has already been configured'); | |
| 203 | − return self; | |
| 204 | − } | |
| 205 | − if (!dsn) return self; | |
| 206 | − | |
| 207 | − var globalOptions = self._globalOptions; | |
| 208 | − | |
| 209 | − // merge in options | |
| 210 | − if (options) { | |
| 211 | − each(options, function(key, value) { | |
| 212 | − // tags and extra are special and need to be put into context | |
| 213 | − if (key === 'tags' || key === 'extra' || key === 'user') { | |
| 214 | − self._globalContext[key] = value; | |
| 215 | − } else { | |
| 216 | − globalOptions[key] = value; | |
| 217 | − } | |
| 218 | − }); | |
| 219 | − } | |
| 126 | + module.exports = { | |
| 127 | + wrapMethod: wrapMethod, | |
| 128 | + }; | |
| 129 | + }, | |
| 130 | + {}, | |
| 131 | + ], | |
| 132 | + 3: [ | |
| 133 | + function (_dereq_, module, exports) { | |
| 134 | + (function (global) { | |
| 135 | + /*global XDomainRequest:false */ | |
| 136 | + | |
| 137 | + var TraceKit = _dereq_(6); | |
| 138 | + var stringify = _dereq_(7); | |
| 139 | + var RavenConfigError = _dereq_(1); | |
| 140 | + | |
| 141 | + var utils = _dereq_(5); | |
| 142 | + var isError = utils.isError; | |
| 143 | + var isObject = utils.isObject; | |
| 144 | + var isErrorEvent = utils.isErrorEvent; | |
| 145 | + var isUndefined = utils.isUndefined; | |
| 146 | + var isFunction = utils.isFunction; | |
| 147 | + var isString = utils.isString; | |
| 148 | + var isArray = utils.isArray; | |
| 149 | + var isEmptyObject = utils.isEmptyObject; | |
| 150 | + var each = utils.each; | |
| 151 | + var objectMerge = utils.objectMerge; | |
| 152 | + var truncate = utils.truncate; | |
| 153 | + var objectFrozen = utils.objectFrozen; | |
| 154 | + var hasKey = utils.hasKey; | |
| 155 | + var joinRegExp = utils.joinRegExp; | |
| 156 | + var urlencode = utils.urlencode; | |
| 157 | + var uuid4 = utils.uuid4; | |
| 158 | + var htmlTreeAsString = utils.htmlTreeAsString; | |
| 159 | + var isSameException = utils.isSameException; | |
| 160 | + var isSameStacktrace = utils.isSameStacktrace; | |
| 161 | + var parseUrl = utils.parseUrl; | |
| 162 | + var fill = utils.fill; | |
| 163 | + | |
| 164 | + var wrapConsoleMethod = _dereq_(2).wrapMethod; | |
| 165 | + | |
| 166 | + var dsnKeys = "source protocol user pass host port path".split(" "), | |
| 167 | + dsnPattern = | |
| 168 | + /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/; | |
| 169 | + | |
| 170 | + function now() { | |
| 171 | + return +new Date(); | |
| 172 | + } | |
| 220 | 173 | |
| 221 | − self.setDSN(dsn); | |
| 222 | − | |
| 223 | − // "Script error." is hard coded into browsers for errors that it can't read. | |
| 224 | − // this is the result of a script being pulled in from an external domain and CORS. | |
| 225 | − globalOptions.ignoreErrors.push(/^Script error\.?$/); | |
| 226 | − globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/); | |
| 227 | − | |
| 228 | − // join regexp rules into one big rule | |
| 229 | − globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors); | |
| 230 | − globalOptions.ignoreUrls = globalOptions.ignoreUrls.length | |
| 231 | − ? joinRegExp(globalOptions.ignoreUrls) | |
| 232 | − : false; | |
| 233 | − globalOptions.whitelistUrls = globalOptions.whitelistUrls.length | |
| 234 | − ? joinRegExp(globalOptions.whitelistUrls) | |
| 235 | − : false; | |
| 236 | − globalOptions.includePaths = joinRegExp(globalOptions.includePaths); | |
| 237 | − globalOptions.maxBreadcrumbs = Math.max( | |
| 238 | − 0, | |
| 239 | − Math.min(globalOptions.maxBreadcrumbs || 100, 100) | |
| 240 | − ); // default and hard limit is 100 | |
| 241 | − | |
| 242 | − var autoBreadcrumbDefaults = { | |
| 243 | − xhr: true, | |
| 244 | − console: true, | |
| 245 | − dom: true, | |
| 246 | − location: true, | |
| 247 | − sentry: true | |
| 248 | − }; | |
| 249 | − | |
| 250 | − var autoBreadcrumbs = globalOptions.autoBreadcrumbs; | |
| 251 | − if ({}.toString.call(autoBreadcrumbs) === '[object Object]') { | |
| 252 | − autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs); | |
| 253 | − } else if (autoBreadcrumbs !== false) { | |
| 254 | − autoBreadcrumbs = autoBreadcrumbDefaults; | |
| 255 | − } | |
| 256 | − globalOptions.autoBreadcrumbs = autoBreadcrumbs; | |
| 174 | + // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785) | |
| 175 | + var _window = | |
| 176 | + typeof window !== "undefined" | |
| 177 | + ? window | |
| 178 | + : typeof global !== "undefined" | |
| 179 | + ? global | |
| 180 | + : typeof self !== "undefined" | |
| 181 | + ? self | |
| 182 | + : {}; | |
| 183 | + var _document = _window.document; | |
| 184 | + var _navigator = _window.navigator; | |
| 185 | + | |
| 186 | + function keepOriginalCallback(original, callback) { | |
| 187 | + return isFunction(callback) | |
| 188 | + ? function (data) { | |
| 189 | + return callback(data, original); | |
| 190 | + } | |
| 191 | + : callback; | |
| 192 | + } | |
| 257 | 193 | |
| 258 | − var instrumentDefaults = { | |
| 259 | − tryCatch: true | |
| 260 | − }; | |
| 194 | + // First, check for JSON support | |
| 195 | + // If there is no JSON, we no-op the core features of Raven | |
| 196 | + // since JSON is required to encode the payload | |
| 197 | + function Raven() { | |
| 198 | + this._hasJSON = !!(typeof JSON === "object" && JSON.stringify); | |
| 199 | + // Raven can run in contexts where there's no document (react-native) | |
| 200 | + this._hasDocument = !isUndefined(_document); | |
| 201 | + this._hasNavigator = !isUndefined(_navigator); | |
| 202 | + this._lastCapturedException = null; | |
| 203 | + this._lastData = null; | |
| 204 | + this._lastEventId = null; | |
| 205 | + this._globalServer = null; | |
| 206 | + this._globalKey = null; | |
| 207 | + this._globalProject = null; | |
| 208 | + this._globalContext = {}; | |
| 209 | + this._globalOptions = { | |
| 210 | + logger: "javascript", | |
| 211 | + ignoreErrors: [], | |
| 212 | + ignoreUrls: [], | |
| 213 | + whitelistUrls: [], | |
| 214 | + includePaths: [], | |
| 215 | + collectWindowErrors: true, | |
| 216 | + maxMessageLength: 0, | |
| 217 | + | |
| 218 | + // By default, truncates URL values to 250 chars | |
| 219 | + maxUrlLength: 250, | |
| 220 | + stackTraceLimit: 50, | |
| 221 | + autoBreadcrumbs: true, | |
| 222 | + instrument: true, | |
| 223 | + sampleRate: 1, | |
| 224 | + }; | |
| 225 | + this._ignoreOnError = 0; | |
| 226 | + this._isRavenInstalled = false; | |
| 227 | + this._originalErrorStackTraceLimit = Error.stackTraceLimit; | |
| 228 | + // capture references to window.console *and* all its methods first | |
| 229 | + // before the console plugin has a chance to monkey patch | |
| 230 | + this._originalConsole = _window.console || {}; | |
| 231 | + this._originalConsoleMethods = {}; | |
| 232 | + this._plugins = []; | |
| 233 | + this._startTime = now(); | |
| 234 | + this._wrappedBuiltIns = []; | |
| 235 | + this._breadcrumbs = []; | |
| 236 | + this._lastCapturedEvent = null; | |
| 237 | + this._keypressTimeout; | |
| 238 | + this._location = _window.location; | |
| 239 | + this._lastHref = this._location && this._location.href; | |
| 240 | + this._resetBackoff(); | |
| 241 | + | |
| 242 | + // eslint-disable-next-line guard-for-in | |
| 243 | + for (var method in this._originalConsole) { | |
| 244 | + this._originalConsoleMethods[method] = | |
| 245 | + this._originalConsole[method]; | |
| 246 | + } | |
| 247 | + } | |
| 261 | 248 | |
| 262 | − var instrument = globalOptions.instrument; | |
| 263 | − if ({}.toString.call(instrument) === '[object Object]') { | |
| 264 | − instrument = objectMerge(instrumentDefaults, instrument); | |
| 265 | − } else if (instrument !== false) { | |
| 266 | − instrument = instrumentDefaults; | |
| 267 | − } | |
| 268 | − globalOptions.instrument = instrument; | |
| 269 | − | |
| 270 | − TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors; | |
| 271 | − | |
| 272 | − // return for chaining | |
| 273 | − return self; | |
| 274 | − }, | |
| 275 | − | |
| 276 | − /* | |
| 277 | − * Installs a global window.onerror error handler | |
| 278 | − * to capture and report uncaught exceptions. | |
| 279 | − * At this point, install() is required to be called due | |
| 280 | − * to the way TraceKit is set up. | |
| 281 | − * | |
| 282 | − * @return {Raven} | |
| 283 | − */ | |
| 284 | − install: function() { | |
| 285 | − var self = this; | |
| 286 | − if (self.isSetup() && !self._isRavenInstalled) { | |
| 287 | − TraceKit.report.subscribe(function() { | |
| 288 | − self._handleOnErrorStackInfo.apply(self, arguments); | |
| 289 | − }); | |
| 290 | − | |
| 291 | − self._patchFunctionToString(); | |
| 292 | − | |
| 293 | − if (self._globalOptions.instrument && self._globalOptions.instrument.tryCatch) { | |
| 294 | − self._instrumentTryCatch(); | |
| 295 | − } | |
| 249 | + /* | |
| 250 | + * The core Raven singleton | |
| 251 | + * | |
| 252 | + * @this {Raven} | |
| 253 | + */ | |
| 254 | + | |
| 255 | + Raven.prototype = { | |
| 256 | + // Hardcode version string so that raven source can be loaded directly via | |
| 257 | + // webpack (using a build step causes webpack #1617). Grunt verifies that | |
| 258 | + // this value matches package.json during build. | |
| 259 | + // See: https://github.com/getsentry/raven-js/issues/465 | |
| 260 | + VERSION: "3.20.1", | |
| 261 | + | |
| 262 | + debug: false, | |
| 263 | + | |
| 264 | + TraceKit: TraceKit, // alias to TraceKit | |
| 265 | + | |
| 266 | + /* | |
| 267 | + * Configure Raven with a DSN and extra options | |
| 268 | + * | |
| 269 | + * @param {string} dsn The public Sentry DSN | |
| 270 | + * @param {object} options Set of global options [optional] | |
| 271 | + * @return {Raven} | |
| 272 | + */ | |
| 273 | + config: function (dsn, options) { | |
| 274 | + var self = this; | |
| 275 | + | |
| 276 | + if (self._globalServer) { | |
| 277 | + this._logDebug( | |
| 278 | + "error", | |
| 279 | + "Error: Raven has already been configured", | |
| 280 | + ); | |
| 281 | + return self; | |
| 282 | + } | |
| 283 | + if (!dsn) return self; | |
| 284 | + | |
| 285 | + var globalOptions = self._globalOptions; | |
| 286 | + | |
| 287 | + // merge in options | |
| 288 | + if (options) { | |
| 289 | + each(options, function (key, value) { | |
| 290 | + // tags and extra are special and need to be put into context | |
| 291 | + if (key === "tags" || key === "extra" || key === "user") { | |
| 292 | + self._globalContext[key] = value; | |
| 293 | + } else { | |
| 294 | + globalOptions[key] = value; | |
| 295 | + } | |
| 296 | + }); | |
| 297 | + } | |
| 296 | 298 | |
| 297 | − if (self._globalOptions.autoBreadcrumbs) self._instrumentBreadcrumbs(); | |
| 299 | + self.setDSN(dsn); | |
| 300 | + | |
| 301 | + // "Script error." is hard coded into browsers for errors that it can't read. | |
| 302 | + // this is the result of a script being pulled in from an external domain and CORS. | |
| 303 | + globalOptions.ignoreErrors.push(/^Script error\.?$/); | |
| 304 | + globalOptions.ignoreErrors.push( | |
| 305 | + /^Javascript error: Script error\.? on line 0$/, | |
| 306 | + ); | |
| 307 | + | |
| 308 | + // join regexp rules into one big rule | |
| 309 | + globalOptions.ignoreErrors = joinRegExp( | |
| 310 | + globalOptions.ignoreErrors, | |
| 311 | + ); | |
| 312 | + globalOptions.ignoreUrls = globalOptions.ignoreUrls.length | |
| 313 | + ? joinRegExp(globalOptions.ignoreUrls) | |
| 314 | + : false; | |
| 315 | + globalOptions.whitelistUrls = globalOptions.whitelistUrls.length | |
| 316 | + ? joinRegExp(globalOptions.whitelistUrls) | |
| 317 | + : false; | |
| 318 | + globalOptions.includePaths = joinRegExp( | |
| 319 | + globalOptions.includePaths, | |
| 320 | + ); | |
| 321 | + globalOptions.maxBreadcrumbs = Math.max( | |
| 322 | + 0, | |
| 323 | + Math.min(globalOptions.maxBreadcrumbs || 100, 100), | |
| 324 | + ); // default and hard limit is 100 | |
| 325 | + | |
| 326 | + var autoBreadcrumbDefaults = { | |
| 327 | + xhr: true, | |
| 328 | + console: true, | |
| 329 | + dom: true, | |
| 330 | + location: true, | |
| 331 | + sentry: true, | |
| 332 | + }; | |
| 298 | 333 | |
| 299 | − // Install all of the plugins | |
| 300 | − self._drainPlugins(); | |
| 334 | + var autoBreadcrumbs = globalOptions.autoBreadcrumbs; | |
| 335 | + if ({}.toString.call(autoBreadcrumbs) === "[object Object]") { | |
| 336 | + autoBreadcrumbs = objectMerge( | |
| 337 | + autoBreadcrumbDefaults, | |
| 338 | + autoBreadcrumbs, | |
| 339 | + ); | |
| 340 | + } else if (autoBreadcrumbs !== false) { | |
| 341 | + autoBreadcrumbs = autoBreadcrumbDefaults; | |
| 342 | + } | |
| 343 | + globalOptions.autoBreadcrumbs = autoBreadcrumbs; | |
| 301 | 344 | |
| 302 | − self._isRavenInstalled = true; | |
| 303 | − } | |
| 345 | + var instrumentDefaults = { | |
| 346 | + tryCatch: true, | |
| 347 | + }; | |
| 304 | 348 | |
| 305 | − Error.stackTraceLimit = self._globalOptions.stackTraceLimit; | |
| 306 | − return this; | |
| 307 | − }, | |
| 308 | − | |
| 309 | − /* | |
| 310 | − * Set the DSN (can be called multiple time unlike config) | |
| 311 | − * | |
| 312 | − * @param {string} dsn The public Sentry DSN | |
| 313 | − */ | |
| 314 | − setDSN: function(dsn) { | |
| 315 | − var self = this, | |
| 316 | − uri = self._parseDSN(dsn), | |
| 317 | − lastSlash = uri.path.lastIndexOf('/'), | |
| 318 | − path = uri.path.substr(1, lastSlash); | |
| 319 | − | |
| 320 | − self._dsn = dsn; | |
| 321 | − self._globalKey = uri.user; | |
| 322 | − self._globalSecret = uri.pass && uri.pass.substr(1); | |
| 323 | − self._globalProject = uri.path.substr(lastSlash + 1); | |
| 324 | − | |
| 325 | − self._globalServer = self._getGlobalServer(uri); | |
| 326 | − | |
| 327 | − self._globalEndpoint = | |
| 328 | − self._globalServer + '/' + path + 'api/' + self._globalProject + '/store/'; | |
| 329 | − | |
| 330 | − // Reset backoff state since we may be pointing at a | |
| 331 | − // new project/server | |
| 332 | − this._resetBackoff(); | |
| 333 | − }, | |
| 334 | − | |
| 335 | − /* | |
| 336 | − * Wrap code within a context so Raven can capture errors | |
| 337 | − * reliably across domains that is executed immediately. | |
| 338 | − * | |
| 339 | − * @param {object} options A specific set of options for this context [optional] | |
| 340 | − * @param {function} func The callback to be immediately executed within the context | |
| 341 | − * @param {array} args An array of arguments to be called with the callback [optional] | |
| 342 | − */ | |
| 343 | − context: function(options, func, args) { | |
| 344 | − if (isFunction(options)) { | |
| 345 | − args = func || []; | |
| 346 | − func = options; | |
| 347 | − options = undefined; | |
| 348 | − } | |
| 349 | + var instrument = globalOptions.instrument; | |
| 350 | + if ({}.toString.call(instrument) === "[object Object]") { | |
| 351 | + instrument = objectMerge(instrumentDefaults, instrument); | |
| 352 | + } else if (instrument !== false) { | |
| 353 | + instrument = instrumentDefaults; | |
| 354 | + } | |
| 355 | + globalOptions.instrument = instrument; | |
| 356 | + | |
| 357 | + TraceKit.collectWindowErrors = | |
| 358 | + !!globalOptions.collectWindowErrors; | |
| 359 | + | |
| 360 | + // return for chaining | |
| 361 | + return self; | |
| 362 | + }, | |
| 363 | + | |
| 364 | + /* | |
| 365 | + * Installs a global window.onerror error handler | |
| 366 | + * to capture and report uncaught exceptions. | |
| 367 | + * At this point, install() is required to be called due | |
| 368 | + * to the way TraceKit is set up. | |
| 369 | + * | |
| 370 | + * @return {Raven} | |
| 371 | + */ | |
| 372 | + install: function () { | |
| 373 | + var self = this; | |
| 374 | + if (self.isSetup() && !self._isRavenInstalled) { | |
| 375 | + TraceKit.report.subscribe(function () { | |
| 376 | + self._handleOnErrorStackInfo.apply(self, arguments); | |
| 377 | + }); | |
| 378 | + | |
| 379 | + self._patchFunctionToString(); | |
| 380 | + | |
| 381 | + if ( | |
| 382 | + self._globalOptions.instrument && | |
| 383 | + self._globalOptions.instrument.tryCatch | |
| 384 | + ) { | |
| 385 | + self._instrumentTryCatch(); | |
| 386 | + } | |
| 349 | 387 | |
| 350 | − return this.wrap(options, func).apply(this, args); | |
| 351 | − }, | |
| 352 | − | |
| 353 | − /* | |
| 354 | − * Wrap code within a context and returns back a new function to be executed | |
| 355 | − * | |
| 356 | − * @param {object} options A specific set of options for this context [optional] | |
| 357 | − * @param {function} func The function to be wrapped in a new context | |
| 358 | − * @param {function} func A function to call before the try/catch wrapper [optional, private] | |
| 359 | − * @return {function} The newly wrapped functions with a context | |
| 360 | − */ | |
| 361 | − wrap: function(options, func, _before) { | |
| 362 | − var self = this; | |
| 363 | − // 1 argument has been passed, and it's not a function | |
| 364 | − // so just return it | |
| 365 | − if (isUndefined(func) && !isFunction(options)) { | |
| 366 | − return options; | |
| 367 | − } | |
| 388 | + if (self._globalOptions.autoBreadcrumbs) | |
| 389 | + self._instrumentBreadcrumbs(); | |
| 368 | 390 | |
| 369 | − // options is optional | |
| 370 | − if (isFunction(options)) { | |
| 371 | − func = options; | |
| 372 | − options = undefined; | |
| 373 | − } | |
| 391 | + // Install all of the plugins | |
| 392 | + self._drainPlugins(); | |
| 374 | 393 | |
| 375 | − // At this point, we've passed along 2 arguments, and the second one | |
| 376 | − // is not a function either, so we'll just return the second argument. | |
| 377 | − if (!isFunction(func)) { | |
| 378 | − return func; | |
| 379 | − } | |
| 394 | + self._isRavenInstalled = true; | |
| 395 | + } | |
| 380 | 396 | |
| 381 | − // We don't wanna wrap it twice! | |
| 382 | − try { | |
| 383 | − if (func.__raven__) { | |
| 384 | − return func; | |
| 385 | − } | |
| 397 | + Error.stackTraceLimit = self._globalOptions.stackTraceLimit; | |
| 398 | + return this; | |
| 399 | + }, | |
| 400 | + | |
| 401 | + /* | |
| 402 | + * Set the DSN (can be called multiple time unlike config) | |
| 403 | + * | |
| 404 | + * @param {string} dsn The public Sentry DSN | |
| 405 | + */ | |
| 406 | + setDSN: function (dsn) { | |
| 407 | + var self = this, | |
| 408 | + uri = self._parseDSN(dsn), | |
| 409 | + lastSlash = uri.path.lastIndexOf("/"), | |
| 410 | + path = uri.path.substr(1, lastSlash); | |
| 411 | + | |
| 412 | + self._dsn = dsn; | |
| 413 | + self._globalKey = uri.user; | |
| 414 | + self._globalSecret = uri.pass && uri.pass.substr(1); | |
| 415 | + self._globalProject = uri.path.substr(lastSlash + 1); | |
| 416 | + | |
| 417 | + self._globalServer = self._getGlobalServer(uri); | |
| 418 | + | |
| 419 | + self._globalEndpoint = | |
| 420 | + self._globalServer + | |
| 421 | + "/" + | |
| 422 | + path + | |
| 423 | + "api/" + | |
| 424 | + self._globalProject + | |
| 425 | + "/store/"; | |
| 426 | + | |
| 427 | + // Reset backoff state since we may be pointing at a | |
| 428 | + // new project/server | |
| 429 | + this._resetBackoff(); | |
| 430 | + }, | |
| 431 | + | |
| 432 | + /* | |
| 433 | + * Wrap code within a context so Raven can capture errors | |
| 434 | + * reliably across domains that is executed immediately. | |
| 435 | + * | |
| 436 | + * @param {object} options A specific set of options for this context [optional] | |
| 437 | + * @param {function} func The callback to be immediately executed within the context | |
| 438 | + * @param {array} args An array of arguments to be called with the callback [optional] | |
| 439 | + */ | |
| 440 | + context: function (options, func, args) { | |
| 441 | + if (isFunction(options)) { | |
| 442 | + args = func || []; | |
| 443 | + func = options; | |
| 444 | + options = undefined; | |
| 445 | + } | |
| 386 | 446 | |
| 387 | − // If this has already been wrapped in the past, return that | |
| 388 | − if (func.__raven_wrapper__) { | |
| 389 | − return func.__raven_wrapper__; | |
| 390 | − } | |
| 391 | − } catch (e) { | |
| 392 | − // Just accessing custom props in some Selenium environments | |
| 393 | − // can cause a "Permission denied" exception (see raven-js#495). | |
| 394 | − // Bail on wrapping and return the function as-is (defers to window.onerror). | |
| 395 | − return func; | |
| 396 | − } | |
| 447 | + return this.wrap(options, func).apply(this, args); | |
| 448 | + }, | |
| 449 | + | |
| 450 | + /* | |
| 451 | + * Wrap code within a context and returns back a new function to be executed | |
| 452 | + * | |
| 453 | + * @param {object} options A specific set of options for this context [optional] | |
| 454 | + * @param {function} func The function to be wrapped in a new context | |
| 455 | + * @param {function} func A function to call before the try/catch wrapper [optional, private] | |
| 456 | + * @return {function} The newly wrapped functions with a context | |
| 457 | + */ | |
| 458 | + wrap: function (options, func, _before) { | |
| 459 | + var self = this; | |
| 460 | + // 1 argument has been passed, and it's not a function | |
| 461 | + // so just return it | |
| 462 | + if (isUndefined(func) && !isFunction(options)) { | |
| 463 | + return options; | |
| 464 | + } | |
| 397 | 465 | |
| 398 | − function wrapped() { | |
| 399 | − var args = [], | |
| 400 | − i = arguments.length, | |
| 401 | − deep = !options || (options && options.deep !== false); | |
| 466 | + // options is optional | |
| 467 | + if (isFunction(options)) { | |
| 468 | + func = options; | |
| 469 | + options = undefined; | |
| 470 | + } | |
| 402 | 471 | |
| 403 | − if (_before && isFunction(_before)) { | |
| 404 | − _before.apply(this, arguments); | |
| 405 | − } | |
| 472 | + // At this point, we've passed along 2 arguments, and the second one | |
| 473 | + // is not a function either, so we'll just return the second argument. | |
| 474 | + if (!isFunction(func)) { | |
| 475 | + return func; | |
| 476 | + } | |
| 406 | 477 | |
| 407 | − // Recursively wrap all of a function's arguments that are | |
| 408 | − // functions themselves. | |
| 409 | − while (i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i]; | |
| 410 | − | |
| 411 | − try { | |
| 412 | − // Attempt to invoke user-land function | |
| 413 | − // NOTE: If you are a Sentry user, and you are seeing this stack frame, it | |
| 414 | − // means Raven caught an error invoking your application code. This is | |
| 415 | − // expected behavior and NOT indicative of a bug with Raven.js. | |
| 416 | − return func.apply(this, args); | |
| 417 | − } catch (e) { | |
| 418 | − self._ignoreNextOnError(); | |
| 419 | − self.captureException(e, options); | |
| 420 | − throw e; | |
| 421 | − } | |
| 422 | − } | |
| 478 | + // We don't wanna wrap it twice! | |
| 479 | + try { | |
| 480 | + if (func.__raven__) { | |
| 481 | + return func; | |
| 482 | + } | |
| 423 | 483 | |
| 424 | − // copy over properties of the old function | |
| 425 | − for (var property in func) { | |
| 426 | − if (hasKey(func, property)) { | |
| 427 | − wrapped[property] = func[property]; | |
| 428 | − } | |
| 429 | − } | |
| 430 | − wrapped.prototype = func.prototype; | |
| 431 | − | |
| 432 | − func.__raven_wrapper__ = wrapped; | |
| 433 | − // Signal that this function has been wrapped/filled already | |
| 434 | − // for both debugging and to prevent it to being wrapped/filled twice | |
| 435 | − wrapped.__raven__ = true; | |
| 436 | − wrapped.__orig__ = func; | |
| 437 | − | |
| 438 | − return wrapped; | |
| 439 | − }, | |
| 440 | − | |
| 441 | − /* | |
| 442 | − * Uninstalls the global error handler. | |
| 443 | − * | |
| 444 | − * @return {Raven} | |
| 445 | − */ | |
| 446 | − uninstall: function() { | |
| 447 | − TraceKit.report.uninstall(); | |
| 448 | − | |
| 449 | − this._unpatchFunctionToString(); | |
| 450 | − this._restoreBuiltIns(); | |
| 451 | − | |
| 452 | − Error.stackTraceLimit = this._originalErrorStackTraceLimit; | |
| 453 | − this._isRavenInstalled = false; | |
| 454 | − | |
| 455 | − return this; | |
| 456 | − }, | |
| 457 | − | |
| 458 | − /* | |
| 459 | − * Manually capture an exception and send it over to Sentry | |
| 460 | − * | |
| 461 | − * @param {error} ex An exception to be logged | |
| 462 | − * @param {object} options A specific set of options for this error [optional] | |
| 463 | − * @return {Raven} | |
| 464 | − */ | |
| 465 | − captureException: function(ex, options) { | |
| 466 | − // Cases for sending ex as a message, rather than an exception | |
| 467 | − var isNotError = !isError(ex); | |
| 468 | − var isNotErrorEvent = !isErrorEvent(ex); | |
| 469 | − var isErrorEventWithoutError = isErrorEvent(ex) && !ex.error; | |
| 470 | − | |
| 471 | − if ((isNotError && isNotErrorEvent) || isErrorEventWithoutError) { | |
| 472 | − return this.captureMessage( | |
| 473 | − ex, | |
| 474 | − objectMerge( | |
| 475 | − { | |
| 476 | − trimHeadFrames: 1, | |
| 477 | − stacktrace: true // if we fall back to captureMessage, default to attempting a new trace | |
| 478 | − }, | |
| 479 | − options | |
| 480 | − ) | |
| 481 | − ); | |
| 482 | − } | |
| 484 | + // If this has already been wrapped in the past, return that | |
| 485 | + if (func.__raven_wrapper__) { | |
| 486 | + return func.__raven_wrapper__; | |
| 487 | + } | |
| 488 | + } catch (e) { | |
| 489 | + // Just accessing custom props in some Selenium environments | |
| 490 | + // can cause a "Permission denied" exception (see raven-js#495). | |
| 491 | + // Bail on wrapping and return the function as-is (defers to window.onerror). | |
| 492 | + return func; | |
| 493 | + } | |
| 483 | 494 | |
| 484 | − // Get actual Error from ErrorEvent | |
| 485 | − if (isErrorEvent(ex)) ex = ex.error; | |
| 486 | − | |
| 487 | − // Store the raw exception object for potential debugging and introspection | |
| 488 | − this._lastCapturedException = ex; | |
| 489 | − | |
| 490 | − // TraceKit.report will re-raise any exception passed to it, | |
| 491 | − // which means you have to wrap it in try/catch. Instead, we | |
| 492 | − // can wrap it here and only re-raise if TraceKit.report | |
| 493 | − // raises an exception different from the one we asked to | |
| 494 | − // report on. | |
| 495 | − try { | |
| 496 | − var stack = TraceKit.computeStackTrace(ex); | |
| 497 | − this._handleStackInfo(stack, options); | |
| 498 | − } catch (ex1) { | |
| 499 | − if (ex !== ex1) { | |
| 500 | − throw ex1; | |
| 501 | − } | |
| 502 | − } | |
| 495 | + function wrapped() { | |
| 496 | + var args = [], | |
| 497 | + i = arguments.length, | |
| 498 | + deep = !options || (options && options.deep !== false); | |
| 503 | 499 | |
| 504 | − return this; | |
| 505 | − }, | |
| 506 | − | |
| 507 | − /* | |
| 508 | − * Manually send a message to Sentry | |
| 509 | − * | |
| 510 | − * @param {string} msg A plain message to be captured in Sentry | |
| 511 | − * @param {object} options A specific set of options for this message [optional] | |
| 512 | − * @return {Raven} | |
| 513 | − */ | |
| 514 | − captureMessage: function(msg, options) { | |
| 515 | − // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an | |
| 516 | − // early call; we'll error on the side of logging anything called before configuration since it's | |
| 517 | − // probably something you should see: | |
| 518 | − if ( | |
| 519 | − !!this._globalOptions.ignoreErrors.test && | |
| 520 | − this._globalOptions.ignoreErrors.test(msg) | |
| 521 | − ) { | |
| 522 | − return; | |
| 523 | − } | |
| 500 | + if (_before && isFunction(_before)) { | |
| 501 | + _before.apply(this, arguments); | |
| 502 | + } | |
| 524 | 503 | |
| 525 | − options = options || {}; | |
| 526 | − | |
| 527 | − var data = objectMerge( | |
| 528 | − { | |
| 529 | − message: msg + '' // Make sure it's actually a string | |
| 530 | − }, | |
| 531 | − options | |
| 532 | − ); | |
| 533 | − | |
| 534 | − var ex; | |
| 535 | − // Generate a "synthetic" stack trace from this point. | |
| 536 | − // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative | |
| 537 | − // of a bug with Raven.js. Sentry generates synthetic traces either by configuration, | |
| 538 | − // or if it catches a thrown object without a "stack" property. | |
| 539 | − try { | |
| 540 | − throw new Error(msg); | |
| 541 | − } catch (ex1) { | |
| 542 | − ex = ex1; | |
| 543 | − } | |
| 504 | + // Recursively wrap all of a function's arguments that are | |
| 505 | + // functions themselves. | |
| 506 | + while (i--) | |
| 507 | + args[i] = deep | |
| 508 | + ? self.wrap(options, arguments[i]) | |
| 509 | + : arguments[i]; | |
| 544 | 510 | |
| 545 | − // null exception name so `Error` isn't prefixed to msg | |
| 546 | − ex.name = null; | |
| 547 | − var stack = TraceKit.computeStackTrace(ex); | |
| 511 | + try { | |
| 512 | + // Attempt to invoke user-land function | |
| 513 | + // NOTE: If you are a Sentry user, and you are seeing this stack frame, it | |
| 514 | + // means Raven caught an error invoking your application code. This is | |
| 515 | + // expected behavior and NOT indicative of a bug with Raven.js. | |
| 516 | + return func.apply(this, args); | |
| 517 | + } catch (e) { | |
| 518 | + self._ignoreNextOnError(); | |
| 519 | + self.captureException(e, options); | |
| 520 | + throw e; | |
| 521 | + } | |
| 522 | + } | |
| 548 | 523 | |
| 549 | − // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1] | |
| 550 | − var initialCall = isArray(stack.stack) && stack.stack[1]; | |
| 551 | − var fileurl = (initialCall && initialCall.url) || ''; | |
| 524 | + // copy over properties of the old function | |
| 525 | + for (var property in func) { | |
| 526 | + if (hasKey(func, property)) { | |
| 527 | + wrapped[property] = func[property]; | |
| 528 | + } | |
| 529 | + } | |
| 530 | + wrapped.prototype = func.prototype; | |
| 531 | + | |
| 532 | + func.__raven_wrapper__ = wrapped; | |
| 533 | + // Signal that this function has been wrapped/filled already | |
| 534 | + // for both debugging and to prevent it to being wrapped/filled twice | |
| 535 | + wrapped.__raven__ = true; | |
| 536 | + wrapped.__orig__ = func; | |
| 537 | + | |
| 538 | + return wrapped; | |
| 539 | + }, | |
| 540 | + | |
| 541 | + /* | |
| 542 | + * Uninstalls the global error handler. | |
| 543 | + * | |
| 544 | + * @return {Raven} | |
| 545 | + */ | |
| 546 | + uninstall: function () { | |
| 547 | + TraceKit.report.uninstall(); | |
| 548 | + | |
| 549 | + this._unpatchFunctionToString(); | |
| 550 | + this._restoreBuiltIns(); | |
| 551 | + | |
| 552 | + Error.stackTraceLimit = this._originalErrorStackTraceLimit; | |
| 553 | + this._isRavenInstalled = false; | |
| 554 | + | |
| 555 | + return this; | |
| 556 | + }, | |
| 557 | + | |
| 558 | + /* | |
| 559 | + * Manually capture an exception and send it over to Sentry | |
| 560 | + * | |
| 561 | + * @param {error} ex An exception to be logged | |
| 562 | + * @param {object} options A specific set of options for this error [optional] | |
| 563 | + * @return {Raven} | |
| 564 | + */ | |
| 565 | + captureException: function (ex, options) { | |
| 566 | + // Cases for sending ex as a message, rather than an exception | |
| 567 | + var isNotError = !isError(ex); | |
| 568 | + var isNotErrorEvent = !isErrorEvent(ex); | |
| 569 | + var isErrorEventWithoutError = isErrorEvent(ex) && !ex.error; | |
| 570 | + | |
| 571 | + if ( | |
| 572 | + (isNotError && isNotErrorEvent) || | |
| 573 | + isErrorEventWithoutError | |
| 574 | + ) { | |
| 575 | + return this.captureMessage( | |
| 576 | + ex, | |
| 577 | + objectMerge( | |
| 578 | + { | |
| 579 | + trimHeadFrames: 1, | |
| 580 | + stacktrace: true, // if we fall back to captureMessage, default to attempting a new trace | |
| 581 | + }, | |
| 582 | + options, | |
| 583 | + ), | |
| 584 | + ); | |
| 585 | + } | |
| 552 | 586 | |
| 553 | − if ( | |
| 554 | − !!this._globalOptions.ignoreUrls.test && | |
| 555 | − this._globalOptions.ignoreUrls.test(fileurl) | |
| 556 | − ) { | |
| 557 | − return; | |
| 558 | − } | |
| 587 | + // Get actual Error from ErrorEvent | |
| 588 | + if (isErrorEvent(ex)) ex = ex.error; | |
| 559 | 589 | |
| 560 | − if ( | |
| 561 | − !!this._globalOptions.whitelistUrls.test && | |
| 562 | − !this._globalOptions.whitelistUrls.test(fileurl) | |
| 563 | − ) { | |
| 564 | − return; | |
| 565 | − } | |
| 590 | + // Store the raw exception object for potential debugging and introspection | |
| 591 | + this._lastCapturedException = ex; | |
| 566 | 592 | |
| 567 | − if (this._globalOptions.stacktrace || (options && options.stacktrace)) { | |
| 568 | − options = objectMerge( | |
| 569 | − { | |
| 570 | − // fingerprint on msg, not stack trace (legacy behavior, could be | |
| 571 | − // revisited) | |
| 572 | − fingerprint: msg, | |
| 573 | − // since we know this is a synthetic trace, the top N-most frames | |
| 574 | − // MUST be from Raven.js, so mark them as in_app later by setting | |
| 575 | − // trimHeadFrames | |
| 576 | − trimHeadFrames: (options.trimHeadFrames || 0) + 1 | |
| 577 | − }, | |
| 578 | − options | |
| 579 | − ); | |
| 580 | − | |
| 581 | − var frames = this._prepareFrames(stack, options); | |
| 582 | − data.stacktrace = { | |
| 583 | − // Sentry expects frames oldest to newest | |
| 584 | − frames: frames.reverse() | |
| 585 | − }; | |
| 586 | − } | |
| 593 | + // TraceKit.report will re-raise any exception passed to it, | |
| 594 | + // which means you have to wrap it in try/catch. Instead, we | |
| 595 | + // can wrap it here and only re-raise if TraceKit.report | |
| 596 | + // raises an exception different from the one we asked to | |
| 597 | + // report on. | |
| 598 | + try { | |
| 599 | + var stack = TraceKit.computeStackTrace(ex); | |
| 600 | + this._handleStackInfo(stack, options); | |
| 601 | + } catch (ex1) { | |
| 602 | + if (ex !== ex1) { | |
| 603 | + throw ex1; | |
| 604 | + } | |
| 605 | + } | |
| 587 | 606 | |
| 588 | − // Fire away! | |
| 589 | − this._send(data); | |
| 607 | + return this; | |
| 608 | + }, | |
| 609 | + | |
| 610 | + /* | |
| 611 | + * Manually send a message to Sentry | |
| 612 | + * | |
| 613 | + * @param {string} msg A plain message to be captured in Sentry | |
| 614 | + * @param {object} options A specific set of options for this message [optional] | |
| 615 | + * @return {Raven} | |
| 616 | + */ | |
| 617 | + captureMessage: function (msg, options) { | |
| 618 | + // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an | |
| 619 | + // early call; we'll error on the side of logging anything called before configuration since it's | |
| 620 | + // probably something you should see: | |
| 621 | + if ( | |
| 622 | + !!this._globalOptions.ignoreErrors.test && | |
| 623 | + this._globalOptions.ignoreErrors.test(msg) | |
| 624 | + ) { | |
| 625 | + return; | |
| 626 | + } | |
| 590 | 627 | |
| 591 | − return this; | |
| 592 | − }, | |
| 628 | + options = options || {}; | |
| 593 | 629 | |
| 594 | − captureBreadcrumb: function(obj) { | |
| 595 | − var crumb = objectMerge( | |
| 596 | − { | |
| 597 | − timestamp: now() / 1000 | |
| 598 | − }, | |
| 599 | − obj | |
| 600 | − ); | |
| 630 | + var data = objectMerge( | |
| 631 | + { | |
| 632 | + message: msg + "", // Make sure it's actually a string | |
| 633 | + }, | |
| 634 | + options, | |
| 635 | + ); | |
| 601 | 636 | |
| 602 | − if (isFunction(this._globalOptions.breadcrumbCallback)) { | |
| 603 | − var result = this._globalOptions.breadcrumbCallback(crumb); | |
| 637 | + var ex; | |
| 638 | + // Generate a "synthetic" stack trace from this point. | |
| 639 | + // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative | |
| 640 | + // of a bug with Raven.js. Sentry generates synthetic traces either by configuration, | |
| 641 | + // or if it catches a thrown object without a "stack" property. | |
| 642 | + try { | |
| 643 | + throw new Error(msg); | |
| 644 | + } catch (ex1) { | |
| 645 | + ex = ex1; | |
| 646 | + } | |
| 604 | 647 | |
| 605 | − if (isObject(result) && !isEmptyObject(result)) { | |
| 606 | − crumb = result; | |
| 607 | − } else if (result === false) { | |
| 608 | − return this; | |
| 609 | − } | |
| 610 | − } | |
| 648 | + // null exception name so `Error` isn't prefixed to msg | |
| 649 | + ex.name = null; | |
| 650 | + var stack = TraceKit.computeStackTrace(ex); | |
| 611 | 651 | |
| 612 | − this._breadcrumbs.push(crumb); | |
| 613 | − if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) { | |
| 614 | − this._breadcrumbs.shift(); | |
| 615 | − } | |
| 616 | − return this; | |
| 617 | − }, | |
| 652 | + // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1] | |
| 653 | + var initialCall = isArray(stack.stack) && stack.stack[1]; | |
| 654 | + var fileurl = (initialCall && initialCall.url) || ""; | |
| 618 | 655 | |
| 619 | − addPlugin: function(plugin /*arg1, arg2, ... argN*/) { | |
| 620 | − var pluginArgs = [].slice.call(arguments, 1); | |
| 656 | + if ( | |
| 657 | + !!this._globalOptions.ignoreUrls.test && | |
| 658 | + this._globalOptions.ignoreUrls.test(fileurl) | |
| 659 | + ) { | |
| 660 | + return; | |
| 661 | + } | |
| 621 | 662 | |
| 622 | − this._plugins.push([plugin, pluginArgs]); | |
| 623 | − if (this._isRavenInstalled) { | |
| 624 | − this._drainPlugins(); | |
| 625 | − } | |
| 663 | + if ( | |
| 664 | + !!this._globalOptions.whitelistUrls.test && | |
| 665 | + !this._globalOptions.whitelistUrls.test(fileurl) | |
| 666 | + ) { | |
| 667 | + return; | |
| 668 | + } | |
| 626 | 669 | |
| 627 | − return this; | |
| 628 | − }, | |
| 629 | − | |
| 630 | − /* | |
| 631 | − * Set/clear a user to be sent along with the payload. | |
| 632 | − * | |
| 633 | − * @param {object} user An object representing user data [optional] | |
| 634 | − * @return {Raven} | |
| 635 | − */ | |
| 636 | − setUserContext: function(user) { | |
| 637 | − // Intentionally do not merge here since that's an unexpected behavior. | |
| 638 | − this._globalContext.user = user; | |
| 639 | − | |
| 640 | − return this; | |
| 641 | − }, | |
| 642 | − | |
| 643 | − /* | |
| 644 | − * Merge extra attributes to be sent along with the payload. | |
| 645 | − * | |
| 646 | − * @param {object} extra An object representing extra data [optional] | |
| 647 | − * @return {Raven} | |
| 648 | − */ | |
| 649 | − setExtraContext: function(extra) { | |
| 650 | − this._mergeContext('extra', extra); | |
| 651 | − | |
| 652 | − return this; | |
| 653 | − }, | |
| 654 | − | |
| 655 | − /* | |
| 656 | − * Merge tags to be sent along with the payload. | |
| 657 | − * | |
| 658 | − * @param {object} tags An object representing tags [optional] | |
| 659 | − * @return {Raven} | |
| 660 | − */ | |
| 661 | − setTagsContext: function(tags) { | |
| 662 | − this._mergeContext('tags', tags); | |
| 663 | − | |
| 664 | − return this; | |
| 665 | − }, | |
| 666 | − | |
| 667 | − /* | |
| 668 | − * Clear all of the context. | |
| 669 | − * | |
| 670 | − * @return {Raven} | |
| 671 | − */ | |
| 672 | − clearContext: function() { | |
| 673 | − this._globalContext = {}; | |
| 674 | − | |
| 675 | − return this; | |
| 676 | − }, | |
| 677 | − | |
| 678 | − /* | |
| 679 | − * Get a copy of the current context. This cannot be mutated. | |
| 680 | − * | |
| 681 | − * @return {object} copy of context | |
| 682 | − */ | |
| 683 | − getContext: function() { | |
| 684 | − // lol javascript | |
| 685 | − return JSON.parse(stringify(this._globalContext)); | |
| 686 | − }, | |
| 687 | − | |
| 688 | − /* | |
| 689 | − * Set environment of application | |
| 690 | − * | |
| 691 | − * @param {string} environment Typically something like 'production'. | |
| 692 | − * @return {Raven} | |
| 693 | − */ | |
| 694 | − setEnvironment: function(environment) { | |
| 695 | − this._globalOptions.environment = environment; | |
| 696 | − | |
| 697 | − return this; | |
| 698 | − }, | |
| 699 | − | |
| 700 | − /* | |
| 701 | − * Set release version of application | |
| 702 | − * | |
| 703 | − * @param {string} release Typically something like a git SHA to identify version | |
| 704 | − * @return {Raven} | |
| 705 | − */ | |
| 706 | − setRelease: function(release) { | |
| 707 | − this._globalOptions.release = release; | |
| 708 | − | |
| 709 | − return this; | |
| 710 | − }, | |
| 711 | − | |
| 712 | − /* | |
| 713 | − * Set the dataCallback option | |
| 714 | − * | |
| 715 | − * @param {function} callback The callback to run which allows the | |
| 716 | − * data blob to be mutated before sending | |
| 717 | − * @return {Raven} | |
| 718 | − */ | |
| 719 | − setDataCallback: function(callback) { | |
| 720 | − var original = this._globalOptions.dataCallback; | |
| 721 | − this._globalOptions.dataCallback = keepOriginalCallback(original, callback); | |
| 722 | − return this; | |
| 723 | − }, | |
| 724 | − | |
| 725 | − /* | |
| 726 | − * Set the breadcrumbCallback option | |
| 727 | − * | |
| 728 | − * @param {function} callback The callback to run which allows filtering | |
| 729 | − * or mutating breadcrumbs | |
| 730 | − * @return {Raven} | |
| 731 | − */ | |
| 732 | − setBreadcrumbCallback: function(callback) { | |
| 733 | − var original = this._globalOptions.breadcrumbCallback; | |
| 734 | − this._globalOptions.breadcrumbCallback = keepOriginalCallback(original, callback); | |
| 735 | − return this; | |
| 736 | − }, | |
| 737 | − | |
| 738 | − /* | |
| 739 | − * Set the shouldSendCallback option | |
| 740 | − * | |
| 741 | − * @param {function} callback The callback to run which allows | |
| 742 | − * introspecting the blob before sending | |
| 743 | − * @return {Raven} | |
| 744 | − */ | |
| 745 | − setShouldSendCallback: function(callback) { | |
| 746 | − var original = this._globalOptions.shouldSendCallback; | |
| 747 | − this._globalOptions.shouldSendCallback = keepOriginalCallback(original, callback); | |
| 748 | − return this; | |
| 749 | − }, | |
| 750 | − | |
| 751 | − /** | |
| 752 | − * Override the default HTTP transport mechanism that transmits data | |
| 753 | − * to the Sentry server. | |
| 754 | − * | |
| 755 | − * @param {function} transport Function invoked instead of the default | |
| 756 | − * `makeRequest` handler. | |
| 757 | − * | |
| 758 | − * @return {Raven} | |
| 759 | − */ | |
| 760 | − setTransport: function(transport) { | |
| 761 | − this._globalOptions.transport = transport; | |
| 762 | − | |
| 763 | − return this; | |
| 764 | − }, | |
| 765 | − | |
| 766 | − /* | |
| 767 | − * Get the latest raw exception that was captured by Raven. | |
| 768 | − * | |
| 769 | − * @return {error} | |
| 770 | − */ | |
| 771 | − lastException: function() { | |
| 772 | − return this._lastCapturedException; | |
| 773 | − }, | |
| 774 | − | |
| 775 | − /* | |
| 776 | − * Get the last event id | |
| 777 | − * | |
| 778 | − * @return {string} | |
| 779 | − */ | |
| 780 | − lastEventId: function() { | |
| 781 | − return this._lastEventId; | |
| 782 | − }, | |
| 783 | − | |
| 784 | − /* | |
| 785 | − * Determine if Raven is setup and ready to go. | |
| 786 | − * | |
| 787 | − * @return {boolean} | |
| 788 | − */ | |
| 789 | − isSetup: function() { | |
| 790 | − if (!this._hasJSON) return false; // needs JSON support | |
| 791 | − if (!this._globalServer) { | |
| 792 | − if (!this.ravenNotConfiguredError) { | |
| 793 | − this.ravenNotConfiguredError = true; | |
| 794 | − this._logDebug('error', 'Error: Raven has not been configured.'); | |
| 795 | − } | |
| 796 | − return false; | |
| 797 | − } | |
| 798 | − return true; | |
| 799 | − }, | |
| 670 | + if ( | |
| 671 | + this._globalOptions.stacktrace || | |
| 672 | + (options && options.stacktrace) | |
| 673 | + ) { | |
| 674 | + options = objectMerge( | |
| 675 | + { | |
| 676 | + // fingerprint on msg, not stack trace (legacy behavior, could be | |
| 677 | + // revisited) | |
| 678 | + fingerprint: msg, | |
| 679 | + // since we know this is a synthetic trace, the top N-most frames | |
| 680 | + // MUST be from Raven.js, so mark them as in_app later by setting | |
| 681 | + // trimHeadFrames | |
| 682 | + trimHeadFrames: (options.trimHeadFrames || 0) + 1, | |
| 683 | + }, | |
| 684 | + options, | |
| 685 | + ); | |
| 686 | + | |
| 687 | + var frames = this._prepareFrames(stack, options); | |
| 688 | + data.stacktrace = { | |
| 689 | + // Sentry expects frames oldest to newest | |
| 690 | + frames: frames.reverse(), | |
| 691 | + }; | |
| 692 | + } | |
| 800 | 693 | |
| 801 | − afterLoad: function() { | |
| 802 | − // TODO: remove window dependence? | |
| 694 | + // Fire away! | |
| 695 | + this._send(data); | |
| 803 | 696 | |
| 804 | − // Attempt to initialize Raven on load | |
| 805 | − var RavenConfig = _window.RavenConfig; | |
| 806 | − if (RavenConfig) { | |
| 807 | − this.config(RavenConfig.dsn, RavenConfig.config).install(); | |
| 808 | − } | |
| 809 | − }, | |
| 697 | + return this; | |
| 698 | + }, | |
| 810 | 699 | |
| 811 | − showReportDialog: function(options) { | |
| 812 | − if ( | |
| 813 | − !_document // doesn't work without a document (React native) | |
| 814 | − ) | |
| 815 | − return; | |
| 700 | + captureBreadcrumb: function (obj) { | |
| 701 | + var crumb = objectMerge( | |
| 702 | + { | |
| 703 | + timestamp: now() / 1000, | |
| 704 | + }, | |
| 705 | + obj, | |
| 706 | + ); | |
| 816 | 707 | |
| 817 | − options = options || {}; | |
| 708 | + if (isFunction(this._globalOptions.breadcrumbCallback)) { | |
| 709 | + var result = this._globalOptions.breadcrumbCallback(crumb); | |
| 818 | 710 | |
| 819 | − var lastEventId = options.eventId || this.lastEventId(); | |
| 820 | − if (!lastEventId) { | |
| 821 | − throw new RavenConfigError('Missing eventId'); | |
| 822 | − } | |
| 711 | + if (isObject(result) && !isEmptyObject(result)) { | |
| 712 | + crumb = result; | |
| 713 | + } else if (result === false) { | |
| 714 | + return this; | |
| 715 | + } | |
| 716 | + } | |
| 823 | 717 | |
| 824 | − var dsn = options.dsn || this._dsn; | |
| 825 | − if (!dsn) { | |
| 826 | − throw new RavenConfigError('Missing DSN'); | |
| 827 | − } | |
| 718 | + this._breadcrumbs.push(crumb); | |
| 719 | + if ( | |
| 720 | + this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs | |
| 721 | + ) { | |
| 722 | + this._breadcrumbs.shift(); | |
| 723 | + } | |
| 724 | + return this; | |
| 725 | + }, | |
| 828 | 726 | |
| 829 | − var encode = encodeURIComponent; | |
| 830 | − var qs = ''; | |
| 831 | − qs += '?eventId=' + encode(lastEventId); | |
| 832 | − qs += '&dsn=' + encode(dsn); | |
| 727 | + addPlugin: function (plugin /*arg1, arg2, ... argN*/) { | |
| 728 | + var pluginArgs = [].slice.call(arguments, 1); | |
| 833 | 729 | |
| 834 | − var user = options.user || this._globalContext.user; | |
| 835 | − if (user) { | |
| 836 | − if (user.name) qs += '&name=' + encode(user.name); | |
| 837 | − if (user.email) qs += '&email=' + encode(user.email); | |
| 838 | − } | |
| 730 | + this._plugins.push([plugin, pluginArgs]); | |
| 731 | + if (this._isRavenInstalled) { | |
| 732 | + this._drainPlugins(); | |
| 733 | + } | |
| 839 | 734 | |
| 840 | − var globalServer = this._getGlobalServer(this._parseDSN(dsn)); | |
| 735 | + return this; | |
| 736 | + }, | |
| 737 | + | |
| 738 | + /* | |
| 739 | + * Set/clear a user to be sent along with the payload. | |
| 740 | + * | |
| 741 | + * @param {object} user An object representing user data [optional] | |
| 742 | + * @return {Raven} | |
| 743 | + */ | |
| 744 | + setUserContext: function (user) { | |
| 745 | + // Intentionally do not merge here since that's an unexpected behavior. | |
| 746 | + this._globalContext.user = user; | |
| 747 | + | |
| 748 | + return this; | |
| 749 | + }, | |
| 750 | + | |
| 751 | + /* | |
| 752 | + * Merge extra attributes to be sent along with the payload. | |
| 753 | + * | |
| 754 | + * @param {object} extra An object representing extra data [optional] | |
| 755 | + * @return {Raven} | |
| 756 | + */ | |
| 757 | + setExtraContext: function (extra) { | |
| 758 | + this._mergeContext("extra", extra); | |
| 759 | + | |
| 760 | + return this; | |
| 761 | + }, | |
| 762 | + | |
| 763 | + /* | |
| 764 | + * Merge tags to be sent along with the payload. | |
| 765 | + * | |
| 766 | + * @param {object} tags An object representing tags [optional] | |
| 767 | + * @return {Raven} | |
| 768 | + */ | |
| 769 | + setTagsContext: function (tags) { | |
| 770 | + this._mergeContext("tags", tags); | |
| 771 | + | |
| 772 | + return this; | |
| 773 | + }, | |
| 774 | + | |
| 775 | + /* | |
| 776 | + * Clear all of the context. | |
| 777 | + * | |
| 778 | + * @return {Raven} | |
| 779 | + */ | |
| 780 | + clearContext: function () { | |
| 781 | + this._globalContext = {}; | |
| 782 | + | |
| 783 | + return this; | |
| 784 | + }, | |
| 785 | + | |
| 786 | + /* | |
| 787 | + * Get a copy of the current context. This cannot be mutated. | |
| 788 | + * | |
| 789 | + * @return {object} copy of context | |
| 790 | + */ | |
| 791 | + getContext: function () { | |
| 792 | + // lol javascript | |
| 793 | + return JSON.parse(stringify(this._globalContext)); | |
| 794 | + }, | |
| 795 | + | |
| 796 | + /* | |
| 797 | + * Set environment of application | |
| 798 | + * | |
| 799 | + * @param {string} environment Typically something like 'production'. | |
| 800 | + * @return {Raven} | |
| 801 | + */ | |
| 802 | + setEnvironment: function (environment) { | |
| 803 | + this._globalOptions.environment = environment; | |
| 804 | + | |
| 805 | + return this; | |
| 806 | + }, | |
| 807 | + | |
| 808 | + /* | |
| 809 | + * Set release version of application | |
| 810 | + * | |
| 811 | + * @param {string} release Typically something like a git SHA to identify version | |
| 812 | + * @return {Raven} | |
| 813 | + */ | |
| 814 | + setRelease: function (release) { | |
| 815 | + this._globalOptions.release = release; | |
| 816 | + | |
| 817 | + return this; | |
| 818 | + }, | |
| 819 | + | |
| 820 | + /* | |
| 821 | + * Set the dataCallback option | |
| 822 | + * | |
| 823 | + * @param {function} callback The callback to run which allows the | |
| 824 | + * data blob to be mutated before sending | |
| 825 | + * @return {Raven} | |
| 826 | + */ | |
| 827 | + setDataCallback: function (callback) { | |
| 828 | + var original = this._globalOptions.dataCallback; | |
| 829 | + this._globalOptions.dataCallback = keepOriginalCallback( | |
| 830 | + original, | |
| 831 | + callback, | |
| 832 | + ); | |
| 833 | + return this; | |
| 834 | + }, | |
| 835 | + | |
| 836 | + /* | |
| 837 | + * Set the breadcrumbCallback option | |
| 838 | + * | |
| 839 | + * @param {function} callback The callback to run which allows filtering | |
| 840 | + * or mutating breadcrumbs | |
| 841 | + * @return {Raven} | |
| 842 | + */ | |
| 843 | + setBreadcrumbCallback: function (callback) { | |
| 844 | + var original = this._globalOptions.breadcrumbCallback; | |
| 845 | + this._globalOptions.breadcrumbCallback = keepOriginalCallback( | |
| 846 | + original, | |
| 847 | + callback, | |
| 848 | + ); | |
| 849 | + return this; | |
| 850 | + }, | |
| 851 | + | |
| 852 | + /* | |
| 853 | + * Set the shouldSendCallback option | |
| 854 | + * | |
| 855 | + * @param {function} callback The callback to run which allows | |
| 856 | + * introspecting the blob before sending | |
| 857 | + * @return {Raven} | |
| 858 | + */ | |
| 859 | + setShouldSendCallback: function (callback) { | |
| 860 | + var original = this._globalOptions.shouldSendCallback; | |
| 861 | + this._globalOptions.shouldSendCallback = keepOriginalCallback( | |
| 862 | + original, | |
| 863 | + callback, | |
| 864 | + ); | |
| 865 | + return this; | |
| 866 | + }, | |
| 867 | + | |
| 868 | + /** | |
| 869 | + * Override the default HTTP transport mechanism that transmits data | |
| 870 | + * to the Sentry server. | |
| 871 | + * | |
| 872 | + * @param {function} transport Function invoked instead of the default | |
| 873 | + * `makeRequest` handler. | |
| 874 | + * | |
| 875 | + * @return {Raven} | |
| 876 | + */ | |
| 877 | + setTransport: function (transport) { | |
| 878 | + this._globalOptions.transport = transport; | |
| 879 | + | |
| 880 | + return this; | |
| 881 | + }, | |
| 882 | + | |
| 883 | + /* | |
| 884 | + * Get the latest raw exception that was captured by Raven. | |
| 885 | + * | |
| 886 | + * @return {error} | |
| 887 | + */ | |
| 888 | + lastException: function () { | |
| 889 | + return this._lastCapturedException; | |
| 890 | + }, | |
| 891 | + | |
| 892 | + /* | |
| 893 | + * Get the last event id | |
| 894 | + * | |
| 895 | + * @return {string} | |
| 896 | + */ | |
| 897 | + lastEventId: function () { | |
| 898 | + return this._lastEventId; | |
| 899 | + }, | |
| 900 | + | |
| 901 | + /* | |
| 902 | + * Determine if Raven is setup and ready to go. | |
| 903 | + * | |
| 904 | + * @return {boolean} | |
| 905 | + */ | |
| 906 | + isSetup: function () { | |
| 907 | + if (!this._hasJSON) return false; // needs JSON support | |
| 908 | + if (!this._globalServer) { | |
| 909 | + if (!this.ravenNotConfiguredError) { | |
| 910 | + this.ravenNotConfiguredError = true; | |
| 911 | + this._logDebug( | |
| 912 | + "error", | |
| 913 | + "Error: Raven has not been configured.", | |
| 914 | + ); | |
| 915 | + } | |
| 916 | + return false; | |
| 917 | + } | |
| 918 | + return true; | |
| 919 | + }, | |
| 841 | 920 | |
| 842 | − var script = _document.createElement('script'); | |
| 843 | − script.async = true; | |
| 844 | − script.src = globalServer + '/api/embed/error-page/' + qs; | |
| 845 | − (_document.head || _document.body).appendChild(script); | |
| 846 | − }, | |
| 921 | + afterLoad: function () { | |
| 922 | + // TODO: remove window dependence? | |
| 847 | 923 | |
| 848 | − /**** Private functions ****/ | |
| 849 | − _ignoreNextOnError: function() { | |
| 850 | − var self = this; | |
| 851 | − this._ignoreOnError += 1; | |
| 852 | − setTimeout(function() { | |
| 853 | − // onerror should trigger before setTimeout | |
| 854 | − self._ignoreOnError -= 1; | |
| 855 | − }); | |
| 856 | − }, | |
| 924 | + // Attempt to initialize Raven on load | |
| 925 | + var RavenConfig = _window.RavenConfig; | |
| 926 | + if (RavenConfig) { | |
| 927 | + this.config(RavenConfig.dsn, RavenConfig.config).install(); | |
| 928 | + } | |
| 929 | + }, | |
| 857 | 930 | |
| 858 | − _triggerEvent: function(eventType, options) { | |
| 859 | − // NOTE: `event` is a native browser thing, so let's avoid conflicting with it | |
| 860 | − var evt, key; | |
| 931 | + showReportDialog: function (options) { | |
| 932 | + if ( | |
| 933 | + !_document // doesn't work without a document (React native) | |
| 934 | + ) | |
| 935 | + return; | |
| 861 | 936 | |
| 862 | − if (!this._hasDocument) return; | |
| 937 | + options = options || {}; | |
| 863 | 938 | |
| 864 | − options = options || {}; | |
| 939 | + var lastEventId = options.eventId || this.lastEventId(); | |
| 940 | + if (!lastEventId) { | |
| 941 | + throw new RavenConfigError("Missing eventId"); | |
| 942 | + } | |
| 865 | 943 | |
| 866 | − eventType = 'raven' + eventType.substr(0, 1).toUpperCase() + eventType.substr(1); | |
| 944 | + var dsn = options.dsn || this._dsn; | |
| 945 | + if (!dsn) { | |
| 946 | + throw new RavenConfigError("Missing DSN"); | |
| 947 | + } | |
| 867 | 948 | |
| 868 | − if (_document.createEvent) { | |
| 869 | − evt = _document.createEvent('HTMLEvents'); | |
| 870 | − evt.initEvent(eventType, true, true); | |
| 871 | − } else { | |
| 872 | − evt = _document.createEventObject(); | |
| 873 | − evt.eventType = eventType; | |
| 874 | − } | |
| 949 | + var encode = encodeURIComponent; | |
| 950 | + var qs = ""; | |
| 951 | + qs += "?eventId=" + encode(lastEventId); | |
| 952 | + qs += "&dsn=" + encode(dsn); | |
| 875 | 953 | |
| 876 | − for (key in options) | |
| 877 | − if (hasKey(options, key)) { | |
| 878 | − evt[key] = options[key]; | |
| 879 | − } | |
| 954 | + var user = options.user || this._globalContext.user; | |
| 955 | + if (user) { | |
| 956 | + if (user.name) qs += "&name=" + encode(user.name); | |
| 957 | + if (user.email) qs += "&email=" + encode(user.email); | |
| 958 | + } | |
| 880 | 959 | |
| 881 | − if (_document.createEvent) { | |
| 882 | − // IE9 if standards | |
| 883 | − _document.dispatchEvent(evt); | |
| 884 | − } else { | |
| 885 | − // IE8 regardless of Quirks or Standards | |
| 886 | − // IE9 if quirks | |
| 887 | − try { | |
| 888 | − _document.fireEvent('on' + evt.eventType.toLowerCase(), evt); | |
| 889 | − } catch (e) { | |
| 890 | − // Do nothing | |
| 891 | − } | |
| 892 | − } | |
| 893 | − }, | |
| 894 | − | |
| 895 | − /** | |
| 896 | − * Wraps addEventListener to capture UI breadcrumbs | |
| 897 | − * @param evtName the event name (e.g. "click") | |
| 898 | − * @returns {Function} | |
| 899 | − * @private | |
| 900 | − */ | |
| 901 | − _breadcrumbEventHandler: function(evtName) { | |
| 902 | − var self = this; | |
| 903 | − return function(evt) { | |
| 904 | − // reset keypress timeout; e.g. triggering a 'click' after | |
| 905 | − // a 'keypress' will reset the keypress debounce so that a new | |
| 906 | − // set of keypresses can be recorded | |
| 907 | − self._keypressTimeout = null; | |
| 908 | − | |
| 909 | − // It's possible this handler might trigger multiple times for the same | |
| 910 | − // event (e.g. event propagation through node ancestors). Ignore if we've | |
| 911 | − // already captured the event. | |
| 912 | − if (self._lastCapturedEvent === evt) return; | |
| 913 | − | |
| 914 | − self._lastCapturedEvent = evt; | |
| 915 | − | |
| 916 | − // try/catch both: | |
| 917 | − // - accessing evt.target (see getsentry/raven-js#838, #768) | |
| 918 | − // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly | |
| 919 | − // can throw an exception in some circumstances. | |
| 920 | − var target; | |
| 921 | − try { | |
| 922 | − target = htmlTreeAsString(evt.target); | |
| 923 | − } catch (e) { | |
| 924 | − target = '<unknown>'; | |
| 925 | − } | |
| 960 | + var globalServer = this._getGlobalServer(this._parseDSN(dsn)); | |
| 961 | + | |
| 962 | + var script = _document.createElement("script"); | |
| 963 | + script.async = true; | |
| 964 | + script.src = globalServer + "/api/embed/error-page/" + qs; | |
| 965 | + (_document.head || _document.body).appendChild(script); | |
| 966 | + }, | |
| 967 | + | |
| 968 | + /**** Private functions ****/ | |
| 969 | + _ignoreNextOnError: function () { | |
| 970 | + var self = this; | |
| 971 | + this._ignoreOnError += 1; | |
| 972 | + setTimeout(function () { | |
| 973 | + // onerror should trigger before setTimeout | |
| 974 | + self._ignoreOnError -= 1; | |
| 975 | + }); | |
| 976 | + }, | |
| 926 | 977 | |
| 927 | − self.captureBreadcrumb({ | |
| 928 | − category: 'ui.' + evtName, // e.g. ui.click, ui.input | |
| 929 | − message: target | |
| 930 | − }); | |
| 931 | − }; | |
| 932 | − }, | |
| 933 | − | |
| 934 | − /** | |
| 935 | − * Wraps addEventListener to capture keypress UI events | |
| 936 | − * @returns {Function} | |
| 937 | − * @private | |
| 938 | − */ | |
| 939 | − _keypressEventHandler: function() { | |
| 940 | − var self = this, | |
| 941 | − debounceDuration = 1000; // milliseconds | |
| 942 | − | |
| 943 | − // TODO: if somehow user switches keypress target before | |
| 944 | − // debounce timeout is triggered, we will only capture | |
| 945 | − // a single breadcrumb from the FIRST target (acceptable?) | |
| 946 | − return function(evt) { | |
| 947 | − var target; | |
| 948 | − try { | |
| 949 | − target = evt.target; | |
| 950 | − } catch (e) { | |
| 951 | − // just accessing event properties can throw an exception in some rare circumstances | |
| 952 | − // see: https://github.com/getsentry/raven-js/issues/838 | |
| 953 | − return; | |
| 954 | − } | |
| 955 | − var tagName = target && target.tagName; | |
| 956 | − | |
| 957 | − // only consider keypress events on actual input elements | |
| 958 | − // this will disregard keypresses targeting body (e.g. tabbing | |
| 959 | − // through elements, hotkeys, etc) | |
| 960 | − if ( | |
| 961 | − !tagName || | |
| 962 | − (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable) | |
| 963 | − ) | |
| 964 | − return; | |
| 965 | − | |
| 966 | − // record first keypress in a series, but ignore subsequent | |
| 967 | − // keypresses until debounce clears | |
| 968 | − var timeout = self._keypressTimeout; | |
| 969 | − if (!timeout) { | |
| 970 | − self._breadcrumbEventHandler('input')(evt); | |
| 971 | − } | |
| 972 | − clearTimeout(timeout); | |
| 973 | − self._keypressTimeout = setTimeout(function() { | |
| 974 | − self._keypressTimeout = null; | |
| 975 | − }, debounceDuration); | |
| 976 | − }; | |
| 977 | − }, | |
| 978 | − | |
| 979 | − /** | |
| 980 | − * Captures a breadcrumb of type "navigation", normalizing input URLs | |
| 981 | − * @param to the originating URL | |
| 982 | − * @param from the target URL | |
| 983 | − * @private | |
| 984 | − */ | |
| 985 | − _captureUrlChange: function(from, to) { | |
| 986 | − var parsedLoc = parseUrl(this._location.href); | |
| 987 | − var parsedTo = parseUrl(to); | |
| 988 | − var parsedFrom = parseUrl(from); | |
| 989 | − | |
| 990 | − // because onpopstate only tells you the "new" (to) value of location.href, and | |
| 991 | − // not the previous (from) value, we need to track the value of the current URL | |
| 992 | − // state ourselves | |
| 993 | − this._lastHref = to; | |
| 994 | − | |
| 995 | − // Use only the path component of the URL if the URL matches the current | |
| 996 | − // document (almost all the time when using pushState) | |
| 997 | − if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host) | |
| 998 | − to = parsedTo.relative; | |
| 999 | − if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) | |
| 1000 | − from = parsedFrom.relative; | |
| 1001 | − | |
| 1002 | − this.captureBreadcrumb({ | |
| 1003 | − category: 'navigation', | |
| 1004 | − data: { | |
| 1005 | − to: to, | |
| 1006 | − from: from | |
| 1007 | − } | |
| 1008 | − }); | |
| 1009 | − }, | |
| 1010 | − | |
| 1011 | − _patchFunctionToString: function() { | |
| 1012 | − var self = this; | |
| 1013 | − self._originalFunctionToString = Function.prototype.toString; | |
| 1014 | − // eslint-disable-next-line no-extend-native | |
| 1015 | − Function.prototype.toString = function() { | |
| 1016 | − if (typeof this === 'function' && this.__raven__) { | |
| 1017 | − return self._originalFunctionToString.apply(this.__orig__, arguments); | |
| 1018 | − } | |
| 1019 | − return self._originalFunctionToString.apply(this, arguments); | |
| 1020 | − }; | |
| 1021 | − }, | |
| 1022 | − | |
| 1023 | − _unpatchFunctionToString: function() { | |
| 1024 | − if (this._originalFunctionToString) { | |
| 1025 | − // eslint-disable-next-line no-extend-native | |
| 1026 | − Function.prototype.toString = this._originalFunctionToString; | |
| 1027 | − } | |
| 1028 | − }, | |
| 1029 | − | |
| 1030 | − /** | |
| 1031 | − * Wrap timer functions and event targets to catch errors and provide | |
| 1032 | − * better metadata. | |
| 1033 | − */ | |
| 1034 | − _instrumentTryCatch: function() { | |
| 1035 | − var self = this; | |
| 1036 | − | |
| 1037 | − var wrappedBuiltIns = self._wrappedBuiltIns; | |
| 1038 | − | |
| 1039 | − function wrapTimeFn(orig) { | |
| 1040 | − return function(fn, t) { | |
| 1041 | − // preserve arity | |
| 1042 | − // Make a copy of the arguments to prevent deoptimization | |
| 1043 | − // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments | |
| 1044 | − var args = new Array(arguments.length); | |
| 1045 | − for (var i = 0; i < args.length; ++i) { | |
| 1046 | − args[i] = arguments[i]; | |
| 1047 | − } | |
| 1048 | − var originalCallback = args[0]; | |
| 1049 | − if (isFunction(originalCallback)) { | |
| 1050 | − args[0] = self.wrap(originalCallback); | |
| 1051 | − } | |
| 978 | + _triggerEvent: function (eventType, options) { | |
| 979 | + // NOTE: `event` is a native browser thing, so let's avoid conflicting with it | |
| 980 | + var evt, key; | |
| 1052 | 981 | |
| 1053 | − // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it | |
| 1054 | − // also supports only two arguments and doesn't care what this is, so we | |
| 1055 | − // can just call the original function directly. | |
| 1056 | − if (orig.apply) { | |
| 1057 | − return orig.apply(this, args); | |
| 1058 | − } else { | |
| 1059 | − return orig(args[0], args[1]); | |
| 1060 | − } | |
| 1061 | − }; | |
| 1062 | − } | |
| 982 | + if (!this._hasDocument) return; | |
| 1063 | 983 | |
| 1064 | − var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs; | |
| 1065 | − | |
| 1066 | − function wrapEventTarget(global) { | |
| 1067 | − var proto = _window[global] && _window[global].prototype; | |
| 1068 | − if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) { | |
| 1069 | − fill( | |
| 1070 | − proto, | |
| 1071 | − 'addEventListener', | |
| 1072 | − function(orig) { | |
| 1073 | − return function(evtName, fn, capture, secure) { | |
| 1074 | − // preserve arity | |
| 1075 | − try { | |
| 1076 | − if (fn && fn.handleEvent) { | |
| 1077 | − fn.handleEvent = self.wrap(fn.handleEvent); | |
| 984 | + options = options || {}; | |
| 985 | + | |
| 986 | + eventType = | |
| 987 | + "raven" + | |
| 988 | + eventType.substr(0, 1).toUpperCase() + | |
| 989 | + eventType.substr(1); | |
| 990 | + | |
| 991 | + if (_document.createEvent) { | |
| 992 | + evt = _document.createEvent("HTMLEvents"); | |
| 993 | + evt.initEvent(eventType, true, true); | |
| 994 | + } else { | |
| 995 | + evt = _document.createEventObject(); | |
| 996 | + evt.eventType = eventType; | |
| 1078 | 997 | } |
| 1079 | − } catch (err) { | |
| 1080 | − // can sometimes get 'Permission denied to access property "handle Event' | |
| 1081 | − } | |
| 1082 | 998 | |
| 1083 | − // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs` | |
| 1084 | − // so that we don't have more than one wrapper function | |
| 1085 | − var before, clickHandler, keypressHandler; | |
| 999 | + for (key in options) | |
| 1000 | + if (hasKey(options, key)) { | |
| 1001 | + evt[key] = options[key]; | |
| 1002 | + } | |
| 1086 | 1003 | |
| 1087 | − if ( | |
| 1088 | − autoBreadcrumbs && | |
| 1089 | − autoBreadcrumbs.dom && | |
| 1090 | − (global === 'EventTarget' || global === 'Node') | |
| 1091 | − ) { | |
| 1092 | − // NOTE: generating multiple handlers per addEventListener invocation, should | |
| 1093 | − // revisit and verify we can just use one (almost certainly) | |
| 1094 | − clickHandler = self._breadcrumbEventHandler('click'); | |
| 1095 | − keypressHandler = self._keypressEventHandler(); | |
| 1096 | − before = function(evt) { | |
| 1097 | − // need to intercept every DOM event in `before` argument, in case that | |
| 1098 | − // same wrapped method is re-used for different events (e.g. mousemove THEN click) | |
| 1099 | − // see #724 | |
| 1100 | − if (!evt) return; | |
| 1101 | − | |
| 1102 | − var eventType; | |
| 1004 | + if (_document.createEvent) { | |
| 1005 | + // IE9 if standards | |
| 1006 | + _document.dispatchEvent(evt); | |
| 1007 | + } else { | |
| 1008 | + // IE8 regardless of Quirks or Standards | |
| 1009 | + // IE9 if quirks | |
| 1010 | + try { | |
| 1011 | + _document.fireEvent( | |
| 1012 | + "on" + evt.eventType.toLowerCase(), | |
| 1013 | + evt, | |
| 1014 | + ); | |
| 1015 | + } catch (e) { | |
| 1016 | + // Do nothing | |
| 1017 | + } | |
| 1018 | + } | |
| 1019 | + }, | |
| 1020 | + | |
| 1021 | + /** | |
| 1022 | + * Wraps addEventListener to capture UI breadcrumbs | |
| 1023 | + * @param evtName the event name (e.g. "click") | |
| 1024 | + * @returns {Function} | |
| 1025 | + * @private | |
| 1026 | + */ | |
| 1027 | + _breadcrumbEventHandler: function (evtName) { | |
| 1028 | + var self = this; | |
| 1029 | + return function (evt) { | |
| 1030 | + // reset keypress timeout; e.g. triggering a 'click' after | |
| 1031 | + // a 'keypress' will reset the keypress debounce so that a new | |
| 1032 | + // set of keypresses can be recorded | |
| 1033 | + self._keypressTimeout = null; | |
| 1034 | + | |
| 1035 | + // It's possible this handler might trigger multiple times for the same | |
| 1036 | + // event (e.g. event propagation through node ancestors). Ignore if we've | |
| 1037 | + // already captured the event. | |
| 1038 | + if (self._lastCapturedEvent === evt) return; | |
| 1039 | + | |
| 1040 | + self._lastCapturedEvent = evt; | |
| 1041 | + | |
| 1042 | + // try/catch both: | |
| 1043 | + // - accessing evt.target (see getsentry/raven-js#838, #768) | |
| 1044 | + // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly | |
| 1045 | + // can throw an exception in some circumstances. | |
| 1046 | + var target; | |
| 1047 | + try { | |
| 1048 | + target = htmlTreeAsString(evt.target); | |
| 1049 | + } catch (e) { | |
| 1050 | + target = "<unknown>"; | |
| 1051 | + } | |
| 1052 | + | |
| 1053 | + self.captureBreadcrumb({ | |
| 1054 | + category: "ui." + evtName, // e.g. ui.click, ui.input | |
| 1055 | + message: target, | |
| 1056 | + }); | |
| 1057 | + }; | |
| 1058 | + }, | |
| 1059 | + | |
| 1060 | + /** | |
| 1061 | + * Wraps addEventListener to capture keypress UI events | |
| 1062 | + * @returns {Function} | |
| 1063 | + * @private | |
| 1064 | + */ | |
| 1065 | + _keypressEventHandler: function () { | |
| 1066 | + var self = this, | |
| 1067 | + debounceDuration = 1000; // milliseconds | |
| 1068 | + | |
| 1069 | + // TODO: if somehow user switches keypress target before | |
| 1070 | + // debounce timeout is triggered, we will only capture | |
| 1071 | + // a single breadcrumb from the FIRST target (acceptable?) | |
| 1072 | + return function (evt) { | |
| 1073 | + var target; | |
| 1103 | 1074 | try { |
| 1104 | − eventType = evt.type; | |
| 1075 | + target = evt.target; | |
| 1105 | 1076 | } catch (e) { |
| 1106 | 1077 | // just accessing event properties can throw an exception in some rare circumstances |
| 1107 | 1078 | // see: https://github.com/getsentry/raven-js/issues/838 |
| 1108 | 1079 | return; |
| 1109 | 1080 | } |
| 1110 | − if (eventType === 'click') return clickHandler(evt); | |
| 1111 | − else if (eventType === 'keypress') return keypressHandler(evt); | |
| 1081 | + var tagName = target && target.tagName; | |
| 1082 | + | |
| 1083 | + // only consider keypress events on actual input elements | |
| 1084 | + // this will disregard keypresses targeting body (e.g. tabbing | |
| 1085 | + // through elements, hotkeys, etc) | |
| 1086 | + if ( | |
| 1087 | + !tagName || | |
| 1088 | + (tagName !== "INPUT" && | |
| 1089 | + tagName !== "TEXTAREA" && | |
| 1090 | + !target.isContentEditable) | |
| 1091 | + ) | |
| 1092 | + return; | |
| 1093 | + | |
| 1094 | + // record first keypress in a series, but ignore subsequent | |
| 1095 | + // keypresses until debounce clears | |
| 1096 | + var timeout = self._keypressTimeout; | |
| 1097 | + if (!timeout) { | |
| 1098 | + self._breadcrumbEventHandler("input")(evt); | |
| 1099 | + } | |
| 1100 | + clearTimeout(timeout); | |
| 1101 | + self._keypressTimeout = setTimeout(function () { | |
| 1102 | + self._keypressTimeout = null; | |
| 1103 | + }, debounceDuration); | |
| 1112 | 1104 | }; |
| 1113 | − } | |
| 1114 | − return orig.call( | |
| 1115 | − this, | |
| 1116 | − evtName, | |
| 1117 | − self.wrap(fn, undefined, before), | |
| 1118 | − capture, | |
| 1119 | − secure | |
| 1120 | − ); | |
| 1121 | − }; | |
| 1122 | − }, | |
| 1123 | − wrappedBuiltIns | |
| 1124 | − ); | |
| 1125 | − fill( | |
| 1126 | − proto, | |
| 1127 | − 'removeEventListener', | |
| 1128 | − function(orig) { | |
| 1129 | − return function(evt, fn, capture, secure) { | |
| 1130 | − try { | |
| 1131 | − fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn); | |
| 1132 | − } catch (e) { | |
| 1133 | − // ignore, accessing __raven_wrapper__ will throw in some Selenium environments | |
| 1134 | − } | |
| 1135 | − return orig.call(this, evt, fn, capture, secure); | |
| 1136 | − }; | |
| 1137 | − }, | |
| 1138 | − wrappedBuiltIns | |
| 1139 | − ); | |
| 1140 | − } | |
| 1141 | − } | |
| 1105 | + }, | |
| 1106 | + | |
| 1107 | + /** | |
| 1108 | + * Captures a breadcrumb of type "navigation", normalizing input URLs | |
| 1109 | + * @param to the originating URL | |
| 1110 | + * @param from the target URL | |
| 1111 | + * @private | |
| 1112 | + */ | |
| 1113 | + _captureUrlChange: function (from, to) { | |
| 1114 | + var parsedLoc = parseUrl(this._location.href); | |
| 1115 | + var parsedTo = parseUrl(to); | |
| 1116 | + var parsedFrom = parseUrl(from); | |
| 1117 | + | |
| 1118 | + // because onpopstate only tells you the "new" (to) value of location.href, and | |
| 1119 | + // not the previous (from) value, we need to track the value of the current URL | |
| 1120 | + // state ourselves | |
| 1121 | + this._lastHref = to; | |
| 1122 | + | |
| 1123 | + // Use only the path component of the URL if the URL matches the current | |
| 1124 | + // document (almost all the time when using pushState) | |
| 1125 | + if ( | |
| 1126 | + parsedLoc.protocol === parsedTo.protocol && | |
| 1127 | + parsedLoc.host === parsedTo.host | |
| 1128 | + ) | |
| 1129 | + to = parsedTo.relative; | |
| 1130 | + if ( | |
| 1131 | + parsedLoc.protocol === parsedFrom.protocol && | |
| 1132 | + parsedLoc.host === parsedFrom.host | |
| 1133 | + ) | |
| 1134 | + from = parsedFrom.relative; | |
| 1135 | + | |
| 1136 | + this.captureBreadcrumb({ | |
| 1137 | + category: "navigation", | |
| 1138 | + data: { | |
| 1139 | + to: to, | |
| 1140 | + from: from, | |
| 1141 | + }, | |
| 1142 | + }); | |
| 1143 | + }, | |
| 1144 | + | |
| 1145 | + _patchFunctionToString: function () { | |
| 1146 | + var self = this; | |
| 1147 | + self._originalFunctionToString = Function.prototype.toString; | |
| 1148 | + // eslint-disable-next-line no-extend-native | |
| 1149 | + Function.prototype.toString = function () { | |
| 1150 | + if (typeof this === "function" && this.__raven__) { | |
| 1151 | + return self._originalFunctionToString.apply( | |
| 1152 | + this.__orig__, | |
| 1153 | + arguments, | |
| 1154 | + ); | |
| 1155 | + } | |
| 1156 | + return self._originalFunctionToString.apply(this, arguments); | |
| 1157 | + }; | |
| 1158 | + }, | |
| 1142 | 1159 | |
| 1143 | − fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns); | |
| 1144 | − fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns); | |
| 1145 | − if (_window.requestAnimationFrame) { | |
| 1146 | − fill( | |
| 1147 | − _window, | |
| 1148 | − 'requestAnimationFrame', | |
| 1149 | − function(orig) { | |
| 1150 | − return function(cb) { | |
| 1151 | − return orig(self.wrap(cb)); | |
| 1152 | − }; | |
| 1153 | − }, | |
| 1154 | − wrappedBuiltIns | |
| 1155 | − ); | |
| 1156 | − } | |
| 1160 | + _unpatchFunctionToString: function () { | |
| 1161 | + if (this._originalFunctionToString) { | |
| 1162 | + // eslint-disable-next-line no-extend-native | |
| 1163 | + Function.prototype.toString = this._originalFunctionToString; | |
| 1164 | + } | |
| 1165 | + }, | |
| 1166 | + | |
| 1167 | + /** | |
| 1168 | + * Wrap timer functions and event targets to catch errors and provide | |
| 1169 | + * better metadata. | |
| 1170 | + */ | |
| 1171 | + _instrumentTryCatch: function () { | |
| 1172 | + var self = this; | |
| 1173 | + | |
| 1174 | + var wrappedBuiltIns = self._wrappedBuiltIns; | |
| 1175 | + | |
| 1176 | + function wrapTimeFn(orig) { | |
| 1177 | + return function (fn, t) { | |
| 1178 | + // preserve arity | |
| 1179 | + // Make a copy of the arguments to prevent deoptimization | |
| 1180 | + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments | |
| 1181 | + var args = new Array(arguments.length); | |
| 1182 | + for (var i = 0; i < args.length; ++i) { | |
| 1183 | + args[i] = arguments[i]; | |
| 1184 | + } | |
| 1185 | + var originalCallback = args[0]; | |
| 1186 | + if (isFunction(originalCallback)) { | |
| 1187 | + args[0] = self.wrap(originalCallback); | |
| 1188 | + } | |
| 1189 | + | |
| 1190 | + // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it | |
| 1191 | + // also supports only two arguments and doesn't care what this is, so we | |
| 1192 | + // can just call the original function directly. | |
| 1193 | + if (orig.apply) { | |
| 1194 | + return orig.apply(this, args); | |
| 1195 | + } else { | |
| 1196 | + return orig(args[0], args[1]); | |
| 1197 | + } | |
| 1198 | + }; | |
| 1199 | + } | |
| 1157 | 1200 | |
| 1158 | − // event targets borrowed from bugsnag-js: | |
| 1159 | − // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666 | |
| 1160 | − var eventTargets = [ | |
| 1161 | − 'EventTarget', | |
| 1162 | − 'Window', | |
| 1163 | − 'Node', | |
| 1164 | − 'ApplicationCache', | |
| 1165 | − 'AudioTrackList', | |
| 1166 | − 'ChannelMergerNode', | |
| 1167 | − 'CryptoOperation', | |
| 1168 | − 'EventSource', | |
| 1169 | − 'FileReader', | |
| 1170 | − 'HTMLUnknownElement', | |
| 1171 | − 'IDBDatabase', | |
| 1172 | − 'IDBRequest', | |
| 1173 | − 'IDBTransaction', | |
| 1174 | − 'KeyOperation', | |
| 1175 | − 'MediaController', | |
| 1176 | − 'MessagePort', | |
| 1177 | − 'ModalWindow', | |
| 1178 | − 'Notification', | |
| 1179 | − 'SVGElementInstance', | |
| 1180 | − 'Screen', | |
| 1181 | − 'TextTrack', | |
| 1182 | − 'TextTrackCue', | |
| 1183 | − 'TextTrackList', | |
| 1184 | − 'WebSocket', | |
| 1185 | − 'WebSocketWorker', | |
| 1186 | − 'Worker', | |
| 1187 | − 'XMLHttpRequest', | |
| 1188 | − 'XMLHttpRequestEventTarget', | |
| 1189 | − 'XMLHttpRequestUpload' | |
| 1190 | − ]; | |
| 1191 | − for (var i = 0; i < eventTargets.length; i++) { | |
| 1192 | − wrapEventTarget(eventTargets[i]); | |
| 1193 | − } | |
| 1194 | − }, | |
| 1195 | − | |
| 1196 | − /** | |
| 1197 | − * Instrument browser built-ins w/ breadcrumb capturing | |
| 1198 | − * - XMLHttpRequests | |
| 1199 | − * - DOM interactions (click/typing) | |
| 1200 | − * - window.location changes | |
| 1201 | − * - console | |
| 1202 | − * | |
| 1203 | − * Can be disabled or individually configured via the `autoBreadcrumbs` config option | |
| 1204 | − */ | |
| 1205 | − _instrumentBreadcrumbs: function() { | |
| 1206 | − var self = this; | |
| 1207 | − var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs; | |
| 1208 | − | |
| 1209 | − var wrappedBuiltIns = self._wrappedBuiltIns; | |
| 1210 | − | |
| 1211 | − function wrapProp(prop, xhr) { | |
| 1212 | − if (prop in xhr && isFunction(xhr[prop])) { | |
| 1213 | − fill(xhr, prop, function(orig) { | |
| 1214 | − return self.wrap(orig); | |
| 1215 | − }); // intentionally don't track filled methods on XHR instances | |
| 1216 | − } | |
| 1217 | − } | |
| 1201 | + var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs; | |
| 1202 | + | |
| 1203 | + function wrapEventTarget(global) { | |
| 1204 | + var proto = _window[global] && _window[global].prototype; | |
| 1205 | + if ( | |
| 1206 | + proto && | |
| 1207 | + proto.hasOwnProperty && | |
| 1208 | + proto.hasOwnProperty("addEventListener") | |
| 1209 | + ) { | |
| 1210 | + fill( | |
| 1211 | + proto, | |
| 1212 | + "addEventListener", | |
| 1213 | + function (orig) { | |
| 1214 | + return function (evtName, fn, capture, secure) { | |
| 1215 | + // preserve arity | |
| 1216 | + try { | |
| 1217 | + if (fn && fn.handleEvent) { | |
| 1218 | + fn.handleEvent = self.wrap(fn.handleEvent); | |
| 1219 | + } | |
| 1220 | + } catch (err) { | |
| 1221 | + // can sometimes get 'Permission denied to access property "handle Event' | |
| 1222 | + } | |
| 1223 | + | |
| 1224 | + // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs` | |
| 1225 | + // so that we don't have more than one wrapper function | |
| 1226 | + var before, clickHandler, keypressHandler; | |
| 1227 | + | |
| 1228 | + if ( | |
| 1229 | + autoBreadcrumbs && | |
| 1230 | + autoBreadcrumbs.dom && | |
| 1231 | + (global === "EventTarget" || global === "Node") | |
| 1232 | + ) { | |
| 1233 | + // NOTE: generating multiple handlers per addEventListener invocation, should | |
| 1234 | + // revisit and verify we can just use one (almost certainly) | |
| 1235 | + clickHandler = | |
| 1236 | + self._breadcrumbEventHandler("click"); | |
| 1237 | + keypressHandler = self._keypressEventHandler(); | |
| 1238 | + before = function (evt) { | |
| 1239 | + // need to intercept every DOM event in `before` argument, in case that | |
| 1240 | + // same wrapped method is re-used for different events (e.g. mousemove THEN click) | |
| 1241 | + // see #724 | |
| 1242 | + if (!evt) return; | |
| 1243 | + | |
| 1244 | + var eventType; | |
| 1245 | + try { | |
| 1246 | + eventType = evt.type; | |
| 1247 | + } catch (e) { | |
| 1248 | + // just accessing event properties can throw an exception in some rare circumstances | |
| 1249 | + // see: https://github.com/getsentry/raven-js/issues/838 | |
| 1250 | + return; | |
| 1251 | + } | |
| 1252 | + if (eventType === "click") | |
| 1253 | + return clickHandler(evt); | |
| 1254 | + else if (eventType === "keypress") | |
| 1255 | + return keypressHandler(evt); | |
| 1256 | + }; | |
| 1257 | + } | |
| 1258 | + return orig.call( | |
| 1259 | + this, | |
| 1260 | + evtName, | |
| 1261 | + self.wrap(fn, undefined, before), | |
| 1262 | + capture, | |
| 1263 | + secure, | |
| 1264 | + ); | |
| 1265 | + }; | |
| 1266 | + }, | |
| 1267 | + wrappedBuiltIns, | |
| 1268 | + ); | |
| 1269 | + fill( | |
| 1270 | + proto, | |
| 1271 | + "removeEventListener", | |
| 1272 | + function (orig) { | |
| 1273 | + return function (evt, fn, capture, secure) { | |
| 1274 | + try { | |
| 1275 | + fn = | |
| 1276 | + fn && | |
| 1277 | + (fn.__raven_wrapper__ | |
| 1278 | + ? fn.__raven_wrapper__ | |
| 1279 | + : fn); | |
| 1280 | + } catch (e) { | |
| 1281 | + // ignore, accessing __raven_wrapper__ will throw in some Selenium environments | |
| 1282 | + } | |
| 1283 | + return orig.call(this, evt, fn, capture, secure); | |
| 1284 | + }; | |
| 1285 | + }, | |
| 1286 | + wrappedBuiltIns, | |
| 1287 | + ); | |
| 1288 | + } | |
| 1289 | + } | |
| 1218 | 1290 | |
| 1219 | − if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) { | |
| 1220 | − var xhrproto = XMLHttpRequest.prototype; | |
| 1221 | − fill( | |
| 1222 | − xhrproto, | |
| 1223 | − 'open', | |
| 1224 | − function(origOpen) { | |
| 1225 | − return function(method, url) { | |
| 1226 | − // preserve arity | |
| 1227 | − | |
| 1228 | − // if Sentry key appears in URL, don't capture | |
| 1229 | − if (isString(url) && url.indexOf(self._globalKey) === -1) { | |
| 1230 | − this.__raven_xhr = { | |
| 1231 | − method: method, | |
| 1232 | − url: url, | |
| 1233 | − status_code: null | |
| 1234 | − }; | |
| 1235 | − } | |
| 1291 | + fill(_window, "setTimeout", wrapTimeFn, wrappedBuiltIns); | |
| 1292 | + fill(_window, "setInterval", wrapTimeFn, wrappedBuiltIns); | |
| 1293 | + if (_window.requestAnimationFrame) { | |
| 1294 | + fill( | |
| 1295 | + _window, | |
| 1296 | + "requestAnimationFrame", | |
| 1297 | + function (orig) { | |
| 1298 | + return function (cb) { | |
| 1299 | + return orig(self.wrap(cb)); | |
| 1300 | + }; | |
| 1301 | + }, | |
| 1302 | + wrappedBuiltIns, | |
| 1303 | + ); | |
| 1304 | + } | |
| 1236 | 1305 | |
| 1237 | − return origOpen.apply(this, arguments); | |
| 1238 | − }; | |
| 1239 | − }, | |
| 1240 | − wrappedBuiltIns | |
| 1241 | − ); | |
| 1242 | − | |
| 1243 | − fill( | |
| 1244 | − xhrproto, | |
| 1245 | − 'send', | |
| 1246 | − function(origSend) { | |
| 1247 | − return function(data) { | |
| 1248 | − // preserve arity | |
| 1249 | − var xhr = this; | |
| 1250 | − | |
| 1251 | − function onreadystatechangeHandler() { | |
| 1252 | − if (xhr.__raven_xhr && xhr.readyState === 4) { | |
| 1253 | − try { | |
| 1254 | − // touching statusCode in some platforms throws | |
| 1255 | − // an exception | |
| 1256 | − xhr.__raven_xhr.status_code = xhr.status; | |
| 1257 | − } catch (e) { | |
| 1258 | − /* do nothing */ | |
| 1306 | + // event targets borrowed from bugsnag-js: | |
| 1307 | + // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666 | |
| 1308 | + var eventTargets = [ | |
| 1309 | + "EventTarget", | |
| 1310 | + "Window", | |
| 1311 | + "Node", | |
| 1312 | + "ApplicationCache", | |
| 1313 | + "AudioTrackList", | |
| 1314 | + "ChannelMergerNode", | |
| 1315 | + "CryptoOperation", | |
| 1316 | + "EventSource", | |
| 1317 | + "FileReader", | |
| 1318 | + "HTMLUnknownElement", | |
| 1319 | + "IDBDatabase", | |
| 1320 | + "IDBRequest", | |
| 1321 | + "IDBTransaction", | |
| 1322 | + "KeyOperation", | |
| 1323 | + "MediaController", | |
| 1324 | + "MessagePort", | |
| 1325 | + "ModalWindow", | |
| 1326 | + "Notification", | |
| 1327 | + "SVGElementInstance", | |
| 1328 | + "Screen", | |
| 1329 | + "TextTrack", | |
| 1330 | + "TextTrackCue", | |
| 1331 | + "TextTrackList", | |
| 1332 | + "WebSocket", | |
| 1333 | + "WebSocketWorker", | |
| 1334 | + "Worker", | |
| 1335 | + "XMLHttpRequest", | |
| 1336 | + "XMLHttpRequestEventTarget", | |
| 1337 | + "XMLHttpRequestUpload", | |
| 1338 | + ]; | |
| 1339 | + for (var i = 0; i < eventTargets.length; i++) { | |
| 1340 | + wrapEventTarget(eventTargets[i]); | |
| 1341 | + } | |
| 1342 | + }, | |
| 1343 | + | |
| 1344 | + /** | |
| 1345 | + * Instrument browser built-ins w/ breadcrumb capturing | |
| 1346 | + * - XMLHttpRequests | |
| 1347 | + * - DOM interactions (click/typing) | |
| 1348 | + * - window.location changes | |
| 1349 | + * - console | |
| 1350 | + * | |
| 1351 | + * Can be disabled or individually configured via the `autoBreadcrumbs` config option | |
| 1352 | + */ | |
| 1353 | + _instrumentBreadcrumbs: function () { | |
| 1354 | + var self = this; | |
| 1355 | + var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs; | |
| 1356 | + | |
| 1357 | + var wrappedBuiltIns = self._wrappedBuiltIns; | |
| 1358 | + | |
| 1359 | + function wrapProp(prop, xhr) { | |
| 1360 | + if (prop in xhr && isFunction(xhr[prop])) { | |
| 1361 | + fill(xhr, prop, function (orig) { | |
| 1362 | + return self.wrap(orig); | |
| 1363 | + }); // intentionally don't track filled methods on XHR instances | |
| 1364 | + } | |
| 1259 | 1365 | } |
| 1260 | 1366 | |
| 1261 | − self.captureBreadcrumb({ | |
| 1262 | − type: 'http', | |
| 1263 | − category: 'xhr', | |
| 1264 | − data: xhr.__raven_xhr | |
| 1265 | − }); | |
| 1266 | − } | |
| 1267 | − } | |
| 1367 | + if (autoBreadcrumbs.xhr && "XMLHttpRequest" in _window) { | |
| 1368 | + var xhrproto = XMLHttpRequest.prototype; | |
| 1369 | + fill( | |
| 1370 | + xhrproto, | |
| 1371 | + "open", | |
| 1372 | + function (origOpen) { | |
| 1373 | + return function (method, url) { | |
| 1374 | + // preserve arity | |
| 1375 | + | |
| 1376 | + // if Sentry key appears in URL, don't capture | |
| 1377 | + if ( | |
| 1378 | + isString(url) && | |
| 1379 | + url.indexOf(self._globalKey) === -1 | |
| 1380 | + ) { | |
| 1381 | + this.__raven_xhr = { | |
| 1382 | + method: method, | |
| 1383 | + url: url, | |
| 1384 | + status_code: null, | |
| 1385 | + }; | |
| 1386 | + } | |
| 1387 | + | |
| 1388 | + return origOpen.apply(this, arguments); | |
| 1389 | + }; | |
| 1390 | + }, | |
| 1391 | + wrappedBuiltIns, | |
| 1392 | + ); | |
| 1393 | + | |
| 1394 | + fill( | |
| 1395 | + xhrproto, | |
| 1396 | + "send", | |
| 1397 | + function (origSend) { | |
| 1398 | + return function (data) { | |
| 1399 | + // preserve arity | |
| 1400 | + var xhr = this; | |
| 1401 | + | |
| 1402 | + function onreadystatechangeHandler() { | |
| 1403 | + if (xhr.__raven_xhr && xhr.readyState === 4) { | |
| 1404 | + try { | |
| 1405 | + // touching statusCode in some platforms throws | |
| 1406 | + // an exception | |
| 1407 | + xhr.__raven_xhr.status_code = xhr.status; | |
| 1408 | + } catch (e) { | |
| 1409 | + /* do nothing */ | |
| 1410 | + } | |
| 1411 | + | |
| 1412 | + self.captureBreadcrumb({ | |
| 1413 | + type: "http", | |
| 1414 | + category: "xhr", | |
| 1415 | + data: xhr.__raven_xhr, | |
| 1416 | + }); | |
| 1417 | + } | |
| 1418 | + } | |
| 1419 | + | |
| 1420 | + var props = ["onload", "onerror", "onprogress"]; | |
| 1421 | + for (var j = 0; j < props.length; j++) { | |
| 1422 | + wrapProp(props[j], xhr); | |
| 1423 | + } | |
| 1424 | + | |
| 1425 | + if ( | |
| 1426 | + "onreadystatechange" in xhr && | |
| 1427 | + isFunction(xhr.onreadystatechange) | |
| 1428 | + ) { | |
| 1429 | + fill( | |
| 1430 | + xhr, | |
| 1431 | + "onreadystatechange", | |
| 1432 | + function (orig) { | |
| 1433 | + return self.wrap( | |
| 1434 | + orig, | |
| 1435 | + undefined, | |
| 1436 | + onreadystatechangeHandler, | |
| 1437 | + ); | |
| 1438 | + } /* intentionally don't track this instrumentation */, | |
| 1439 | + ); | |
| 1440 | + } else { | |
| 1441 | + // if onreadystatechange wasn't actually set by the page on this xhr, we | |
| 1442 | + // are free to set our own and capture the breadcrumb | |
| 1443 | + xhr.onreadystatechange = onreadystatechangeHandler; | |
| 1444 | + } | |
| 1445 | + | |
| 1446 | + return origSend.apply(this, arguments); | |
| 1447 | + }; | |
| 1448 | + }, | |
| 1449 | + wrappedBuiltIns, | |
| 1450 | + ); | |
| 1451 | + } | |
| 1268 | 1452 | |
| 1269 | − var props = ['onload', 'onerror', 'onprogress']; | |
| 1270 | − for (var j = 0; j < props.length; j++) { | |
| 1271 | − wrapProp(props[j], xhr); | |
| 1272 | − } | |
| 1453 | + if (autoBreadcrumbs.xhr && "fetch" in _window) { | |
| 1454 | + fill( | |
| 1455 | + _window, | |
| 1456 | + "fetch", | |
| 1457 | + function (origFetch) { | |
| 1458 | + return function (fn, t) { | |
| 1459 | + // preserve arity | |
| 1460 | + // Make a copy of the arguments to prevent deoptimization | |
| 1461 | + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments | |
| 1462 | + var args = new Array(arguments.length); | |
| 1463 | + for (var i = 0; i < args.length; ++i) { | |
| 1464 | + args[i] = arguments[i]; | |
| 1465 | + } | |
| 1466 | + | |
| 1467 | + var fetchInput = args[0]; | |
| 1468 | + var method = "GET"; | |
| 1469 | + var url; | |
| 1470 | + | |
| 1471 | + if (typeof fetchInput === "string") { | |
| 1472 | + url = fetchInput; | |
| 1473 | + } else if ( | |
| 1474 | + "Request" in _window && | |
| 1475 | + fetchInput instanceof _window.Request | |
| 1476 | + ) { | |
| 1477 | + url = fetchInput.url; | |
| 1478 | + if (fetchInput.method) { | |
| 1479 | + method = fetchInput.method; | |
| 1480 | + } | |
| 1481 | + } else { | |
| 1482 | + url = "" + fetchInput; | |
| 1483 | + } | |
| 1484 | + | |
| 1485 | + if (args[1] && args[1].method) { | |
| 1486 | + method = args[1].method; | |
| 1487 | + } | |
| 1488 | + | |
| 1489 | + var fetchData = { | |
| 1490 | + method: method, | |
| 1491 | + url: url, | |
| 1492 | + status_code: null, | |
| 1493 | + }; | |
| 1494 | + | |
| 1495 | + self.captureBreadcrumb({ | |
| 1496 | + type: "http", | |
| 1497 | + category: "fetch", | |
| 1498 | + data: fetchData, | |
| 1499 | + }); | |
| 1500 | + | |
| 1501 | + return origFetch | |
| 1502 | + .apply(this, args) | |
| 1503 | + .then(function (response) { | |
| 1504 | + fetchData.status_code = response.status; | |
| 1505 | + | |
| 1506 | + return response; | |
| 1507 | + }); | |
| 1508 | + }; | |
| 1509 | + }, | |
| 1510 | + wrappedBuiltIns, | |
| 1511 | + ); | |
| 1512 | + } | |
| 1273 | 1513 | |
| 1274 | − if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) { | |
| 1275 | − fill( | |
| 1276 | − xhr, | |
| 1277 | − 'onreadystatechange', | |
| 1278 | − function(orig) { | |
| 1279 | − return self.wrap(orig, undefined, onreadystatechangeHandler); | |
| 1280 | − } /* intentionally don't track this instrumentation */ | |
| 1281 | − ); | |
| 1282 | − } else { | |
| 1283 | − // if onreadystatechange wasn't actually set by the page on this xhr, we | |
| 1284 | − // are free to set our own and capture the breadcrumb | |
| 1285 | − xhr.onreadystatechange = onreadystatechangeHandler; | |
| 1286 | − } | |
| 1514 | + // Capture breadcrumbs from any click that is unhandled / bubbled up all the way | |
| 1515 | + // to the document. Do this before we instrument addEventListener. | |
| 1516 | + if (autoBreadcrumbs.dom && this._hasDocument) { | |
| 1517 | + if (_document.addEventListener) { | |
| 1518 | + _document.addEventListener( | |
| 1519 | + "click", | |
| 1520 | + self._breadcrumbEventHandler("click"), | |
| 1521 | + false, | |
| 1522 | + ); | |
| 1523 | + _document.addEventListener( | |
| 1524 | + "keypress", | |
| 1525 | + self._keypressEventHandler(), | |
| 1526 | + false, | |
| 1527 | + ); | |
| 1528 | + } else { | |
| 1529 | + // IE8 Compatibility | |
| 1530 | + _document.attachEvent( | |
| 1531 | + "onclick", | |
| 1532 | + self._breadcrumbEventHandler("click"), | |
| 1533 | + ); | |
| 1534 | + _document.attachEvent( | |
| 1535 | + "onkeypress", | |
| 1536 | + self._keypressEventHandler(), | |
| 1537 | + ); | |
| 1538 | + } | |
| 1539 | + } | |
| 1287 | 1540 | |
| 1288 | − return origSend.apply(this, arguments); | |
| 1289 | − }; | |
| 1290 | − }, | |
| 1291 | − wrappedBuiltIns | |
| 1292 | − ); | |
| 1293 | − } | |
| 1541 | + // record navigation (URL) changes | |
| 1542 | + // NOTE: in Chrome App environment, touching history.pushState, *even inside | |
| 1543 | + // a try/catch block*, will cause Chrome to output an error to console.error | |
| 1544 | + // borrowed from: https://github.com/angular/angular.js/pull/13945/files | |
| 1545 | + var chrome = _window.chrome; | |
| 1546 | + var isChromePackagedApp = | |
| 1547 | + chrome && chrome.app && chrome.app.runtime; | |
| 1548 | + var hasPushAndReplaceState = | |
| 1549 | + !isChromePackagedApp && | |
| 1550 | + _window.history && | |
| 1551 | + history.pushState && | |
| 1552 | + history.replaceState; | |
| 1553 | + if (autoBreadcrumbs.location && hasPushAndReplaceState) { | |
| 1554 | + // TODO: remove onpopstate handler on uninstall() | |
| 1555 | + var oldOnPopState = _window.onpopstate; | |
| 1556 | + _window.onpopstate = function () { | |
| 1557 | + var currentHref = self._location.href; | |
| 1558 | + self._captureUrlChange(self._lastHref, currentHref); | |
| 1559 | + | |
| 1560 | + if (oldOnPopState) { | |
| 1561 | + return oldOnPopState.apply(this, arguments); | |
| 1562 | + } | |
| 1563 | + }; | |
| 1564 | + | |
| 1565 | + var historyReplacementFunction = function (origHistFunction) { | |
| 1566 | + // note history.pushState.length is 0; intentionally not declaring | |
| 1567 | + // params to preserve 0 arity | |
| 1568 | + return function (/* state, title, url */) { | |
| 1569 | + var url = arguments.length > 2 ? arguments[2] : undefined; | |
| 1570 | + | |
| 1571 | + // url argument is optional | |
| 1572 | + if (url) { | |
| 1573 | + // coerce to string (this is what pushState does) | |
| 1574 | + self._captureUrlChange(self._lastHref, url + ""); | |
| 1575 | + } | |
| 1576 | + | |
| 1577 | + return origHistFunction.apply(this, arguments); | |
| 1578 | + }; | |
| 1579 | + }; | |
| 1580 | + | |
| 1581 | + fill( | |
| 1582 | + history, | |
| 1583 | + "pushState", | |
| 1584 | + historyReplacementFunction, | |
| 1585 | + wrappedBuiltIns, | |
| 1586 | + ); | |
| 1587 | + fill( | |
| 1588 | + history, | |
| 1589 | + "replaceState", | |
| 1590 | + historyReplacementFunction, | |
| 1591 | + wrappedBuiltIns, | |
| 1592 | + ); | |
| 1593 | + } | |
| 1294 | 1594 | |
| 1295 | − if (autoBreadcrumbs.xhr && 'fetch' in _window) { | |
| 1296 | − fill( | |
| 1297 | − _window, | |
| 1298 | − 'fetch', | |
| 1299 | − function(origFetch) { | |
| 1300 | − return function(fn, t) { | |
| 1301 | − // preserve arity | |
| 1302 | − // Make a copy of the arguments to prevent deoptimization | |
| 1303 | − // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments | |
| 1304 | − var args = new Array(arguments.length); | |
| 1305 | − for (var i = 0; i < args.length; ++i) { | |
| 1306 | − args[i] = arguments[i]; | |
| 1307 | − } | |
| 1595 | + if ( | |
| 1596 | + autoBreadcrumbs.console && | |
| 1597 | + "console" in _window && | |
| 1598 | + console.log | |
| 1599 | + ) { | |
| 1600 | + // console | |
| 1601 | + var consoleMethodCallback = function (msg, data) { | |
| 1602 | + self.captureBreadcrumb({ | |
| 1603 | + message: msg, | |
| 1604 | + level: data.level, | |
| 1605 | + category: "console", | |
| 1606 | + }); | |
| 1607 | + }; | |
| 1608 | + | |
| 1609 | + each( | |
| 1610 | + ["debug", "info", "warn", "error", "log"], | |
| 1611 | + function (_, level) { | |
| 1612 | + wrapConsoleMethod(console, level, consoleMethodCallback); | |
| 1613 | + }, | |
| 1614 | + ); | |
| 1615 | + } | |
| 1616 | + }, | |
| 1308 | 1617 | |
| 1309 | − var fetchInput = args[0]; | |
| 1310 | − var method = 'GET'; | |
| 1311 | − var url; | |
| 1618 | + _restoreBuiltIns: function () { | |
| 1619 | + // restore any wrapped builtins | |
| 1620 | + var builtin; | |
| 1621 | + while (this._wrappedBuiltIns.length) { | |
| 1622 | + builtin = this._wrappedBuiltIns.shift(); | |
| 1312 | 1623 | |
| 1313 | − if (typeof fetchInput === 'string') { | |
| 1314 | − url = fetchInput; | |
| 1315 | − } else if ('Request' in _window && fetchInput instanceof _window.Request) { | |
| 1316 | − url = fetchInput.url; | |
| 1317 | − if (fetchInput.method) { | |
| 1318 | − method = fetchInput.method; | |
| 1319 | − } | |
| 1320 | − } else { | |
| 1321 | − url = '' + fetchInput; | |
| 1322 | − } | |
| 1624 | + var obj = builtin[0], | |
| 1625 | + name = builtin[1], | |
| 1626 | + orig = builtin[2]; | |
| 1323 | 1627 | |
| 1324 | − if (args[1] && args[1].method) { | |
| 1325 | − method = args[1].method; | |
| 1326 | − } | |
| 1628 | + obj[name] = orig; | |
| 1629 | + } | |
| 1630 | + }, | |
| 1327 | 1631 | |
| 1328 | − var fetchData = { | |
| 1329 | − method: method, | |
| 1330 | − url: url, | |
| 1331 | − status_code: null | |
| 1332 | − }; | |
| 1632 | + _drainPlugins: function () { | |
| 1633 | + var self = this; | |
| 1333 | 1634 | |
| 1334 | − self.captureBreadcrumb({ | |
| 1335 | − type: 'http', | |
| 1336 | − category: 'fetch', | |
| 1337 | − data: fetchData | |
| 1338 | − }); | |
| 1635 | + // FIX ME TODO | |
| 1636 | + each(this._plugins, function (_, plugin) { | |
| 1637 | + var installer = plugin[0]; | |
| 1638 | + var args = plugin[1]; | |
| 1639 | + installer.apply(self, [self].concat(args)); | |
| 1640 | + }); | |
| 1641 | + }, | |
| 1339 | 1642 | |
| 1340 | − return origFetch.apply(this, args).then(function(response) { | |
| 1341 | − fetchData.status_code = response.status; | |
| 1643 | + _parseDSN: function (str) { | |
| 1644 | + var m = dsnPattern.exec(str), | |
| 1645 | + dsn = {}, | |
| 1646 | + i = 7; | |
| 1342 | 1647 | |
| 1343 | − return response; | |
| 1344 | − }); | |
| 1345 | − }; | |
| 1346 | − }, | |
| 1347 | − wrappedBuiltIns | |
| 1348 | − ); | |
| 1349 | − } | |
| 1648 | + try { | |
| 1649 | + while (i--) dsn[dsnKeys[i]] = m[i] || ""; | |
| 1650 | + } catch (e) { | |
| 1651 | + throw new RavenConfigError("Invalid DSN: " + str); | |
| 1652 | + } | |
| 1350 | 1653 | |
| 1351 | − // Capture breadcrumbs from any click that is unhandled / bubbled up all the way | |
| 1352 | − // to the document. Do this before we instrument addEventListener. | |
| 1353 | − if (autoBreadcrumbs.dom && this._hasDocument) { | |
| 1354 | − if (_document.addEventListener) { | |
| 1355 | − _document.addEventListener('click', self._breadcrumbEventHandler('click'), false); | |
| 1356 | − _document.addEventListener('keypress', self._keypressEventHandler(), false); | |
| 1357 | − } else { | |
| 1358 | − // IE8 Compatibility | |
| 1359 | − _document.attachEvent('onclick', self._breadcrumbEventHandler('click')); | |
| 1360 | − _document.attachEvent('onkeypress', self._keypressEventHandler()); | |
| 1361 | − } | |
| 1362 | − } | |
| 1654 | + if (dsn.pass && !this._globalOptions.allowSecretKey) { | |
| 1655 | + throw new RavenConfigError( | |
| 1656 | + "Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key", | |
| 1657 | + ); | |
| 1658 | + } | |
| 1363 | 1659 | |
| 1364 | − // record navigation (URL) changes | |
| 1365 | − // NOTE: in Chrome App environment, touching history.pushState, *even inside | |
| 1366 | − // a try/catch block*, will cause Chrome to output an error to console.error | |
| 1367 | − // borrowed from: https://github.com/angular/angular.js/pull/13945/files | |
| 1368 | − var chrome = _window.chrome; | |
| 1369 | − var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime; | |
| 1370 | − var hasPushAndReplaceState = | |
| 1371 | − !isChromePackagedApp && | |
| 1372 | − _window.history && | |
| 1373 | − history.pushState && | |
| 1374 | − history.replaceState; | |
| 1375 | − if (autoBreadcrumbs.location && hasPushAndReplaceState) { | |
| 1376 | − // TODO: remove onpopstate handler on uninstall() | |
| 1377 | − var oldOnPopState = _window.onpopstate; | |
| 1378 | − _window.onpopstate = function() { | |
| 1379 | − var currentHref = self._location.href; | |
| 1380 | − self._captureUrlChange(self._lastHref, currentHref); | |
| 1381 | − | |
| 1382 | − if (oldOnPopState) { | |
| 1383 | − return oldOnPopState.apply(this, arguments); | |
| 1384 | − } | |
| 1385 | − }; | |
| 1386 | − | |
| 1387 | − var historyReplacementFunction = function(origHistFunction) { | |
| 1388 | − // note history.pushState.length is 0; intentionally not declaring | |
| 1389 | − // params to preserve 0 arity | |
| 1390 | − return function(/* state, title, url */) { | |
| 1391 | − var url = arguments.length > 2 ? arguments[2] : undefined; | |
| 1392 | − | |
| 1393 | − // url argument is optional | |
| 1394 | − if (url) { | |
| 1395 | − // coerce to string (this is what pushState does) | |
| 1396 | − self._captureUrlChange(self._lastHref, url + ''); | |
| 1397 | − } | |
| 1660 | + return dsn; | |
| 1661 | + }, | |
| 1398 | 1662 | |
| 1399 | − return origHistFunction.apply(this, arguments); | |
| 1400 | − }; | |
| 1401 | − }; | |
| 1663 | + _getGlobalServer: function (uri) { | |
| 1664 | + // assemble the endpoint from the uri pieces | |
| 1665 | + var globalServer = | |
| 1666 | + "//" + uri.host + (uri.port ? ":" + uri.port : ""); | |
| 1402 | 1667 | |
| 1403 | − fill(history, 'pushState', historyReplacementFunction, wrappedBuiltIns); | |
| 1404 | − fill(history, 'replaceState', historyReplacementFunction, wrappedBuiltIns); | |
| 1405 | − } | |
| 1668 | + if (uri.protocol) { | |
| 1669 | + globalServer = uri.protocol + ":" + globalServer; | |
| 1670 | + } | |
| 1671 | + return globalServer; | |
| 1672 | + }, | |
| 1406 | 1673 | |
| 1407 | − if (autoBreadcrumbs.console && 'console' in _window && console.log) { | |
| 1408 | − // console | |
| 1409 | − var consoleMethodCallback = function(msg, data) { | |
| 1410 | − self.captureBreadcrumb({ | |
| 1411 | − message: msg, | |
| 1412 | − level: data.level, | |
| 1413 | − category: 'console' | |
| 1414 | − }); | |
| 1415 | − }; | |
| 1416 | − | |
| 1417 | − each(['debug', 'info', 'warn', 'error', 'log'], function(_, level) { | |
| 1418 | − wrapConsoleMethod(console, level, consoleMethodCallback); | |
| 1419 | − }); | |
| 1420 | − } | |
| 1421 | − }, | |
| 1674 | + _handleOnErrorStackInfo: function () { | |
| 1675 | + // if we are intentionally ignoring errors via onerror, bail out | |
| 1676 | + if (!this._ignoreOnError) { | |
| 1677 | + this._handleStackInfo.apply(this, arguments); | |
| 1678 | + } | |
| 1679 | + }, | |
| 1422 | 1680 | |
| 1423 | − _restoreBuiltIns: function() { | |
| 1424 | − // restore any wrapped builtins | |
| 1425 | − var builtin; | |
| 1426 | − while (this._wrappedBuiltIns.length) { | |
| 1427 | − builtin = this._wrappedBuiltIns.shift(); | |
| 1681 | + _handleStackInfo: function (stackInfo, options) { | |
| 1682 | + var frames = this._prepareFrames(stackInfo, options); | |
| 1428 | 1683 | |
| 1429 | − var obj = builtin[0], | |
| 1430 | − name = builtin[1], | |
| 1431 | − orig = builtin[2]; | |
| 1684 | + this._triggerEvent("handle", { | |
| 1685 | + stackInfo: stackInfo, | |
| 1686 | + options: options, | |
| 1687 | + }); | |
| 1432 | 1688 | |
| 1433 | − obj[name] = orig; | |
| 1434 | − } | |
| 1435 | − }, | |
| 1436 | − | |
| 1437 | − _drainPlugins: function() { | |
| 1438 | − var self = this; | |
| 1439 | − | |
| 1440 | − // FIX ME TODO | |
| 1441 | − each(this._plugins, function(_, plugin) { | |
| 1442 | − var installer = plugin[0]; | |
| 1443 | − var args = plugin[1]; | |
| 1444 | − installer.apply(self, [self].concat(args)); | |
| 1445 | − }); | |
| 1446 | − }, | |
| 1447 | − | |
| 1448 | − _parseDSN: function(str) { | |
| 1449 | − var m = dsnPattern.exec(str), | |
| 1450 | − dsn = {}, | |
| 1451 | − i = 7; | |
| 1452 | − | |
| 1453 | − try { | |
| 1454 | − while (i--) dsn[dsnKeys[i]] = m[i] || ''; | |
| 1455 | − } catch (e) { | |
| 1456 | − throw new RavenConfigError('Invalid DSN: ' + str); | |
| 1457 | − } | |
| 1689 | + this._processException( | |
| 1690 | + stackInfo.name, | |
| 1691 | + stackInfo.message, | |
| 1692 | + stackInfo.url, | |
| 1693 | + stackInfo.lineno, | |
| 1694 | + frames, | |
| 1695 | + options, | |
| 1696 | + ); | |
| 1697 | + }, | |
| 1698 | + | |
| 1699 | + _prepareFrames: function (stackInfo, options) { | |
| 1700 | + var self = this; | |
| 1701 | + var frames = []; | |
| 1702 | + if (stackInfo.stack && stackInfo.stack.length) { | |
| 1703 | + each(stackInfo.stack, function (i, stack) { | |
| 1704 | + var frame = self._normalizeFrame(stack, stackInfo.url); | |
| 1705 | + if (frame) { | |
| 1706 | + frames.push(frame); | |
| 1707 | + } | |
| 1708 | + }); | |
| 1709 | + | |
| 1710 | + // e.g. frames captured via captureMessage throw | |
| 1711 | + if (options && options.trimHeadFrames) { | |
| 1712 | + for ( | |
| 1713 | + var j = 0; | |
| 1714 | + j < options.trimHeadFrames && j < frames.length; | |
| 1715 | + j++ | |
| 1716 | + ) { | |
| 1717 | + frames[j].in_app = false; | |
| 1718 | + } | |
| 1719 | + } | |
| 1720 | + } | |
| 1721 | + frames = frames.slice(0, this._globalOptions.stackTraceLimit); | |
| 1722 | + return frames; | |
| 1723 | + }, | |
| 1724 | + | |
| 1725 | + _normalizeFrame: function (frame, stackInfoUrl) { | |
| 1726 | + // normalize the frames data | |
| 1727 | + var normalized = { | |
| 1728 | + filename: frame.url, | |
| 1729 | + lineno: frame.line, | |
| 1730 | + colno: frame.column, | |
| 1731 | + function: frame.func || "?", | |
| 1732 | + }; | |
| 1458 | 1733 | |
| 1459 | − if (dsn.pass && !this._globalOptions.allowSecretKey) { | |
| 1460 | − throw new RavenConfigError( | |
| 1461 | − 'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key' | |
| 1462 | − ); | |
| 1463 | − } | |
| 1734 | + // Case when we don't have any information about the error | |
| 1735 | + // E.g. throwing a string or raw object, instead of an `Error` in Firefox | |
| 1736 | + // Generating synthetic error doesn't add any value here | |
| 1737 | + // | |
| 1738 | + // We should probably somehow let a user know that they should fix their code | |
| 1739 | + if (!frame.url) { | |
| 1740 | + normalized.filename = stackInfoUrl; // fallback to whole stacks url from onerror handler | |
| 1741 | + } | |
| 1464 | 1742 | |
| 1465 | − return dsn; | |
| 1466 | − }, | |
| 1743 | + normalized.in_app = !( | |
| 1744 | + // determine if an exception came from outside of our app | |
| 1745 | + // first we check the global includePaths list. | |
| 1746 | + ( | |
| 1747 | + (!!this._globalOptions.includePaths.test && | |
| 1748 | + !this._globalOptions.includePaths.test( | |
| 1749 | + normalized.filename, | |
| 1750 | + )) || | |
| 1751 | + // Now we check for fun, if the function name is Raven or TraceKit | |
| 1752 | + /(Raven|TraceKit)\./.test(normalized["function"]) || | |
| 1753 | + // finally, we do a last ditch effort and check for raven.min.js | |
| 1754 | + /raven\.(min\.)?js$/.test(normalized.filename) | |
| 1755 | + ) | |
| 1756 | + ); | |
| 1757 | + | |
| 1758 | + return normalized; | |
| 1759 | + }, | |
| 1760 | + | |
| 1761 | + _processException: function ( | |
| 1762 | + type, | |
| 1763 | + message, | |
| 1764 | + fileurl, | |
| 1765 | + lineno, | |
| 1766 | + frames, | |
| 1767 | + options, | |
| 1768 | + ) { | |
| 1769 | + var prefixedMessage = | |
| 1770 | + (type ? type + ": " : "") + (message || ""); | |
| 1771 | + if ( | |
| 1772 | + !!this._globalOptions.ignoreErrors.test && | |
| 1773 | + (this._globalOptions.ignoreErrors.test(message) || | |
| 1774 | + this._globalOptions.ignoreErrors.test(prefixedMessage)) | |
| 1775 | + ) { | |
| 1776 | + return; | |
| 1777 | + } | |
| 1467 | 1778 | |
| 1468 | − _getGlobalServer: function(uri) { | |
| 1469 | − // assemble the endpoint from the uri pieces | |
| 1470 | − var globalServer = '//' + uri.host + (uri.port ? ':' + uri.port : ''); | |
| 1779 | + var stacktrace; | |
| 1780 | + | |
| 1781 | + if (frames && frames.length) { | |
| 1782 | + fileurl = frames[0].filename || fileurl; | |
| 1783 | + // Sentry expects frames oldest to newest | |
| 1784 | + // and JS sends them as newest to oldest | |
| 1785 | + frames.reverse(); | |
| 1786 | + stacktrace = { frames: frames }; | |
| 1787 | + } else if (fileurl) { | |
| 1788 | + stacktrace = { | |
| 1789 | + frames: [ | |
| 1790 | + { | |
| 1791 | + filename: fileurl, | |
| 1792 | + lineno: lineno, | |
| 1793 | + in_app: true, | |
| 1794 | + }, | |
| 1795 | + ], | |
| 1796 | + }; | |
| 1797 | + } | |
| 1471 | 1798 | |
| 1472 | − if (uri.protocol) { | |
| 1473 | − globalServer = uri.protocol + ':' + globalServer; | |
| 1474 | − } | |
| 1475 | − return globalServer; | |
| 1476 | − }, | |
| 1799 | + if ( | |
| 1800 | + !!this._globalOptions.ignoreUrls.test && | |
| 1801 | + this._globalOptions.ignoreUrls.test(fileurl) | |
| 1802 | + ) { | |
| 1803 | + return; | |
| 1804 | + } | |
| 1477 | 1805 | |
| 1478 | − _handleOnErrorStackInfo: function() { | |
| 1479 | − // if we are intentionally ignoring errors via onerror, bail out | |
| 1480 | − if (!this._ignoreOnError) { | |
| 1481 | − this._handleStackInfo.apply(this, arguments); | |
| 1482 | − } | |
| 1483 | − }, | |
| 1484 | − | |
| 1485 | − _handleStackInfo: function(stackInfo, options) { | |
| 1486 | − var frames = this._prepareFrames(stackInfo, options); | |
| 1487 | − | |
| 1488 | − this._triggerEvent('handle', { | |
| 1489 | − stackInfo: stackInfo, | |
| 1490 | − options: options | |
| 1491 | − }); | |
| 1492 | − | |
| 1493 | − this._processException( | |
| 1494 | − stackInfo.name, | |
| 1495 | − stackInfo.message, | |
| 1496 | − stackInfo.url, | |
| 1497 | − stackInfo.lineno, | |
| 1498 | − frames, | |
| 1499 | − options | |
| 1500 | − ); | |
| 1501 | − }, | |
| 1502 | − | |
| 1503 | − _prepareFrames: function(stackInfo, options) { | |
| 1504 | − var self = this; | |
| 1505 | − var frames = []; | |
| 1506 | − if (stackInfo.stack && stackInfo.stack.length) { | |
| 1507 | − each(stackInfo.stack, function(i, stack) { | |
| 1508 | − var frame = self._normalizeFrame(stack, stackInfo.url); | |
| 1509 | − if (frame) { | |
| 1510 | − frames.push(frame); | |
| 1511 | − } | |
| 1512 | − }); | |
| 1806 | + if ( | |
| 1807 | + !!this._globalOptions.whitelistUrls.test && | |
| 1808 | + !this._globalOptions.whitelistUrls.test(fileurl) | |
| 1809 | + ) { | |
| 1810 | + return; | |
| 1811 | + } | |
| 1513 | 1812 | |
| 1514 | − // e.g. frames captured via captureMessage throw | |
| 1515 | − if (options && options.trimHeadFrames) { | |
| 1516 | − for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) { | |
| 1517 | − frames[j].in_app = false; | |
| 1518 | − } | |
| 1519 | − } | |
| 1520 | − } | |
| 1521 | − frames = frames.slice(0, this._globalOptions.stackTraceLimit); | |
| 1522 | − return frames; | |
| 1523 | − }, | |
| 1524 | − | |
| 1525 | − _normalizeFrame: function(frame, stackInfoUrl) { | |
| 1526 | − // normalize the frames data | |
| 1527 | − var normalized = { | |
| 1528 | − filename: frame.url, | |
| 1529 | − lineno: frame.line, | |
| 1530 | − colno: frame.column, | |
| 1531 | − function: frame.func || '?' | |
| 1532 | − }; | |
| 1533 | − | |
| 1534 | − // Case when we don't have any information about the error | |
| 1535 | − // E.g. throwing a string or raw object, instead of an `Error` in Firefox | |
| 1536 | − // Generating synthetic error doesn't add any value here | |
| 1537 | − // | |
| 1538 | − // We should probably somehow let a user know that they should fix their code | |
| 1539 | − if (!frame.url) { | |
| 1540 | − normalized.filename = stackInfoUrl; // fallback to whole stacks url from onerror handler | |
| 1541 | − } | |
| 1813 | + var data = objectMerge( | |
| 1814 | + { | |
| 1815 | + // sentry.interfaces.Exception | |
| 1816 | + exception: { | |
| 1817 | + values: [ | |
| 1818 | + { | |
| 1819 | + type: type, | |
| 1820 | + value: message, | |
| 1821 | + stacktrace: stacktrace, | |
| 1822 | + }, | |
| 1823 | + ], | |
| 1824 | + }, | |
| 1825 | + culprit: fileurl, | |
| 1826 | + }, | |
| 1827 | + options, | |
| 1828 | + ); | |
| 1829 | + | |
| 1830 | + // Fire away! | |
| 1831 | + this._send(data); | |
| 1832 | + }, | |
| 1833 | + | |
| 1834 | + _trimPacket: function (data) { | |
| 1835 | + // For now, we only want to truncate the two different messages | |
| 1836 | + // but this could/should be expanded to just trim everything | |
| 1837 | + var max = this._globalOptions.maxMessageLength; | |
| 1838 | + if (data.message) { | |
| 1839 | + data.message = truncate(data.message, max); | |
| 1840 | + } | |
| 1841 | + if (data.exception) { | |
| 1842 | + var exception = data.exception.values[0]; | |
| 1843 | + exception.value = truncate(exception.value, max); | |
| 1844 | + } | |
| 1542 | 1845 | |
| 1543 | − normalized.in_app = !// determine if an exception came from outside of our app | |
| 1544 | − // first we check the global includePaths list. | |
| 1545 | − ( | |
| 1546 | − (!!this._globalOptions.includePaths.test && | |
| 1547 | − !this._globalOptions.includePaths.test(normalized.filename)) || | |
| 1548 | − // Now we check for fun, if the function name is Raven or TraceKit | |
| 1549 | − /(Raven|TraceKit)\./.test(normalized['function']) || | |
| 1550 | − // finally, we do a last ditch effort and check for raven.min.js | |
| 1551 | − /raven\.(min\.)?js$/.test(normalized.filename) | |
| 1552 | − ); | |
| 1553 | − | |
| 1554 | − return normalized; | |
| 1555 | − }, | |
| 1556 | − | |
| 1557 | − _processException: function(type, message, fileurl, lineno, frames, options) { | |
| 1558 | − var prefixedMessage = (type ? type + ': ' : '') + (message || ''); | |
| 1559 | − if ( | |
| 1560 | − !!this._globalOptions.ignoreErrors.test && | |
| 1561 | − (this._globalOptions.ignoreErrors.test(message) || | |
| 1562 | − this._globalOptions.ignoreErrors.test(prefixedMessage)) | |
| 1563 | − ) { | |
| 1564 | − return; | |
| 1565 | − } | |
| 1846 | + var request = data.request; | |
| 1847 | + if (request) { | |
| 1848 | + if (request.url) { | |
| 1849 | + request.url = truncate( | |
| 1850 | + request.url, | |
| 1851 | + this._globalOptions.maxUrlLength, | |
| 1852 | + ); | |
| 1853 | + } | |
| 1854 | + if (request.Referer) { | |
| 1855 | + request.Referer = truncate( | |
| 1856 | + request.Referer, | |
| 1857 | + this._globalOptions.maxUrlLength, | |
| 1858 | + ); | |
| 1859 | + } | |
| 1860 | + } | |
| 1566 | 1861 | |
| 1567 | − var stacktrace; | |
| 1568 | − | |
| 1569 | − if (frames && frames.length) { | |
| 1570 | − fileurl = frames[0].filename || fileurl; | |
| 1571 | − // Sentry expects frames oldest to newest | |
| 1572 | − // and JS sends them as newest to oldest | |
| 1573 | − frames.reverse(); | |
| 1574 | − stacktrace = {frames: frames}; | |
| 1575 | − } else if (fileurl) { | |
| 1576 | − stacktrace = { | |
| 1577 | − frames: [ | |
| 1578 | − { | |
| 1579 | − filename: fileurl, | |
| 1580 | − lineno: lineno, | |
| 1581 | − in_app: true | |
| 1582 | − } | |
| 1583 | − ] | |
| 1584 | − }; | |
| 1585 | − } | |
| 1862 | + if (data.breadcrumbs && data.breadcrumbs.values) | |
| 1863 | + this._trimBreadcrumbs(data.breadcrumbs); | |
| 1864 | + | |
| 1865 | + return data; | |
| 1866 | + }, | |
| 1867 | + | |
| 1868 | + /** | |
| 1869 | + * Truncate breadcrumb values (right now just URLs) | |
| 1870 | + */ | |
| 1871 | + _trimBreadcrumbs: function (breadcrumbs) { | |
| 1872 | + // known breadcrumb properties with urls | |
| 1873 | + // TODO: also consider arbitrary prop values that start with (https?)?:// | |
| 1874 | + var urlProps = ["to", "from", "url"], | |
| 1875 | + urlProp, | |
| 1876 | + crumb, | |
| 1877 | + data; | |
| 1878 | + | |
| 1879 | + for (var i = 0; i < breadcrumbs.values.length; ++i) { | |
| 1880 | + crumb = breadcrumbs.values[i]; | |
| 1881 | + if ( | |
| 1882 | + !crumb.hasOwnProperty("data") || | |
| 1883 | + !isObject(crumb.data) || | |
| 1884 | + objectFrozen(crumb.data) | |
| 1885 | + ) | |
| 1886 | + continue; | |
| 1887 | + | |
| 1888 | + data = objectMerge({}, crumb.data); | |
| 1889 | + for (var j = 0; j < urlProps.length; ++j) { | |
| 1890 | + urlProp = urlProps[j]; | |
| 1891 | + if (data.hasOwnProperty(urlProp) && data[urlProp]) { | |
| 1892 | + data[urlProp] = truncate( | |
| 1893 | + data[urlProp], | |
| 1894 | + this._globalOptions.maxUrlLength, | |
| 1895 | + ); | |
| 1896 | + } | |
| 1897 | + } | |
| 1898 | + breadcrumbs.values[i].data = data; | |
| 1899 | + } | |
| 1900 | + }, | |
| 1586 | 1901 | |
| 1587 | − if ( | |
| 1588 | − !!this._globalOptions.ignoreUrls.test && | |
| 1589 | − this._globalOptions.ignoreUrls.test(fileurl) | |
| 1590 | − ) { | |
| 1591 | − return; | |
| 1592 | − } | |
| 1902 | + _getHttpData: function () { | |
| 1903 | + if (!this._hasNavigator && !this._hasDocument) return; | |
| 1904 | + var httpData = {}; | |
| 1593 | 1905 | |
| 1594 | − if ( | |
| 1595 | − !!this._globalOptions.whitelistUrls.test && | |
| 1596 | − !this._globalOptions.whitelistUrls.test(fileurl) | |
| 1597 | − ) { | |
| 1598 | − return; | |
| 1599 | − } | |
| 1906 | + if (this._hasNavigator && _navigator.userAgent) { | |
| 1907 | + httpData.headers = { | |
| 1908 | + "User-Agent": navigator.userAgent, | |
| 1909 | + }; | |
| 1910 | + } | |
| 1600 | 1911 | |
| 1601 | − var data = objectMerge( | |
| 1602 | − { | |
| 1603 | − // sentry.interfaces.Exception | |
| 1604 | − exception: { | |
| 1605 | − values: [ | |
| 1606 | − { | |
| 1607 | − type: type, | |
| 1608 | − value: message, | |
| 1609 | − stacktrace: stacktrace | |
| 1610 | − } | |
| 1611 | − ] | |
| 1612 | − }, | |
| 1613 | − culprit: fileurl | |
| 1614 | − }, | |
| 1615 | − options | |
| 1616 | − ); | |
| 1617 | − | |
| 1618 | − // Fire away! | |
| 1619 | − this._send(data); | |
| 1620 | − }, | |
| 1621 | − | |
| 1622 | − _trimPacket: function(data) { | |
| 1623 | − // For now, we only want to truncate the two different messages | |
| 1624 | − // but this could/should be expanded to just trim everything | |
| 1625 | − var max = this._globalOptions.maxMessageLength; | |
| 1626 | − if (data.message) { | |
| 1627 | − data.message = truncate(data.message, max); | |
| 1628 | − } | |
| 1629 | − if (data.exception) { | |
| 1630 | − var exception = data.exception.values[0]; | |
| 1631 | − exception.value = truncate(exception.value, max); | |
| 1632 | − } | |
| 1633 | − | |
| 1634 | − var request = data.request; | |
| 1635 | − if (request) { | |
| 1636 | − if (request.url) { | |
| 1637 | − request.url = truncate(request.url, this._globalOptions.maxUrlLength); | |
| 1638 | − } | |
| 1639 | − if (request.Referer) { | |
| 1640 | − request.Referer = truncate(request.Referer, this._globalOptions.maxUrlLength); | |
| 1641 | − } | |
| 1642 | − } | |
| 1643 | − | |
| 1644 | − if (data.breadcrumbs && data.breadcrumbs.values) | |
| 1645 | − this._trimBreadcrumbs(data.breadcrumbs); | |
| 1646 | − | |
| 1647 | − return data; | |
| 1648 | − }, | |
| 1649 | − | |
| 1650 | − /** | |
| 1651 | − * Truncate breadcrumb values (right now just URLs) | |
| 1652 | − */ | |
| 1653 | − _trimBreadcrumbs: function(breadcrumbs) { | |
| 1654 | − // known breadcrumb properties with urls | |
| 1655 | − // TODO: also consider arbitrary prop values that start with (https?)?:// | |
| 1656 | − var urlProps = ['to', 'from', 'url'], | |
| 1657 | − urlProp, | |
| 1658 | − crumb, | |
| 1659 | − data; | |
| 1660 | − | |
| 1661 | − for (var i = 0; i < breadcrumbs.values.length; ++i) { | |
| 1662 | − crumb = breadcrumbs.values[i]; | |
| 1663 | − if ( | |
| 1664 | − !crumb.hasOwnProperty('data') || | |
| 1665 | − !isObject(crumb.data) || | |
| 1666 | − objectFrozen(crumb.data) | |
| 1667 | − ) | |
| 1668 | − continue; | |
| 1669 | − | |
| 1670 | − data = objectMerge({}, crumb.data); | |
| 1671 | − for (var j = 0; j < urlProps.length; ++j) { | |
| 1672 | − urlProp = urlProps[j]; | |
| 1673 | − if (data.hasOwnProperty(urlProp) && data[urlProp]) { | |
| 1674 | − data[urlProp] = truncate(data[urlProp], this._globalOptions.maxUrlLength); | |
| 1675 | − } | |
| 1676 | − } | |
| 1677 | − breadcrumbs.values[i].data = data; | |
| 1678 | − } | |
| 1679 | − }, | |
| 1680 | − | |
| 1681 | − _getHttpData: function() { | |
| 1682 | − if (!this._hasNavigator && !this._hasDocument) return; | |
| 1683 | − var httpData = {}; | |
| 1684 | − | |
| 1685 | − if (this._hasNavigator && _navigator.userAgent) { | |
| 1686 | − httpData.headers = { | |
| 1687 | − 'User-Agent': navigator.userAgent | |
| 1688 | − }; | |
| 1689 | − } | |
| 1690 | − | |
| 1691 | − if (this._hasDocument) { | |
| 1692 | − if (_document.location && _document.location.href) { | |
| 1693 | − httpData.url = _document.location.href; | |
| 1694 | − } | |
| 1695 | − if (_document.referrer) { | |
| 1696 | − if (!httpData.headers) httpData.headers = {}; | |
| 1697 | − httpData.headers.Referer = _document.referrer; | |
| 1698 | − } | |
| 1699 | − } | |
| 1700 | − | |
| 1701 | − return httpData; | |
| 1702 | − }, | |
| 1703 | − | |
| 1704 | − _resetBackoff: function() { | |
| 1705 | − this._backoffDuration = 0; | |
| 1706 | − this._backoffStart = null; | |
| 1707 | − }, | |
| 1708 | − | |
| 1709 | − _shouldBackoff: function() { | |
| 1710 | − return this._backoffDuration && now() - this._backoffStart < this._backoffDuration; | |
| 1711 | − }, | |
| 1712 | − | |
| 1713 | − /** | |
| 1714 | − * Returns true if the in-process data payload matches the signature | |
| 1715 | − * of the previously-sent data | |
| 1716 | − * | |
| 1717 | − * NOTE: This has to be done at this level because TraceKit can generate | |
| 1718 | − * data from window.onerror WITHOUT an exception object (IE8, IE9, | |
| 1719 | − * other old browsers). This can take the form of an "exception" | |
| 1720 | − * data object with a single frame (derived from the onerror args). | |
| 1721 | − */ | |
| 1722 | − _isRepeatData: function(current) { | |
| 1723 | − var last = this._lastData; | |
| 1724 | − | |
| 1725 | − if ( | |
| 1726 | − !last || | |
| 1727 | − current.message !== last.message || // defined for captureMessage | |
| 1728 | − current.culprit !== last.culprit // defined for captureException/onerror | |
| 1729 | − ) | |
| 1730 | − return false; | |
| 1731 | − | |
| 1732 | − // Stacktrace interface (i.e. from captureMessage) | |
| 1733 | − if (current.stacktrace || last.stacktrace) { | |
| 1734 | − return isSameStacktrace(current.stacktrace, last.stacktrace); | |
| 1735 | − } else if (current.exception || last.exception) { | |
| 1736 | − // Exception interface (i.e. from captureException/onerror) | |
| 1737 | − return isSameException(current.exception, last.exception); | |
| 1738 | − } | |
| 1739 | − | |
| 1740 | − return true; | |
| 1741 | − }, | |
| 1742 | − | |
| 1743 | − _setBackoffState: function(request) { | |
| 1744 | − // If we are already in a backoff state, don't change anything | |
| 1745 | − if (this._shouldBackoff()) { | |
| 1746 | − return; | |
| 1747 | − } | |
| 1748 | − | |
| 1749 | − var status = request.status; | |
| 1750 | − | |
| 1751 | − // 400 - project_id doesn't exist or some other fatal | |
| 1752 | − // 401 - invalid/revoked dsn | |
| 1753 | − // 429 - too many requests | |
| 1754 | − if (!(status === 400 || status === 401 || status === 429)) return; | |
| 1755 | − | |
| 1756 | − var retry; | |
| 1757 | − try { | |
| 1758 | − // If Retry-After is not in Access-Control-Expose-Headers, most | |
| 1759 | − // browsers will throw an exception trying to access it | |
| 1760 | − retry = request.getResponseHeader('Retry-After'); | |
| 1761 | − retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds | |
| 1762 | − } catch (e) { | |
| 1763 | − /* eslint no-empty:0 */ | |
| 1764 | − } | |
| 1765 | − | |
| 1766 | − this._backoffDuration = retry | |
| 1767 | − ? // If Sentry server returned a Retry-After value, use it | |
| 1768 | − retry | |
| 1769 | − : // Otherwise, double the last backoff duration (starts at 1 sec) | |
| 1770 | − this._backoffDuration * 2 || 1000; | |
| 1912 | + if (this._hasDocument) { | |
| 1913 | + if (_document.location && _document.location.href) { | |
| 1914 | + httpData.url = _document.location.href; | |
| 1915 | + } | |
| 1916 | + if (_document.referrer) { | |
| 1917 | + if (!httpData.headers) httpData.headers = {}; | |
| 1918 | + httpData.headers.Referer = _document.referrer; | |
| 1919 | + } | |
| 1920 | + } | |
| 1771 | 1921 | |
| 1772 | − this._backoffStart = now(); | |
| 1773 | − }, | |
| 1922 | + return httpData; | |
| 1923 | + }, | |
| 1924 | + | |
| 1925 | + _resetBackoff: function () { | |
| 1926 | + this._backoffDuration = 0; | |
| 1927 | + this._backoffStart = null; | |
| 1928 | + }, | |
| 1929 | + | |
| 1930 | + _shouldBackoff: function () { | |
| 1931 | + return ( | |
| 1932 | + this._backoffDuration && | |
| 1933 | + now() - this._backoffStart < this._backoffDuration | |
| 1934 | + ); | |
| 1935 | + }, | |
| 1936 | + | |
| 1937 | + /** | |
| 1938 | + * Returns true if the in-process data payload matches the signature | |
| 1939 | + * of the previously-sent data | |
| 1940 | + * | |
| 1941 | + * NOTE: This has to be done at this level because TraceKit can generate | |
| 1942 | + * data from window.onerror WITHOUT an exception object (IE8, IE9, | |
| 1943 | + * other old browsers). This can take the form of an "exception" | |
| 1944 | + * data object with a single frame (derived from the onerror args). | |
| 1945 | + */ | |
| 1946 | + _isRepeatData: function (current) { | |
| 1947 | + var last = this._lastData; | |
| 1948 | + | |
| 1949 | + if ( | |
| 1950 | + !last || | |
| 1951 | + current.message !== last.message || // defined for captureMessage | |
| 1952 | + current.culprit !== last.culprit // defined for captureException/onerror | |
| 1953 | + ) | |
| 1954 | + return false; | |
| 1955 | + | |
| 1956 | + // Stacktrace interface (i.e. from captureMessage) | |
| 1957 | + if (current.stacktrace || last.stacktrace) { | |
| 1958 | + return isSameStacktrace(current.stacktrace, last.stacktrace); | |
| 1959 | + } else if (current.exception || last.exception) { | |
| 1960 | + // Exception interface (i.e. from captureException/onerror) | |
| 1961 | + return isSameException(current.exception, last.exception); | |
| 1962 | + } | |
| 1774 | 1963 | |
| 1775 | − _send: function(data) { | |
| 1776 | − var globalOptions = this._globalOptions; | |
| 1964 | + return true; | |
| 1965 | + }, | |
| 1777 | 1966 | |
| 1778 | − var baseData = { | |
| 1779 | − project: this._globalProject, | |
| 1780 | − logger: globalOptions.logger, | |
| 1781 | − platform: 'javascript' | |
| 1782 | − }, | |
| 1783 | − httpData = this._getHttpData(); | |
| 1967 | + _setBackoffState: function (request) { | |
| 1968 | + // If we are already in a backoff state, don't change anything | |
| 1969 | + if (this._shouldBackoff()) { | |
| 1970 | + return; | |
| 1971 | + } | |
| 1784 | 1972 | |
| 1785 | − if (httpData) { | |
| 1786 | − baseData.request = httpData; | |
| 1787 | − } | |
| 1973 | + var status = request.status; | |
| 1788 | 1974 | |
| 1789 | − // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload | |
| 1790 | − if (data.trimHeadFrames) delete data.trimHeadFrames; | |
| 1975 | + // 400 - project_id doesn't exist or some other fatal | |
| 1976 | + // 401 - invalid/revoked dsn | |
| 1977 | + // 429 - too many requests | |
| 1978 | + if (!(status === 400 || status === 401 || status === 429)) | |
| 1979 | + return; | |
| 1791 | 1980 | |
| 1792 | − data = objectMerge(baseData, data); | |
| 1981 | + var retry; | |
| 1982 | + try { | |
| 1983 | + // If Retry-After is not in Access-Control-Expose-Headers, most | |
| 1984 | + // browsers will throw an exception trying to access it | |
| 1985 | + retry = request.getResponseHeader("Retry-After"); | |
| 1986 | + retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds | |
| 1987 | + } catch (e) { | |
| 1988 | + /* eslint no-empty:0 */ | |
| 1989 | + } | |
| 1793 | 1990 | |
| 1794 | − // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge | |
| 1795 | − data.tags = objectMerge(objectMerge({}, this._globalContext.tags), data.tags); | |
| 1796 | − data.extra = objectMerge(objectMerge({}, this._globalContext.extra), data.extra); | |
| 1991 | + this._backoffDuration = retry | |
| 1992 | + ? // If Sentry server returned a Retry-After value, use it | |
| 1993 | + retry | |
| 1994 | + : // Otherwise, double the last backoff duration (starts at 1 sec) | |
| 1995 | + this._backoffDuration * 2 || 1000; | |
| 1797 | 1996 | |
| 1798 | − // Send along our own collected metadata with extra | |
| 1799 | − data.extra['session:duration'] = now() - this._startTime; | |
| 1997 | + this._backoffStart = now(); | |
| 1998 | + }, | |
| 1800 | 1999 | |
| 1801 | − if (this._breadcrumbs && this._breadcrumbs.length > 0) { | |
| 1802 | − // intentionally make shallow copy so that additions | |
| 1803 | − // to breadcrumbs aren't accidentally sent in this request | |
| 1804 | − data.breadcrumbs = { | |
| 1805 | − values: [].slice.call(this._breadcrumbs, 0) | |
| 1806 | − }; | |
| 1807 | − } | |
| 2000 | + _send: function (data) { | |
| 2001 | + var globalOptions = this._globalOptions; | |
| 1808 | 2002 | |
| 1809 | − // If there are no tags/extra, strip the key from the payload alltogther. | |
| 1810 | − if (isEmptyObject(data.tags)) delete data.tags; | |
| 2003 | + var baseData = { | |
| 2004 | + project: this._globalProject, | |
| 2005 | + logger: globalOptions.logger, | |
| 2006 | + platform: "javascript", | |
| 2007 | + }, | |
| 2008 | + httpData = this._getHttpData(); | |
| 1811 | 2009 | |
| 1812 | − if (this._globalContext.user) { | |
| 1813 | − // sentry.interfaces.User | |
| 1814 | − data.user = this._globalContext.user; | |
| 1815 | − } | |
| 2010 | + if (httpData) { | |
| 2011 | + baseData.request = httpData; | |
| 2012 | + } | |
| 1816 | 2013 | |
| 1817 | − // Include the environment if it's defined in globalOptions | |
| 1818 | − if (globalOptions.environment) data.environment = globalOptions.environment; | |
| 2014 | + // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload | |
| 2015 | + if (data.trimHeadFrames) delete data.trimHeadFrames; | |
| 2016 | + | |
| 2017 | + data = objectMerge(baseData, data); | |
| 2018 | + | |
| 2019 | + // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge | |
| 2020 | + data.tags = objectMerge( | |
| 2021 | + objectMerge({}, this._globalContext.tags), | |
| 2022 | + data.tags, | |
| 2023 | + ); | |
| 2024 | + data.extra = objectMerge( | |
| 2025 | + objectMerge({}, this._globalContext.extra), | |
| 2026 | + data.extra, | |
| 2027 | + ); | |
| 2028 | + | |
| 2029 | + // Send along our own collected metadata with extra | |
| 2030 | + data.extra["session:duration"] = now() - this._startTime; | |
| 2031 | + | |
| 2032 | + if (this._breadcrumbs && this._breadcrumbs.length > 0) { | |
| 2033 | + // intentionally make shallow copy so that additions | |
| 2034 | + // to breadcrumbs aren't accidentally sent in this request | |
| 2035 | + data.breadcrumbs = { | |
| 2036 | + values: [].slice.call(this._breadcrumbs, 0), | |
| 2037 | + }; | |
| 2038 | + } | |
| 1819 | 2039 | |
| 1820 | − // Include the release if it's defined in globalOptions | |
| 1821 | − if (globalOptions.release) data.release = globalOptions.release; | |
| 2040 | + // If there are no tags/extra, strip the key from the payload alltogther. | |
| 2041 | + if (isEmptyObject(data.tags)) delete data.tags; | |
| 1822 | 2042 | |
| 1823 | − // Include server_name if it's defined in globalOptions | |
| 1824 | − if (globalOptions.serverName) data.server_name = globalOptions.serverName; | |
| 2043 | + if (this._globalContext.user) { | |
| 2044 | + // sentry.interfaces.User | |
| 2045 | + data.user = this._globalContext.user; | |
| 2046 | + } | |
| 1825 | 2047 | |
| 1826 | − if (isFunction(globalOptions.dataCallback)) { | |
| 1827 | − data = globalOptions.dataCallback(data) || data; | |
| 1828 | − } | |
| 2048 | + // Include the environment if it's defined in globalOptions | |
| 2049 | + if (globalOptions.environment) | |
| 2050 | + data.environment = globalOptions.environment; | |
| 1829 | 2051 | |
| 1830 | − // Why?????????? | |
| 1831 | − if (!data || isEmptyObject(data)) { | |
| 1832 | − return; | |
| 1833 | − } | |
| 2052 | + // Include the release if it's defined in globalOptions | |
| 2053 | + if (globalOptions.release) data.release = globalOptions.release; | |
| 1834 | 2054 | |
| 1835 | − // Check if the request should be filtered or not | |
| 1836 | − if ( | |
| 1837 | − isFunction(globalOptions.shouldSendCallback) && | |
| 1838 | − !globalOptions.shouldSendCallback(data) | |
| 1839 | − ) { | |
| 1840 | − return; | |
| 1841 | − } | |
| 2055 | + // Include server_name if it's defined in globalOptions | |
| 2056 | + if (globalOptions.serverName) | |
| 2057 | + data.server_name = globalOptions.serverName; | |
| 1842 | 2058 | |
| 1843 | − // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests), | |
| 1844 | − // so drop requests until "cool-off" period has elapsed. | |
| 1845 | − if (this._shouldBackoff()) { | |
| 1846 | − this._logDebug('warn', 'Raven dropped error due to backoff: ', data); | |
| 1847 | − return; | |
| 1848 | − } | |
| 2059 | + if (isFunction(globalOptions.dataCallback)) { | |
| 2060 | + data = globalOptions.dataCallback(data) || data; | |
| 2061 | + } | |
| 1849 | 2062 | |
| 1850 | − if (typeof globalOptions.sampleRate === 'number') { | |
| 1851 | − if (Math.random() < globalOptions.sampleRate) { | |
| 1852 | − this._sendProcessedPayload(data); | |
| 1853 | − } | |
| 1854 | − } else { | |
| 1855 | − this._sendProcessedPayload(data); | |
| 1856 | − } | |
| 1857 | − }, | |
| 2063 | + // Why?????????? | |
| 2064 | + if (!data || isEmptyObject(data)) { | |
| 2065 | + return; | |
| 2066 | + } | |
| 1858 | 2067 | |
| 1859 | − _getUuid: function() { | |
| 1860 | − return uuid4(); | |
| 1861 | − }, | |
| 2068 | + // Check if the request should be filtered or not | |
| 2069 | + if ( | |
| 2070 | + isFunction(globalOptions.shouldSendCallback) && | |
| 2071 | + !globalOptions.shouldSendCallback(data) | |
| 2072 | + ) { | |
| 2073 | + return; | |
| 2074 | + } | |
| 1862 | 2075 | |
| 1863 | − _sendProcessedPayload: function(data, callback) { | |
| 1864 | − var self = this; | |
| 1865 | − var globalOptions = this._globalOptions; | |
| 2076 | + // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests), | |
| 2077 | + // so drop requests until "cool-off" period has elapsed. | |
| 2078 | + if (this._shouldBackoff()) { | |
| 2079 | + this._logDebug( | |
| 2080 | + "warn", | |
| 2081 | + "Raven dropped error due to backoff: ", | |
| 2082 | + data, | |
| 2083 | + ); | |
| 2084 | + return; | |
| 2085 | + } | |
| 1866 | 2086 | |
| 1867 | − if (!this.isSetup()) return; | |
| 2087 | + if (typeof globalOptions.sampleRate === "number") { | |
| 2088 | + if (Math.random() < globalOptions.sampleRate) { | |
| 2089 | + this._sendProcessedPayload(data); | |
| 2090 | + } | |
| 2091 | + } else { | |
| 2092 | + this._sendProcessedPayload(data); | |
| 2093 | + } | |
| 2094 | + }, | |
| 2095 | + | |
| 2096 | + _getUuid: function () { | |
| 2097 | + return uuid4(); | |
| 2098 | + }, | |
| 2099 | + | |
| 2100 | + _sendProcessedPayload: function (data, callback) { | |
| 2101 | + var self = this; | |
| 2102 | + var globalOptions = this._globalOptions; | |
| 2103 | + | |
| 2104 | + if (!this.isSetup()) return; | |
| 2105 | + | |
| 2106 | + // Try and clean up the packet before sending by truncating long values | |
| 2107 | + data = this._trimPacket(data); | |
| 2108 | + | |
| 2109 | + // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback, | |
| 2110 | + // but this would require copying an un-truncated copy of the data packet, which can be | |
| 2111 | + // arbitrarily deep (extra_data) -- could be worthwhile? will revisit | |
| 2112 | + if ( | |
| 2113 | + !this._globalOptions.allowDuplicates && | |
| 2114 | + this._isRepeatData(data) | |
| 2115 | + ) { | |
| 2116 | + this._logDebug("warn", "Raven dropped repeat event: ", data); | |
| 2117 | + return; | |
| 2118 | + } | |
| 1868 | 2119 | |
| 1869 | − // Try and clean up the packet before sending by truncating long values | |
| 1870 | − data = this._trimPacket(data); | |
| 2120 | + // Send along an event_id if not explicitly passed. | |
| 2121 | + // This event_id can be used to reference the error within Sentry itself. | |
| 2122 | + // Set lastEventId after we know the error should actually be sent | |
| 2123 | + this._lastEventId = | |
| 2124 | + data.event_id || (data.event_id = this._getUuid()); | |
| 1871 | 2125 | |
| 1872 | − // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback, | |
| 1873 | − // but this would require copying an un-truncated copy of the data packet, which can be | |
| 1874 | − // arbitrarily deep (extra_data) -- could be worthwhile? will revisit | |
| 1875 | − if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) { | |
| 1876 | − this._logDebug('warn', 'Raven dropped repeat event: ', data); | |
| 1877 | − return; | |
| 1878 | − } | |
| 2126 | + // Store outbound payload after trim | |
| 2127 | + this._lastData = data; | |
| 1879 | 2128 | |
| 1880 | − // Send along an event_id if not explicitly passed. | |
| 1881 | − // This event_id can be used to reference the error within Sentry itself. | |
| 1882 | − // Set lastEventId after we know the error should actually be sent | |
| 1883 | − this._lastEventId = data.event_id || (data.event_id = this._getUuid()); | |
| 2129 | + this._logDebug("debug", "Raven about to send:", data); | |
| 1884 | 2130 | |
| 1885 | − // Store outbound payload after trim | |
| 1886 | − this._lastData = data; | |
| 2131 | + var auth = { | |
| 2132 | + sentry_version: "7", | |
| 2133 | + sentry_client: "raven-js/" + this.VERSION, | |
| 2134 | + sentry_key: this._globalKey, | |
| 2135 | + }; | |
| 1887 | 2136 | |
| 1888 | − this._logDebug('debug', 'Raven about to send:', data); | |
| 2137 | + if (this._globalSecret) { | |
| 2138 | + auth.sentry_secret = this._globalSecret; | |
| 2139 | + } | |
| 1889 | 2140 | |
| 1890 | − var auth = { | |
| 1891 | − sentry_version: '7', | |
| 1892 | − sentry_client: 'raven-js/' + this.VERSION, | |
| 1893 | − sentry_key: this._globalKey | |
| 1894 | − }; | |
| 2141 | + var exception = data.exception && data.exception.values[0]; | |
| 2142 | + | |
| 2143 | + // only capture 'sentry' breadcrumb is autoBreadcrumbs is truthy | |
| 2144 | + if ( | |
| 2145 | + this._globalOptions.autoBreadcrumbs && | |
| 2146 | + this._globalOptions.autoBreadcrumbs.sentry | |
| 2147 | + ) { | |
| 2148 | + this.captureBreadcrumb({ | |
| 2149 | + category: "sentry", | |
| 2150 | + message: exception | |
| 2151 | + ? (exception.type ? exception.type + ": " : "") + | |
| 2152 | + exception.value | |
| 2153 | + : data.message, | |
| 2154 | + event_id: data.event_id, | |
| 2155 | + level: data.level || "error", // presume error unless specified | |
| 2156 | + }); | |
| 2157 | + } | |
| 1895 | 2158 | |
| 1896 | − if (this._globalSecret) { | |
| 1897 | − auth.sentry_secret = this._globalSecret; | |
| 1898 | − } | |
| 2159 | + var url = this._globalEndpoint; | |
| 2160 | + (globalOptions.transport || this._makeRequest).call(this, { | |
| 2161 | + url: url, | |
| 2162 | + auth: auth, | |
| 2163 | + data: data, | |
| 2164 | + options: globalOptions, | |
| 2165 | + onSuccess: function success() { | |
| 2166 | + self._resetBackoff(); | |
| 2167 | + | |
| 2168 | + self._triggerEvent("success", { | |
| 2169 | + data: data, | |
| 2170 | + src: url, | |
| 2171 | + }); | |
| 2172 | + callback && callback(); | |
| 2173 | + }, | |
| 2174 | + onError: function failure(error) { | |
| 2175 | + self._logDebug( | |
| 2176 | + "error", | |
| 2177 | + "Raven transport failed to send: ", | |
| 2178 | + error, | |
| 2179 | + ); | |
| 2180 | + | |
| 2181 | + if (error.request) { | |
| 2182 | + self._setBackoffState(error.request); | |
| 2183 | + } | |
| 2184 | + | |
| 2185 | + self._triggerEvent("failure", { | |
| 2186 | + data: data, | |
| 2187 | + src: url, | |
| 2188 | + }); | |
| 2189 | + error = | |
| 2190 | + error || | |
| 2191 | + new Error( | |
| 2192 | + "Raven send failed (no additional details provided)", | |
| 2193 | + ); | |
| 2194 | + callback && callback(error); | |
| 2195 | + }, | |
| 2196 | + }); | |
| 2197 | + }, | |
| 2198 | + | |
| 2199 | + _makeRequest: function (opts) { | |
| 2200 | + var request = | |
| 2201 | + _window.XMLHttpRequest && new _window.XMLHttpRequest(); | |
| 2202 | + if (!request) return; | |
| 2203 | + | |
| 2204 | + // if browser doesn't support CORS (e.g. IE7), we are out of luck | |
| 2205 | + var hasCORS = | |
| 2206 | + "withCredentials" in request || | |
| 2207 | + typeof XDomainRequest !== "undefined"; | |
| 2208 | + | |
| 2209 | + if (!hasCORS) return; | |
| 2210 | + | |
| 2211 | + var url = opts.url; | |
| 2212 | + | |
| 2213 | + if ("withCredentials" in request) { | |
| 2214 | + request.onreadystatechange = function () { | |
| 2215 | + if (request.readyState !== 4) { | |
| 2216 | + return; | |
| 2217 | + } else if (request.status === 200) { | |
| 2218 | + opts.onSuccess && opts.onSuccess(); | |
| 2219 | + } else if (opts.onError) { | |
| 2220 | + var err = new Error( | |
| 2221 | + "Sentry error code: " + request.status, | |
| 2222 | + ); | |
| 2223 | + err.request = request; | |
| 2224 | + opts.onError(err); | |
| 2225 | + } | |
| 2226 | + }; | |
| 2227 | + } else { | |
| 2228 | + request = new XDomainRequest(); | |
| 2229 | + // xdomainrequest cannot go http -> https (or vice versa), | |
| 2230 | + // so always use protocol relative | |
| 2231 | + url = url.replace(/^https?:/, ""); | |
| 2232 | + | |
| 2233 | + // onreadystatechange not supported by XDomainRequest | |
| 2234 | + if (opts.onSuccess) { | |
| 2235 | + request.onload = opts.onSuccess; | |
| 2236 | + } | |
| 2237 | + if (opts.onError) { | |
| 2238 | + request.onerror = function () { | |
| 2239 | + var err = new Error("Sentry error code: XDomainRequest"); | |
| 2240 | + err.request = request; | |
| 2241 | + opts.onError(err); | |
| 2242 | + }; | |
| 2243 | + } | |
| 2244 | + } | |
| 1899 | 2245 | |
| 1900 | − var exception = data.exception && data.exception.values[0]; | |
| 1901 | − | |
| 1902 | − // only capture 'sentry' breadcrumb is autoBreadcrumbs is truthy | |
| 1903 | − if ( | |
| 1904 | − this._globalOptions.autoBreadcrumbs && | |
| 1905 | − this._globalOptions.autoBreadcrumbs.sentry | |
| 1906 | − ) { | |
| 1907 | − this.captureBreadcrumb({ | |
| 1908 | − category: 'sentry', | |
| 1909 | − message: exception | |
| 1910 | − ? (exception.type ? exception.type + ': ' : '') + exception.value | |
| 1911 | − : data.message, | |
| 1912 | − event_id: data.event_id, | |
| 1913 | − level: data.level || 'error' // presume error unless specified | |
| 1914 | − }); | |
| 1915 | − } | |
| 2246 | + // NOTE: auth is intentionally sent as part of query string (NOT as custom | |
| 2247 | + // HTTP header) so as to avoid preflight CORS requests | |
| 2248 | + request.open("POST", url + "?" + urlencode(opts.auth)); | |
| 2249 | + request.send(stringify(opts.data)); | |
| 2250 | + }, | |
| 2251 | + | |
| 2252 | + _logDebug: function (level) { | |
| 2253 | + if (this._originalConsoleMethods[level] && this.debug) { | |
| 2254 | + // In IE<10 console methods do not have their own 'apply' method | |
| 2255 | + Function.prototype.apply.call( | |
| 2256 | + this._originalConsoleMethods[level], | |
| 2257 | + this._originalConsole, | |
| 2258 | + [].slice.call(arguments, 1), | |
| 2259 | + ); | |
| 2260 | + } | |
| 2261 | + }, | |
| 2262 | + | |
| 2263 | + _mergeContext: function (key, context) { | |
| 2264 | + if (isUndefined(context)) { | |
| 2265 | + delete this._globalContext[key]; | |
| 2266 | + } else { | |
| 2267 | + this._globalContext[key] = objectMerge( | |
| 2268 | + this._globalContext[key] || {}, | |
| 2269 | + context, | |
| 2270 | + ); | |
| 2271 | + } | |
| 2272 | + }, | |
| 2273 | + }; | |
| 1916 | 2274 | |
| 1917 | − var url = this._globalEndpoint; | |
| 1918 | − (globalOptions.transport || this._makeRequest).call(this, { | |
| 1919 | − url: url, | |
| 1920 | − auth: auth, | |
| 1921 | − data: data, | |
| 1922 | − options: globalOptions, | |
| 1923 | − onSuccess: function success() { | |
| 1924 | − self._resetBackoff(); | |
| 1925 | − | |
| 1926 | − self._triggerEvent('success', { | |
| 1927 | − data: data, | |
| 1928 | − src: url | |
| 1929 | − }); | |
| 1930 | − callback && callback(); | |
| 1931 | − }, | |
| 1932 | − onError: function failure(error) { | |
| 1933 | − self._logDebug('error', 'Raven transport failed to send: ', error); | |
| 1934 | − | |
| 1935 | − if (error.request) { | |
| 1936 | − self._setBackoffState(error.request); | |
| 1937 | − } | |
| 2275 | + // Deprecations | |
| 2276 | + Raven.prototype.setUser = Raven.prototype.setUserContext; | |
| 2277 | + Raven.prototype.setReleaseContext = Raven.prototype.setRelease; | |
| 2278 | + | |
| 2279 | + module.exports = Raven; | |
| 2280 | + }).call( | |
| 2281 | + this, | |
| 2282 | + typeof global !== "undefined" | |
| 2283 | + ? global | |
| 2284 | + : typeof self !== "undefined" | |
| 2285 | + ? self | |
| 2286 | + : typeof window !== "undefined" | |
| 2287 | + ? window | |
| 2288 | + : {}, | |
| 2289 | + ); | |
| 2290 | + }, | |
| 2291 | + { 1: 1, 2: 2, 5: 5, 6: 6, 7: 7 }, | |
| 2292 | + ], | |
| 2293 | + 4: [ | |
| 2294 | + function (_dereq_, module, exports) { | |
| 2295 | + (function (global) { | |
| 2296 | + /** | |
| 2297 | + * Enforces a single instance of the Raven client, and the | |
| 2298 | + * main entry point for Raven. If you are a consumer of the | |
| 2299 | + * Raven library, you SHOULD load this file (vs raven.js). | |
| 2300 | + **/ | |
| 2301 | + | |
| 2302 | + var RavenConstructor = _dereq_(3); | |
| 2303 | + | |
| 2304 | + // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785) | |
| 2305 | + var _window = | |
| 2306 | + typeof window !== "undefined" | |
| 2307 | + ? window | |
| 2308 | + : typeof global !== "undefined" | |
| 2309 | + ? global | |
| 2310 | + : typeof self !== "undefined" | |
| 2311 | + ? self | |
| 2312 | + : {}; | |
| 2313 | + var _Raven = _window.Raven; | |
| 2314 | + | |
| 2315 | + var Raven = new RavenConstructor(); | |
| 2316 | + | |
| 2317 | + /* | |
| 2318 | + * Allow multiple versions of Raven to be installed. | |
| 2319 | + * Strip Raven from the global context and returns the instance. | |
| 2320 | + * | |
| 2321 | + * @return {Raven} | |
| 2322 | + */ | |
| 2323 | + Raven.noConflict = function () { | |
| 2324 | + _window.Raven = _Raven; | |
| 2325 | + return Raven; | |
| 2326 | + }; | |
| 1938 | 2327 | |
| 1939 | − self._triggerEvent('failure', { | |
| 1940 | − data: data, | |
| 1941 | − src: url | |
| 1942 | − }); | |
| 1943 | − error = error || new Error('Raven send failed (no additional details provided)'); | |
| 1944 | − callback && callback(error); | |
| 1945 | − } | |
| 1946 | − }); | |
| 1947 | − }, | |
| 1948 | − | |
| 1949 | − _makeRequest: function(opts) { | |
| 1950 | − var request = _window.XMLHttpRequest && new _window.XMLHttpRequest(); | |
| 1951 | − if (!request) return; | |
| 1952 | − | |
| 1953 | − // if browser doesn't support CORS (e.g. IE7), we are out of luck | |
| 1954 | − var hasCORS = 'withCredentials' in request || typeof XDomainRequest !== 'undefined'; | |
| 1955 | − | |
| 1956 | − if (!hasCORS) return; | |
| 1957 | − | |
| 1958 | − var url = opts.url; | |
| 1959 | − | |
| 1960 | − if ('withCredentials' in request) { | |
| 1961 | − request.onreadystatechange = function() { | |
| 1962 | − if (request.readyState !== 4) { | |
| 1963 | − return; | |
| 1964 | − } else if (request.status === 200) { | |
| 1965 | − opts.onSuccess && opts.onSuccess(); | |
| 1966 | − } else if (opts.onError) { | |
| 1967 | − var err = new Error('Sentry error code: ' + request.status); | |
| 1968 | − err.request = request; | |
| 1969 | − opts.onError(err); | |
| 1970 | − } | |
| 1971 | − }; | |
| 1972 | − } else { | |
| 1973 | − request = new XDomainRequest(); | |
| 1974 | − // xdomainrequest cannot go http -> https (or vice versa), | |
| 1975 | − // so always use protocol relative | |
| 1976 | − url = url.replace(/^https?:/, ''); | |
| 1977 | − | |
| 1978 | − // onreadystatechange not supported by XDomainRequest | |
| 1979 | − if (opts.onSuccess) { | |
| 1980 | − request.onload = opts.onSuccess; | |
| 1981 | − } | |
| 1982 | − if (opts.onError) { | |
| 1983 | − request.onerror = function() { | |
| 1984 | − var err = new Error('Sentry error code: XDomainRequest'); | |
| 1985 | − err.request = request; | |
| 1986 | − opts.onError(err); | |
| 1987 | − }; | |
| 1988 | − } | |
| 1989 | − } | |
| 2328 | + Raven.afterLoad(); | |
| 2329 | + | |
| 2330 | + module.exports = Raven; | |
| 2331 | + }).call( | |
| 2332 | + this, | |
| 2333 | + typeof global !== "undefined" | |
| 2334 | + ? global | |
| 2335 | + : typeof self !== "undefined" | |
| 2336 | + ? self | |
| 2337 | + : typeof window !== "undefined" | |
| 2338 | + ? window | |
| 2339 | + : {}, | |
| 2340 | + ); | |
| 2341 | + }, | |
| 2342 | + { 3: 3 }, | |
| 2343 | + ], | |
| 2344 | + 5: [ | |
| 2345 | + function (_dereq_, module, exports) { | |
| 2346 | + (function (global) { | |
| 2347 | + var _window = | |
| 2348 | + typeof window !== "undefined" | |
| 2349 | + ? window | |
| 2350 | + : typeof global !== "undefined" | |
| 2351 | + ? global | |
| 2352 | + : typeof self !== "undefined" | |
| 2353 | + ? self | |
| 2354 | + : {}; | |
| 2355 | + | |
| 2356 | + function isObject(what) { | |
| 2357 | + return typeof what === "object" && what !== null; | |
| 2358 | + } | |
| 1990 | 2359 | |
| 1991 | − // NOTE: auth is intentionally sent as part of query string (NOT as custom | |
| 1992 | − // HTTP header) so as to avoid preflight CORS requests | |
| 1993 | − request.open('POST', url + '?' + urlencode(opts.auth)); | |
| 1994 | − request.send(stringify(opts.data)); | |
| 1995 | − }, | |
| 1996 | − | |
| 1997 | − _logDebug: function(level) { | |
| 1998 | − if (this._originalConsoleMethods[level] && this.debug) { | |
| 1999 | − // In IE<10 console methods do not have their own 'apply' method | |
| 2000 | − Function.prototype.apply.call( | |
| 2001 | − this._originalConsoleMethods[level], | |
| 2002 | − this._originalConsole, | |
| 2003 | − [].slice.call(arguments, 1) | |
| 2004 | − ); | |
| 2005 | − } | |
| 2006 | − }, | |
| 2360 | + // Yanked from https://git.io/vS8DV re-used under CC0 | |
| 2361 | + // with some tiny modifications | |
| 2362 | + function isError(value) { | |
| 2363 | + switch ({}.toString.call(value)) { | |
| 2364 | + case "[object Error]": | |
| 2365 | + return true; | |
| 2366 | + case "[object Exception]": | |
| 2367 | + return true; | |
| 2368 | + case "[object DOMException]": | |
| 2369 | + return true; | |
| 2370 | + default: | |
| 2371 | + return value instanceof Error; | |
| 2372 | + } | |
| 2373 | + } | |
| 2007 | 2374 | |
| 2008 | − _mergeContext: function(key, context) { | |
| 2009 | − if (isUndefined(context)) { | |
| 2010 | − delete this._globalContext[key]; | |
| 2011 | − } else { | |
| 2012 | − this._globalContext[key] = objectMerge(this._globalContext[key] || {}, context); | |
| 2013 | − } | |
| 2014 | − } | |
| 2015 | −}; | |
| 2375 | + function isErrorEvent(value) { | |
| 2376 | + return ( | |
| 2377 | + supportsErrorEvent() && | |
| 2378 | + {}.toString.call(value) === "[object ErrorEvent]" | |
| 2379 | + ); | |
| 2380 | + } | |
| 2016 | 2381 | |
| 2017 | −// Deprecations | |
| 2018 | −Raven.prototype.setUser = Raven.prototype.setUserContext; | |
| 2019 | −Raven.prototype.setReleaseContext = Raven.prototype.setRelease; | |
| 2382 | + function isUndefined(what) { | |
| 2383 | + return what === void 0; | |
| 2384 | + } | |
| 2020 | 2385 | |
| 2021 | −module.exports = Raven; | |
| 2386 | + function isFunction(what) { | |
| 2387 | + return typeof what === "function"; | |
| 2388 | + } | |
| 2022 | 2389 | |
| 2023 | −}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| 2024 | −},{"1":1,"2":2,"5":5,"6":6,"7":7}],4:[function(_dereq_,module,exports){ | |
| 2025 | −(function (global){ | |
| 2026 | −/** | |
| 2027 | − * Enforces a single instance of the Raven client, and the | |
| 2028 | − * main entry point for Raven. If you are a consumer of the | |
| 2029 | − * Raven library, you SHOULD load this file (vs raven.js). | |
| 2030 | − **/ | |
| 2390 | + function isString(what) { | |
| 2391 | + return Object.prototype.toString.call(what) === "[object String]"; | |
| 2392 | + } | |
| 2031 | 2393 | |
| 2032 | −var RavenConstructor = _dereq_(3); | |
| 2394 | + function isArray(what) { | |
| 2395 | + return Object.prototype.toString.call(what) === "[object Array]"; | |
| 2396 | + } | |
| 2033 | 2397 | |
| 2034 | −// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785) | |
| 2035 | −var _window = | |
| 2036 | − typeof window !== 'undefined' | |
| 2037 | − ? window | |
| 2038 | − : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
| 2039 | −var _Raven = _window.Raven; | |
| 2398 | + function isEmptyObject(what) { | |
| 2399 | + for (var _ in what) { | |
| 2400 | + if (what.hasOwnProperty(_)) { | |
| 2401 | + return false; | |
| 2402 | + } | |
| 2403 | + } | |
| 2404 | + return true; | |
| 2405 | + } | |
| 2040 | 2406 | |
| 2041 | −var Raven = new RavenConstructor(); | |
| 2407 | + function supportsErrorEvent() { | |
| 2408 | + try { | |
| 2409 | + new ErrorEvent(""); // eslint-disable-line no-new | |
| 2410 | + return true; | |
| 2411 | + } catch (e) { | |
| 2412 | + return false; | |
| 2413 | + } | |
| 2414 | + } | |
| 2042 | 2415 | |
| 2043 | −/* | |
| 2044 | − * Allow multiple versions of Raven to be installed. | |
| 2045 | − * Strip Raven from the global context and returns the instance. | |
| 2046 | − * | |
| 2047 | − * @return {Raven} | |
| 2048 | − */ | |
| 2049 | −Raven.noConflict = function() { | |
| 2050 | − _window.Raven = _Raven; | |
| 2051 | − return Raven; | |
| 2052 | −}; | |
| 2053 | − | |
| 2054 | −Raven.afterLoad(); | |
| 2055 | − | |
| 2056 | −module.exports = Raven; | |
| 2057 | − | |
| 2058 | −}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| 2059 | −},{"3":3}],5:[function(_dereq_,module,exports){ | |
| 2060 | −(function (global){ | |
| 2061 | −var _window = | |
| 2062 | − typeof window !== 'undefined' | |
| 2063 | − ? window | |
| 2064 | − : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
| 2065 | − | |
| 2066 | −function isObject(what) { | |
| 2067 | − return typeof what === 'object' && what !== null; | |
| 2068 | −} | |
| 2069 | − | |
| 2070 | −// Yanked from https://git.io/vS8DV re-used under CC0 | |
| 2071 | −// with some tiny modifications | |
| 2072 | −function isError(value) { | |
| 2073 | − switch ({}.toString.call(value)) { | |
| 2074 | − case '[object Error]': | |
| 2075 | − return true; | |
| 2076 | − case '[object Exception]': | |
| 2077 | − return true; | |
| 2078 | − case '[object DOMException]': | |
| 2079 | − return true; | |
| 2080 | − default: | |
| 2081 | − return value instanceof Error; | |
| 2082 | − } | |
| 2083 | −} | |
| 2416 | + function wrappedCallback(callback) { | |
| 2417 | + function dataCallback(data, original) { | |
| 2418 | + var normalizedData = callback(data) || data; | |
| 2419 | + if (original) { | |
| 2420 | + return original(normalizedData) || normalizedData; | |
| 2421 | + } | |
| 2422 | + return normalizedData; | |
| 2423 | + } | |
| 2084 | 2424 | |
| 2085 | −function isErrorEvent(value) { | |
| 2086 | − return supportsErrorEvent() && {}.toString.call(value) === '[object ErrorEvent]'; | |
| 2087 | −} | |
| 2425 | + return dataCallback; | |
| 2426 | + } | |
| 2088 | 2427 | |
| 2089 | −function isUndefined(what) { | |
| 2090 | − return what === void 0; | |
| 2091 | −} | |
| 2428 | + function each(obj, callback) { | |
| 2429 | + var i, j; | |
| 2092 | 2430 | |
| 2093 | −function isFunction(what) { | |
| 2094 | − return typeof what === 'function'; | |
| 2095 | −} | |
| 2431 | + if (isUndefined(obj.length)) { | |
| 2432 | + for (i in obj) { | |
| 2433 | + if (hasKey(obj, i)) { | |
| 2434 | + callback.call(null, i, obj[i]); | |
| 2435 | + } | |
| 2436 | + } | |
| 2437 | + } else { | |
| 2438 | + j = obj.length; | |
| 2439 | + if (j) { | |
| 2440 | + for (i = 0; i < j; i++) { | |
| 2441 | + callback.call(null, i, obj[i]); | |
| 2442 | + } | |
| 2443 | + } | |
| 2444 | + } | |
| 2445 | + } | |
| 2096 | 2446 | |
| 2097 | −function isString(what) { | |
| 2098 | − return Object.prototype.toString.call(what) === '[object String]'; | |
| 2099 | −} | |
| 2447 | + function objectMerge(obj1, obj2) { | |
| 2448 | + if (!obj2) { | |
| 2449 | + return obj1; | |
| 2450 | + } | |
| 2451 | + each(obj2, function (key, value) { | |
| 2452 | + obj1[key] = value; | |
| 2453 | + }); | |
| 2454 | + return obj1; | |
| 2455 | + } | |
| 2100 | 2456 | |
| 2101 | −function isArray(what) { | |
| 2102 | − return Object.prototype.toString.call(what) === '[object Array]'; | |
| 2103 | −} | |
| 2457 | + /** | |
| 2458 | + * This function is only used for react-native. | |
| 2459 | + * react-native freezes object that have already been sent over the | |
| 2460 | + * js bridge. We need this function in order to check if the object is frozen. | |
| 2461 | + * So it's ok that objectFrozen returns false if Object.isFrozen is not | |
| 2462 | + * supported because it's not relevant for other "platforms". See related issue: | |
| 2463 | + * https://github.com/getsentry/react-native-sentry/issues/57 | |
| 2464 | + */ | |
| 2465 | + function objectFrozen(obj) { | |
| 2466 | + if (!Object.isFrozen) { | |
| 2467 | + return false; | |
| 2468 | + } | |
| 2469 | + return Object.isFrozen(obj); | |
| 2470 | + } | |
| 2104 | 2471 | |
| 2105 | −function isEmptyObject(what) { | |
| 2106 | − for (var _ in what) { | |
| 2107 | − if (what.hasOwnProperty(_)) { | |
| 2108 | − return false; | |
| 2109 | − } | |
| 2110 | − } | |
| 2111 | − return true; | |
| 2112 | −} | |
| 2113 | − | |
| 2114 | −function supportsErrorEvent() { | |
| 2115 | − try { | |
| 2116 | − new ErrorEvent(''); // eslint-disable-line no-new | |
| 2117 | − return true; | |
| 2118 | − } catch (e) { | |
| 2119 | − return false; | |
| 2120 | − } | |
| 2121 | −} | |
| 2472 | + function truncate(str, max) { | |
| 2473 | + return !max || str.length <= max | |
| 2474 | + ? str | |
| 2475 | + : str.substr(0, max) + "\u2026"; | |
| 2476 | + } | |
| 2122 | 2477 | |
| 2123 | −function wrappedCallback(callback) { | |
| 2124 | − function dataCallback(data, original) { | |
| 2125 | − var normalizedData = callback(data) || data; | |
| 2126 | − if (original) { | |
| 2127 | − return original(normalizedData) || normalizedData; | |
| 2128 | − } | |
| 2129 | − return normalizedData; | |
| 2130 | − } | |
| 2478 | + /** | |
| 2479 | + * hasKey, a better form of hasOwnProperty | |
| 2480 | + * Example: hasKey(MainHostObject, property) === true/false | |
| 2481 | + * | |
| 2482 | + * @param {Object} host object to check property | |
| 2483 | + * @param {string} key to check | |
| 2484 | + */ | |
| 2485 | + function hasKey(object, key) { | |
| 2486 | + return Object.prototype.hasOwnProperty.call(object, key); | |
| 2487 | + } | |
| 2131 | 2488 | |
| 2132 | − return dataCallback; | |
| 2133 | −} | |
| 2489 | + function joinRegExp(patterns) { | |
| 2490 | + // Combine an array of regular expressions and strings into one large regexp | |
| 2491 | + // Be mad. | |
| 2492 | + var sources = [], | |
| 2493 | + i = 0, | |
| 2494 | + len = patterns.length, | |
| 2495 | + pattern; | |
| 2496 | + | |
| 2497 | + for (; i < len; i++) { | |
| 2498 | + pattern = patterns[i]; | |
| 2499 | + if (isString(pattern)) { | |
| 2500 | + // If it's a string, we need to escape it | |
| 2501 | + // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions | |
| 2502 | + sources.push( | |
| 2503 | + pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"), | |
| 2504 | + ); | |
| 2505 | + } else if (pattern && pattern.source) { | |
| 2506 | + // If it's a regexp already, we want to extract the source | |
| 2507 | + sources.push(pattern.source); | |
| 2508 | + } | |
| 2509 | + // Intentionally skip other cases | |
| 2510 | + } | |
| 2511 | + return new RegExp(sources.join("|"), "i"); | |
| 2512 | + } | |
| 2134 | 2513 | |
| 2135 | −function each(obj, callback) { | |
| 2136 | − var i, j; | |
| 2514 | + function urlencode(o) { | |
| 2515 | + var pairs = []; | |
| 2516 | + each(o, function (key, value) { | |
| 2517 | + pairs.push( | |
| 2518 | + encodeURIComponent(key) + "=" + encodeURIComponent(value), | |
| 2519 | + ); | |
| 2520 | + }); | |
| 2521 | + return pairs.join("&"); | |
| 2522 | + } | |
| 2137 | 2523 | |
| 2138 | − if (isUndefined(obj.length)) { | |
| 2139 | − for (i in obj) { | |
| 2140 | − if (hasKey(obj, i)) { | |
| 2141 | − callback.call(null, i, obj[i]); | |
| 2142 | − } | |
| 2143 | − } | |
| 2144 | − } else { | |
| 2145 | − j = obj.length; | |
| 2146 | − if (j) { | |
| 2147 | − for (i = 0; i < j; i++) { | |
| 2148 | − callback.call(null, i, obj[i]); | |
| 2149 | − } | |
| 2150 | − } | |
| 2151 | − } | |
| 2152 | −} | |
| 2524 | + // borrowed from https://datatracker.ietf.org/doc/html/rfc3986#appendix-B | |
| 2525 | + // intentionally using regex and not <a/> href parsing trick because React Native and other | |
| 2526 | + // environments where DOM might not be available | |
| 2527 | + function parseUrl(url) { | |
| 2528 | + var match = url.match( | |
| 2529 | + /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/, | |
| 2530 | + ); | |
| 2531 | + if (!match) return {}; | |
| 2532 | + | |
| 2533 | + // coerce to undefined values to empty string so we don't get 'undefined' | |
| 2534 | + var query = match[6] || ""; | |
| 2535 | + var fragment = match[8] || ""; | |
| 2536 | + return { | |
| 2537 | + protocol: match[2], | |
| 2538 | + host: match[4], | |
| 2539 | + path: match[5], | |
| 2540 | + relative: match[5] + query + fragment, // everything minus origin | |
| 2541 | + }; | |
| 2542 | + } | |
| 2543 | + function uuid4() { | |
| 2544 | + var crypto = _window.crypto || _window.msCrypto; | |
| 2545 | + | |
| 2546 | + if (!isUndefined(crypto) && crypto.getRandomValues) { | |
| 2547 | + // Use window.crypto API if available | |
| 2548 | + // eslint-disable-next-line no-undef | |
| 2549 | + var arr = new Uint16Array(8); | |
| 2550 | + crypto.getRandomValues(arr); | |
| 2551 | + | |
| 2552 | + // set 4 in byte 7 | |
| 2553 | + arr[3] = (arr[3] & 0xfff) | 0x4000; | |
| 2554 | + // set 2 most significant bits of byte 9 to '10' | |
| 2555 | + arr[4] = (arr[4] & 0x3fff) | 0x8000; | |
| 2556 | + | |
| 2557 | + var pad = function (num) { | |
| 2558 | + var v = num.toString(16); | |
| 2559 | + while (v.length < 4) { | |
| 2560 | + v = "0" + v; | |
| 2561 | + } | |
| 2562 | + return v; | |
| 2563 | + }; | |
| 2153 | 2564 | |
| 2154 | −function objectMerge(obj1, obj2) { | |
| 2155 | − if (!obj2) { | |
| 2156 | − return obj1; | |
| 2157 | − } | |
| 2158 | − each(obj2, function(key, value) { | |
| 2159 | − obj1[key] = value; | |
| 2160 | − }); | |
| 2161 | − return obj1; | |
| 2162 | −} | |
| 2163 | − | |
| 2164 | −/** | |
| 2165 | − * This function is only used for react-native. | |
| 2166 | − * react-native freezes object that have already been sent over the | |
| 2167 | − * js bridge. We need this function in order to check if the object is frozen. | |
| 2168 | − * So it's ok that objectFrozen returns false if Object.isFrozen is not | |
| 2169 | − * supported because it's not relevant for other "platforms". See related issue: | |
| 2170 | − * https://github.com/getsentry/react-native-sentry/issues/57 | |
| 2171 | − */ | |
| 2172 | −function objectFrozen(obj) { | |
| 2173 | − if (!Object.isFrozen) { | |
| 2174 | − return false; | |
| 2175 | − } | |
| 2176 | − return Object.isFrozen(obj); | |
| 2177 | −} | |
| 2565 | + return ( | |
| 2566 | + pad(arr[0]) + | |
| 2567 | + pad(arr[1]) + | |
| 2568 | + pad(arr[2]) + | |
| 2569 | + pad(arr[3]) + | |
| 2570 | + pad(arr[4]) + | |
| 2571 | + pad(arr[5]) + | |
| 2572 | + pad(arr[6]) + | |
| 2573 | + pad(arr[7]) | |
| 2574 | + ); | |
| 2575 | + } else { | |
| 2576 | + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 | |
| 2577 | + return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace( | |
| 2578 | + /[xy]/g, | |
| 2579 | + function (c) { | |
| 2580 | + var r = (Math.random() * 16) | 0, | |
| 2581 | + v = c === "x" ? r : (r & 0x3) | 0x8; | |
| 2582 | + return v.toString(16); | |
| 2583 | + }, | |
| 2584 | + ); | |
| 2585 | + } | |
| 2586 | + } | |
| 2178 | 2587 | |
| 2179 | −function truncate(str, max) { | |
| 2180 | − return !max || str.length <= max ? str : str.substr(0, max) + '\u2026'; | |
| 2181 | −} | |
| 2588 | + /** | |
| 2589 | + * Given a child DOM element, returns a query-selector statement describing that | |
| 2590 | + * and its ancestors | |
| 2591 | + * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] | |
| 2592 | + * @param elem | |
| 2593 | + * @returns {string} | |
| 2594 | + */ | |
| 2595 | + function htmlTreeAsString(elem) { | |
| 2596 | + /* eslint no-extra-parens:0*/ | |
| 2597 | + var MAX_TRAVERSE_HEIGHT = 5, | |
| 2598 | + MAX_OUTPUT_LEN = 80, | |
| 2599 | + out = [], | |
| 2600 | + height = 0, | |
| 2601 | + len = 0, | |
| 2602 | + separator = " > ", | |
| 2603 | + sepLength = separator.length, | |
| 2604 | + nextStr; | |
| 2605 | + | |
| 2606 | + while (elem && height++ < MAX_TRAVERSE_HEIGHT) { | |
| 2607 | + nextStr = htmlElementAsString(elem); | |
| 2608 | + // bail out if | |
| 2609 | + // - nextStr is the 'html' element | |
| 2610 | + // - the length of the string that would be created exceeds MAX_OUTPUT_LEN | |
| 2611 | + // (ignore this limit if we are on the first iteration) | |
| 2612 | + if ( | |
| 2613 | + nextStr === "html" || | |
| 2614 | + (height > 1 && | |
| 2615 | + len + out.length * sepLength + nextStr.length >= | |
| 2616 | + MAX_OUTPUT_LEN) | |
| 2617 | + ) { | |
| 2618 | + break; | |
| 2619 | + } | |
| 2182 | 2620 | |
| 2183 | −/** | |
| 2184 | − * hasKey, a better form of hasOwnProperty | |
| 2185 | − * Example: hasKey(MainHostObject, property) === true/false | |
| 2186 | − * | |
| 2187 | − * @param {Object} host object to check property | |
| 2188 | − * @param {string} key to check | |
| 2189 | − */ | |
| 2190 | −function hasKey(object, key) { | |
| 2191 | − return Object.prototype.hasOwnProperty.call(object, key); | |
| 2192 | −} | |
| 2193 | − | |
| 2194 | −function joinRegExp(patterns) { | |
| 2195 | − // Combine an array of regular expressions and strings into one large regexp | |
| 2196 | − // Be mad. | |
| 2197 | − var sources = [], | |
| 2198 | − i = 0, | |
| 2199 | − len = patterns.length, | |
| 2200 | − pattern; | |
| 2201 | − | |
| 2202 | − for (; i < len; i++) { | |
| 2203 | − pattern = patterns[i]; | |
| 2204 | − if (isString(pattern)) { | |
| 2205 | − // If it's a string, we need to escape it | |
| 2206 | − // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions | |
| 2207 | − sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1')); | |
| 2208 | − } else if (pattern && pattern.source) { | |
| 2209 | − // If it's a regexp already, we want to extract the source | |
| 2210 | − sources.push(pattern.source); | |
| 2211 | − } | |
| 2212 | − // Intentionally skip other cases | |
| 2213 | − } | |
| 2214 | − return new RegExp(sources.join('|'), 'i'); | |
| 2215 | −} | |
| 2216 | − | |
| 2217 | −function urlencode(o) { | |
| 2218 | − var pairs = []; | |
| 2219 | − each(o, function(key, value) { | |
| 2220 | − pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); | |
| 2221 | − }); | |
| 2222 | − return pairs.join('&'); | |
| 2223 | −} | |
| 2224 | − | |
| 2225 | −// borrowed from https://datatracker.ietf.org/doc/html/rfc3986#appendix-B | |
| 2226 | −// intentionally using regex and not <a/> href parsing trick because React Native and other | |
| 2227 | −// environments where DOM might not be available | |
| 2228 | −function parseUrl(url) { | |
| 2229 | − var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/); | |
| 2230 | − if (!match) return {}; | |
| 2231 | − | |
| 2232 | − // coerce to undefined values to empty string so we don't get 'undefined' | |
| 2233 | − var query = match[6] || ''; | |
| 2234 | − var fragment = match[8] || ''; | |
| 2235 | − return { | |
| 2236 | − protocol: match[2], | |
| 2237 | − host: match[4], | |
| 2238 | − path: match[5], | |
| 2239 | − relative: match[5] + query + fragment // everything minus origin | |
| 2240 | − }; | |
| 2241 | −} | |
| 2242 | −function uuid4() { | |
| 2243 | − var crypto = _window.crypto || _window.msCrypto; | |
| 2244 | − | |
| 2245 | − if (!isUndefined(crypto) && crypto.getRandomValues) { | |
| 2246 | − // Use window.crypto API if available | |
| 2247 | − // eslint-disable-next-line no-undef | |
| 2248 | − var arr = new Uint16Array(8); | |
| 2249 | − crypto.getRandomValues(arr); | |
| 2250 | − | |
| 2251 | − // set 4 in byte 7 | |
| 2252 | − arr[3] = (arr[3] & 0xfff) | 0x4000; | |
| 2253 | − // set 2 most significant bits of byte 9 to '10' | |
| 2254 | − arr[4] = (arr[4] & 0x3fff) | 0x8000; | |
| 2255 | − | |
| 2256 | − var pad = function(num) { | |
| 2257 | − var v = num.toString(16); | |
| 2258 | − while (v.length < 4) { | |
| 2259 | − v = '0' + v; | |
| 2260 | − } | |
| 2261 | − return v; | |
| 2262 | − }; | |
| 2263 | − | |
| 2264 | − return ( | |
| 2265 | − pad(arr[0]) + | |
| 2266 | − pad(arr[1]) + | |
| 2267 | − pad(arr[2]) + | |
| 2268 | − pad(arr[3]) + | |
| 2269 | − pad(arr[4]) + | |
| 2270 | − pad(arr[5]) + | |
| 2271 | − pad(arr[6]) + | |
| 2272 | − pad(arr[7]) | |
| 2273 | − ); | |
| 2274 | − } else { | |
| 2275 | − // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 | |
| 2276 | − return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |
| 2277 | − var r = (Math.random() * 16) | 0, | |
| 2278 | − v = c === 'x' ? r : (r & 0x3) | 0x8; | |
| 2279 | − return v.toString(16); | |
| 2280 | − }); | |
| 2281 | − } | |
| 2282 | −} | |
| 2283 | − | |
| 2284 | −/** | |
| 2285 | − * Given a child DOM element, returns a query-selector statement describing that | |
| 2286 | − * and its ancestors | |
| 2287 | − * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] | |
| 2288 | − * @param elem | |
| 2289 | − * @returns {string} | |
| 2290 | − */ | |
| 2291 | −function htmlTreeAsString(elem) { | |
| 2292 | − /* eslint no-extra-parens:0*/ | |
| 2293 | − var MAX_TRAVERSE_HEIGHT = 5, | |
| 2294 | − MAX_OUTPUT_LEN = 80, | |
| 2295 | − out = [], | |
| 2296 | − height = 0, | |
| 2297 | − len = 0, | |
| 2298 | − separator = ' > ', | |
| 2299 | − sepLength = separator.length, | |
| 2300 | − nextStr; | |
| 2301 | − | |
| 2302 | − while (elem && height++ < MAX_TRAVERSE_HEIGHT) { | |
| 2303 | − nextStr = htmlElementAsString(elem); | |
| 2304 | − // bail out if | |
| 2305 | − // - nextStr is the 'html' element | |
| 2306 | − // - the length of the string that would be created exceeds MAX_OUTPUT_LEN | |
| 2307 | − // (ignore this limit if we are on the first iteration) | |
| 2308 | − if ( | |
| 2309 | − nextStr === 'html' || | |
| 2310 | − (height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN) | |
| 2311 | − ) { | |
| 2312 | − break; | |
| 2313 | − } | |
| 2621 | + out.push(nextStr); | |
| 2314 | 2622 | |
| 2315 | − out.push(nextStr); | |
| 2623 | + len += nextStr.length; | |
| 2624 | + elem = elem.parentNode; | |
| 2625 | + } | |
| 2316 | 2626 | |
| 2317 | − len += nextStr.length; | |
| 2318 | − elem = elem.parentNode; | |
| 2319 | − } | |
| 2627 | + return out.reverse().join(separator); | |
| 2628 | + } | |
| 2320 | 2629 | |
| 2321 | − return out.reverse().join(separator); | |
| 2322 | −} | |
| 2630 | + /** | |
| 2631 | + * Returns a simple, query-selector representation of a DOM element | |
| 2632 | + * e.g. [HTMLElement] => input#foo.btn[name=baz] | |
| 2633 | + * @param HTMLElement | |
| 2634 | + * @returns {string} | |
| 2635 | + */ | |
| 2636 | + function htmlElementAsString(elem) { | |
| 2637 | + var out = [], | |
| 2638 | + className, | |
| 2639 | + classes, | |
| 2640 | + key, | |
| 2641 | + attr, | |
| 2642 | + i; | |
| 2643 | + | |
| 2644 | + if (!elem || !elem.tagName) { | |
| 2645 | + return ""; | |
| 2646 | + } | |
| 2323 | 2647 | |
| 2324 | −/** | |
| 2325 | − * Returns a simple, query-selector representation of a DOM element | |
| 2326 | − * e.g. [HTMLElement] => input#foo.btn[name=baz] | |
| 2327 | − * @param HTMLElement | |
| 2328 | − * @returns {string} | |
| 2329 | − */ | |
| 2330 | −function htmlElementAsString(elem) { | |
| 2331 | − var out = [], | |
| 2332 | − className, | |
| 2333 | − classes, | |
| 2334 | − key, | |
| 2335 | − attr, | |
| 2336 | − i; | |
| 2337 | − | |
| 2338 | − if (!elem || !elem.tagName) { | |
| 2339 | − return ''; | |
| 2340 | − } | |
| 2648 | + out.push(elem.tagName.toLowerCase()); | |
| 2649 | + if (elem.id) { | |
| 2650 | + out.push("#" + elem.id); | |
| 2651 | + } | |
| 2341 | 2652 | |
| 2342 | − out.push(elem.tagName.toLowerCase()); | |
| 2343 | − if (elem.id) { | |
| 2344 | − out.push('#' + elem.id); | |
| 2345 | − } | |
| 2653 | + className = elem.className; | |
| 2654 | + if (className && isString(className)) { | |
| 2655 | + classes = className.split(/\s+/); | |
| 2656 | + for (i = 0; i < classes.length; i++) { | |
| 2657 | + out.push("." + classes[i]); | |
| 2658 | + } | |
| 2659 | + } | |
| 2660 | + var attrWhitelist = ["type", "name", "title", "alt"]; | |
| 2661 | + for (i = 0; i < attrWhitelist.length; i++) { | |
| 2662 | + key = attrWhitelist[i]; | |
| 2663 | + attr = elem.getAttribute(key); | |
| 2664 | + if (attr) { | |
| 2665 | + out.push("[" + key + '="' + attr + '"]'); | |
| 2666 | + } | |
| 2667 | + } | |
| 2668 | + return out.join(""); | |
| 2669 | + } | |
| 2346 | 2670 | |
| 2347 | − className = elem.className; | |
| 2348 | − if (className && isString(className)) { | |
| 2349 | − classes = className.split(/\s+/); | |
| 2350 | − for (i = 0; i < classes.length; i++) { | |
| 2351 | − out.push('.' + classes[i]); | |
| 2352 | − } | |
| 2353 | − } | |
| 2354 | − var attrWhitelist = ['type', 'name', 'title', 'alt']; | |
| 2355 | − for (i = 0; i < attrWhitelist.length; i++) { | |
| 2356 | − key = attrWhitelist[i]; | |
| 2357 | − attr = elem.getAttribute(key); | |
| 2358 | − if (attr) { | |
| 2359 | − out.push('[' + key + '="' + attr + '"]'); | |
| 2360 | − } | |
| 2361 | − } | |
| 2362 | − return out.join(''); | |
| 2363 | −} | |
| 2671 | + /** | |
| 2672 | + * Returns true if either a OR b is truthy, but not both | |
| 2673 | + */ | |
| 2674 | + function isOnlyOneTruthy(a, b) { | |
| 2675 | + return !!(!!a ^ !!b); | |
| 2676 | + } | |
| 2364 | 2677 | |
| 2365 | −/** | |
| 2366 | − * Returns true if either a OR b is truthy, but not both | |
| 2367 | − */ | |
| 2368 | −function isOnlyOneTruthy(a, b) { | |
| 2369 | − return !!(!!a ^ !!b); | |
| 2370 | −} | |
| 2678 | + /** | |
| 2679 | + * Returns true if the two input exception interfaces have the same content | |
| 2680 | + */ | |
| 2681 | + function isSameException(ex1, ex2) { | |
| 2682 | + if (isOnlyOneTruthy(ex1, ex2)) return false; | |
| 2371 | 2683 | |
| 2372 | −/** | |
| 2373 | − * Returns true if the two input exception interfaces have the same content | |
| 2374 | − */ | |
| 2375 | −function isSameException(ex1, ex2) { | |
| 2376 | − if (isOnlyOneTruthy(ex1, ex2)) return false; | |
| 2684 | + ex1 = ex1.values[0]; | |
| 2685 | + ex2 = ex2.values[0]; | |
| 2377 | 2686 | |
| 2378 | − ex1 = ex1.values[0]; | |
| 2379 | − ex2 = ex2.values[0]; | |
| 2687 | + if (ex1.type !== ex2.type || ex1.value !== ex2.value) | |
| 2688 | + return false; | |
| 2380 | 2689 | |
| 2381 | − if (ex1.type !== ex2.type || ex1.value !== ex2.value) return false; | |
| 2690 | + return isSameStacktrace(ex1.stacktrace, ex2.stacktrace); | |
| 2691 | + } | |
| 2382 | 2692 | |
| 2383 | − return isSameStacktrace(ex1.stacktrace, ex2.stacktrace); | |
| 2384 | −} | |
| 2693 | + /** | |
| 2694 | + * Returns true if the two input stack trace interfaces have the same content | |
| 2695 | + */ | |
| 2696 | + function isSameStacktrace(stack1, stack2) { | |
| 2697 | + if (isOnlyOneTruthy(stack1, stack2)) return false; | |
| 2698 | + | |
| 2699 | + var frames1 = stack1.frames; | |
| 2700 | + var frames2 = stack2.frames; | |
| 2701 | + | |
| 2702 | + // Exit early if frame count differs | |
| 2703 | + if (frames1.length !== frames2.length) return false; | |
| 2704 | + | |
| 2705 | + // Iterate through every frame; bail out if anything differs | |
| 2706 | + var a, b; | |
| 2707 | + for (var i = 0; i < frames1.length; i++) { | |
| 2708 | + a = frames1[i]; | |
| 2709 | + b = frames2[i]; | |
| 2710 | + if ( | |
| 2711 | + a.filename !== b.filename || | |
| 2712 | + a.lineno !== b.lineno || | |
| 2713 | + a.colno !== b.colno || | |
| 2714 | + a["function"] !== b["function"] | |
| 2715 | + ) | |
| 2716 | + return false; | |
| 2717 | + } | |
| 2718 | + return true; | |
| 2719 | + } | |
| 2385 | 2720 | |
| 2386 | −/** | |
| 2387 | − * Returns true if the two input stack trace interfaces have the same content | |
| 2388 | − */ | |
| 2389 | −function isSameStacktrace(stack1, stack2) { | |
| 2390 | − if (isOnlyOneTruthy(stack1, stack2)) return false; | |
| 2391 | − | |
| 2392 | − var frames1 = stack1.frames; | |
| 2393 | − var frames2 = stack2.frames; | |
| 2394 | − | |
| 2395 | − // Exit early if frame count differs | |
| 2396 | − if (frames1.length !== frames2.length) return false; | |
| 2397 | − | |
| 2398 | − // Iterate through every frame; bail out if anything differs | |
| 2399 | − var a, b; | |
| 2400 | − for (var i = 0; i < frames1.length; i++) { | |
| 2401 | − a = frames1[i]; | |
| 2402 | − b = frames2[i]; | |
| 2403 | − if ( | |
| 2404 | − a.filename !== b.filename || | |
| 2405 | − a.lineno !== b.lineno || | |
| 2406 | − a.colno !== b.colno || | |
| 2407 | − a['function'] !== b['function'] | |
| 2408 | − ) | |
| 2409 | − return false; | |
| 2410 | − } | |
| 2411 | − return true; | |
| 2412 | −} | |
| 2413 | − | |
| 2414 | −/** | |
| 2415 | − * Polyfill a method | |
| 2416 | − * @param obj object e.g. `document` | |
| 2417 | − * @param name method name present on object e.g. `addEventListener` | |
| 2418 | − * @param replacement replacement function | |
| 2419 | − * @param track {optional} record instrumentation to an array | |
| 2420 | − */ | |
| 2421 | −function fill(obj, name, replacement, track) { | |
| 2422 | − var orig = obj[name]; | |
| 2423 | − obj[name] = replacement(orig); | |
| 2424 | − obj[name].__raven__ = true; | |
| 2425 | − obj[name].__orig__ = orig; | |
| 2426 | − if (track) { | |
| 2427 | − track.push([obj, name, orig]); | |
| 2428 | − } | |
| 2429 | −} | |
| 2430 | − | |
| 2431 | −module.exports = { | |
| 2432 | − isObject: isObject, | |
| 2433 | − isError: isError, | |
| 2434 | − isErrorEvent: isErrorEvent, | |
| 2435 | − isUndefined: isUndefined, | |
| 2436 | − isFunction: isFunction, | |
| 2437 | − isString: isString, | |
| 2438 | − isArray: isArray, | |
| 2439 | − isEmptyObject: isEmptyObject, | |
| 2440 | − supportsErrorEvent: supportsErrorEvent, | |
| 2441 | − wrappedCallback: wrappedCallback, | |
| 2442 | − each: each, | |
| 2443 | − objectMerge: objectMerge, | |
| 2444 | − truncate: truncate, | |
| 2445 | − objectFrozen: objectFrozen, | |
| 2446 | − hasKey: hasKey, | |
| 2447 | − joinRegExp: joinRegExp, | |
| 2448 | − urlencode: urlencode, | |
| 2449 | − uuid4: uuid4, | |
| 2450 | − htmlTreeAsString: htmlTreeAsString, | |
| 2451 | − htmlElementAsString: htmlElementAsString, | |
| 2452 | − isSameException: isSameException, | |
| 2453 | − isSameStacktrace: isSameStacktrace, | |
| 2454 | − parseUrl: parseUrl, | |
| 2455 | − fill: fill | |
| 2456 | −}; | |
| 2457 | − | |
| 2458 | −}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
| 2459 | −},{}],6:[function(_dereq_,module,exports){ | |
| 2460 | −(function (global){ | |
| 2461 | −var utils = _dereq_(5); | |
| 2721 | + /** | |
| 2722 | + * Polyfill a method | |
| 2723 | + * @param obj object e.g. `document` | |
| 2724 | + * @param name method name present on object e.g. `addEventListener` | |
| 2725 | + * @param replacement replacement function | |
| 2726 | + * @param track {optional} record instrumentation to an array | |
| 2727 | + */ | |
| 2728 | + function fill(obj, name, replacement, track) { | |
| 2729 | + var orig = obj[name]; | |
| 2730 | + obj[name] = replacement(orig); | |
| 2731 | + obj[name].__raven__ = true; | |
| 2732 | + obj[name].__orig__ = orig; | |
| 2733 | + if (track) { | |
1440 more lines aren’t shown here.
| @@ -32,51 +32,46 @@ const Cls = (app.views.Content = class Content extends app.View { · 31 unmodified lines | ||
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | static initClass() { |
| 35 | − this.el = '._content'; | |
| 36 | − this.loadingClass = '_content-loading'; | |
| 37 | − | |
| 38 | − this.events = | |
| 39 | − {click: 'onClick'}; | |
| 40 | − | |
| 35 | + this.el = "._content"; | |
| 36 | + this.loadingClass = "_content-loading"; | |
| 37 | + | |
| 38 | + this.events = { click: "onClick" }; | |
| 39 | + | |
| 41 | 40 | this.shortcuts = { |
| 42 | − altUp: 'scrollStepUp', | |
| 43 | − altDown: 'scrollStepDown', | |
| 44 | − pageUp: 'scrollPageUp', | |
| 45 | − pageDown: 'scrollPageDown', | |
| 46 | − pageTop: 'scrollToTop', | |
| 47 | − pageBottom: 'scrollToBottom', | |
| 48 | − altF: 'onAltF' | |
| 41 | + altUp: "scrollStepUp", | |
| 42 | + altDown: "scrollStepDown", | |
| 43 | + pageUp: "scrollPageUp", | |
| 44 | + pageDown: "scrollPageDown", | |
| 45 | + pageTop: "scrollToTop", | |
| 46 | + pageBottom: "scrollToBottom", | |
| 47 | + altF: "onAltF", | |
| 49 | 48 | }; |
| 50 | − | |
| 49 | + | |
| 51 | 50 | this.routes = { |
| 52 | − before: 'beforeRoute', | |
| 53 | − after: 'afterRoute' | |
| 51 | + before: "beforeRoute", | |
| 52 | + after: "afterRoute", | |
| 54 | 53 | }; |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | 56 | init() { |
| 58 | − this.scrollEl = app.isMobile() ? | |
| 59 | − (document.scrollingElement || document.body) | |
| 60 | − : | |
| 61 | − this.el; | |
| 57 | + this.scrollEl = app.isMobile() | |
| 58 | + ? document.scrollingElement || document.body | |
| 59 | + : this.el; | |
| 62 | 60 | this.scrollMap = {}; |
| 63 | 61 | this.scrollStack = []; |
| 64 | 62 | |
| 65 | − this.rootPage = new app.views.RootPage; | |
| 66 | − this.staticPage = new app.views.StaticPage; | |
| 67 | − this.settingsPage = new app.views.SettingsPage; | |
| 68 | − this.offlinePage = new app.views.OfflinePage; | |
| 69 | − this.typePage = new app.views.TypePage; | |
| 70 | − this.entryPage = new app.views.EntryPage; | |
| 63 | + this.rootPage = new app.views.RootPage(); | |
| 64 | + this.staticPage = new app.views.StaticPage(); | |
| 65 | + this.settingsPage = new app.views.SettingsPage(); | |
| 66 | + this.offlinePage = new app.views.OfflinePage(); | |
| 67 | + this.typePage = new app.views.TypePage(); | |
| 68 | + this.entryPage = new app.views.EntryPage(); | |
| 71 | 69 | |
| 72 | 70 | this.entryPage |
| 73 | − .on('loading', this.onEntryLoading) | |
| 74 | − .on('loaded', this.onEntryLoaded); | |
| 75 | − | |
| 76 | − app | |
| 77 | − .on('ready', this.onReady) | |
| 78 | − .on('bootError', this.onBootError); | |
| 71 | + .on("loading", this.onEntryLoading) | |
| 72 | + .on("loaded", this.onEntryLoaded); | |
| 79 | 73 | |
| 74 | + app.on("ready", this.onReady).on("bootError", this.onBootError); | |
| 80 | 75 | } |
| 81 | 76 | |
| 82 | 77 | show(view) { |
| @@ -85,7 +80,7 @@ const Cls = (app.views.Content = class Content extends app.View { · 2 unmodified lines | ||
| 85 | 80 | if (this.view != null) { |
| 86 | 81 | this.view.deactivate(); |
| 87 | 82 | } |
| 88 | − this.html(this.view = view); | |
| 83 | + this.html((this.view = view)); | |
| 89 | 84 | this.view.activate(); |
| 90 | 85 | } |
| 91 | 86 | } |
| @@ -107,7 +102,7 @@ const Cls = (app.views.Content = class Content extends app.View { · 15 unmodified lines | ||
| 107 | 102 | } |
| 108 | 103 | |
| 109 | 104 | smoothScrollTo(value) { |
| 110 | − if (app.settings.get('fastScroll')) { | |
| 105 | + if (app.settings.get("fastScroll")) { | |
| 111 | 106 | this.scrollTo(value); |
| 112 | 107 | } else { |
| 113 | 108 | $.smoothScroll(this.scrollEl, value || 0); |
| @@ -144,10 +139,14 @@ const Cls = (app.views.Content = class Content extends app.View { · 30 unmodified lines | ||
| 144 | 139 | |
| 145 | 140 | scrollToTarget() { |
| 146 | 141 | let el; |
| 147 | − if (this.routeCtx.hash && (el = this.findTargetByHash(this.routeCtx.hash))) { | |
| 148 | − $.scrollToWithImageLock(el, this.scrollEl, 'top', | |
| 149 | − {margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top}); | |
| 150 | − $.highlight(el, {className: '_highlight'}); | |
| 142 | + if ( | |
| 143 | + this.routeCtx.hash && | |
| 144 | + (el = this.findTargetByHash(this.routeCtx.hash)) | |
| 145 | + ) { | |
| 146 | + $.scrollToWithImageLock(el, this.scrollEl, "top", { | |
| 147 | + margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top, | |
| 148 | + }); | |
| 149 | + $.highlight(el, { className: "_highlight" }); | |
| 151 | 150 | } else { |
| 152 | 151 | this.scrollTo(this.scrollMap[this.routeCtx.state.id]); |
| 153 | 152 | } |
| @@ -159,7 +158,7 @@ const Cls = (app.views.Content = class Content extends app.View { · 5 unmodified lines | ||
| 159 | 158 | |
| 160 | 159 | onBootError() { |
| 161 | 160 | this.hideLoading(); |
| 162 | − this.html(this.tmpl('bootError')); | |
| 161 | + this.html(this.tmpl("bootError")); | |
| 163 | 162 | } |
| 164 | 163 | |
| 165 | 164 | onEntryLoading() { |
| @@ -186,8 +185,12 @@ const Cls = (app.views.Content = class Content extends app.View { · 20 unmodified lines | ||
| 186 | 185 | } |
| 187 | 186 | |
| 188 | 187 | cacheScrollPosition() { |
| 189 | − if (!this.routeCtx || this.routeCtx.hash) { return; } | |
| 190 | − if (this.routeCtx.path === '/') { return; } | |
| 188 | + if (!this.routeCtx || this.routeCtx.hash) { | |
| 189 | + return; | |
| 190 | + } | |
| 191 | + if (this.routeCtx.path === "/") { | |
| 192 | + return; | |
| 193 | + } | |
| 191 | 194 | |
| 192 | 195 | if (this.scrollMap[this.routeCtx.state.id] == null) { |
| 193 | 196 | this.scrollStack.push(this.routeCtx.state.id); |
| @@ -200,24 +203,24 @@ const Cls = (app.views.Content = class Content extends app.View { · 6 unmodified lines | ||
| 200 | 203 | } |
| 201 | 204 | |
| 202 | 205 | afterRoute(route, context) { |
| 203 | − if ((route !== 'entry') && (route !== 'type')) { | |
| 206 | + if (route !== "entry" && route !== "type") { | |
| 204 | 207 | resetFavicon(); |
| 205 | 208 | } |
| 206 | 209 | |
| 207 | 210 | switch (route) { |
| 208 | − case 'root': | |
| 211 | + case "root": | |
| 209 | 212 | this.show(this.rootPage); |
| 210 | 213 | break; |
| 211 | − case 'entry': | |
| 214 | + case "entry": | |
| 212 | 215 | this.show(this.entryPage); |
| 213 | 216 | break; |
| 214 | − case 'type': | |
| 217 | + case "type": | |
| 215 | 218 | this.show(this.typePage); |
| 216 | 219 | break; |
| 217 | − case 'settings': | |
| 220 | + case "settings": | |
| 218 | 221 | this.show(this.settingsPage); |
| 219 | 222 | break; |
| 220 | − case 'offline': | |
| 223 | + case "offline": | |
| 221 | 224 | this.show(this.offlinePage); |
| 222 | 225 | break; |
| 223 | 226 | default: |
| @@ -225,37 +228,59 @@ const Cls = (app.views.Content = class Content extends app.View { · 1 unmodified line | ||
| 225 | 228 | } |
| 226 | 229 | |
| 227 | 230 | this.view.onRoute(context); |
| 228 | − app.document.setTitle(typeof this.view.getTitle === 'function' ? this.view.getTitle() : undefined); | |
| 231 | + app.document.setTitle( | |
| 232 | + typeof this.view.getTitle === "function" | |
| 233 | + ? this.view.getTitle() | |
| 234 | + : undefined, | |
| 235 | + ); | |
| 229 | 236 | } |
| 230 | 237 | |
| 231 | 238 | onClick(event) { |
| 232 | 239 | const link = $.closestLink($.eventTarget(event), this.el); |
| 233 | − if (link && this.isExternalUrl(link.getAttribute('href'))) { | |
| 240 | + if (link && this.isExternalUrl(link.getAttribute("href"))) { | |
| 234 | 241 | $.stopEvent(event); |
| 235 | 242 | $.popup(link); |
| 236 | 243 | } |
| 237 | 244 | } |
| 238 | 245 | |
| 239 | 246 | onAltF(event) { |
| 240 | − if (!document.activeElement || !$.hasChild(this.el, document.activeElement)) { | |
| 241 | − __guard__(this.find('a:not(:empty)'), x => x.focus()); | |
| 247 | + if ( | |
| 248 | + !document.activeElement || | |
| 249 | + !$.hasChild(this.el, document.activeElement) | |
| 250 | + ) { | |
| 251 | + __guard__(this.find("a:not(:empty)"), (x) => x.focus()); | |
| 242 | 252 | return $.stopEvent(event); |
| 243 | 253 | } |
| 244 | 254 | } |
| 245 | 255 | |
| 246 | 256 | findTargetByHash(hash) { |
| 247 | − let el = (() => { try { return $.id(decodeURIComponent(hash)); } catch (error) {} })(); | |
| 248 | − if (!el) { el = (() => { try { return $.id(hash); } catch (error1) {} })(); } | |
| 257 | + let el = (() => { | |
| 258 | + try { | |
| 259 | + return $.id(decodeURIComponent(hash)); | |
| 260 | + } catch (error) {} | |
| 261 | + })(); | |
| 262 | + if (!el) { | |
| 263 | + el = (() => { | |
| 264 | + try { | |
| 265 | + return $.id(hash); | |
| 266 | + } catch (error1) {} | |
| 267 | + })(); | |
| 268 | + } | |
| 249 | 269 | return el; |
| 250 | 270 | } |
| 251 | 271 | |
| 252 | 272 | isExternalUrl(url) { |
| 253 | 273 | let needle; |
| 254 | − return (needle = __guard__(url, x => x.slice(0, 6)), ['http:/', 'https:'].includes(needle)); | |
| 274 | + return ( | |
| 275 | + (needle = __guard__(url, (x) => x.slice(0, 6))), | |
| 276 | + ["http:/", "https:"].includes(needle) | |
| 277 | + ); | |
| 255 | 278 | } |
| 256 | 279 | }); |
| 257 | 280 | Cls.initClass(); |
| 258 | 281 | |
| 259 | 282 | function __guard__(value, transform) { |
| 260 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 261 | −} | |
| 283 | + return typeof value !== "undefined" && value !== null | |
| 284 | + ? transform(value) | |
| 285 | + : undefined; | |
| 286 | +} | |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | * DS207: Consider shorter variations of null checks |
| 11 | 11 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 12 | 12 | */ |
| 13 | −(function() { | |
| 13 | +(function () { | |
| 14 | 14 | let LINKS = undefined; |
| 15 | 15 | const Cls = (app.views.EntryPage = class EntryPage extends app.View { |
| 16 | 16 | constructor(...args) { |
| @@ -24,23 +24,21 @@ · 7 unmodified lines | ||
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | static initClass() { |
| 27 | − this.className = '_page'; | |
| 28 | − this.errorClass = '_page-error'; | |
| 29 | − | |
| 30 | − this.events = | |
| 31 | − {click: 'onClick'}; | |
| 32 | − | |
| 27 | + this.className = "_page"; | |
| 28 | + this.errorClass = "_page-error"; | |
| 29 | + | |
| 30 | + this.events = { click: "onClick" }; | |
| 31 | + | |
| 33 | 32 | this.shortcuts = { |
| 34 | − altC: 'onAltC', | |
| 35 | − altO: 'onAltO' | |
| 33 | + altC: "onAltC", | |
| 34 | + altO: "onAltO", | |
| 36 | 35 | }; |
| 37 | − | |
| 38 | − this.routes = | |
| 39 | − {before: 'beforeRoute'}; | |
| 40 | − | |
| 36 | + | |
| 37 | + this.routes = { before: "beforeRoute" }; | |
| 38 | + | |
| 41 | 39 | LINKS = { |
| 42 | − home: 'Homepage', | |
| 43 | − code: 'Source code' | |
| 40 | + home: "Homepage", | |
| 41 | + code: "Source code", | |
| 44 | 42 | }; |
| 45 | 43 | } |
| 46 | 44 | |
| @@ -58,61 +56,84 @@ · 11 unmodified lines | ||
| 58 | 56 | |
| 59 | 57 | loading() { |
| 60 | 58 | this.empty(); |
| 61 | − this.trigger('loading'); | |
| 59 | + this.trigger("loading"); | |
| 62 | 60 | } |
| 63 | 61 | |
| 64 | 62 | render(content, fromCache) { |
| 65 | − if (content == null) { content = ''; } | |
| 66 | − if (fromCache == null) { fromCache = false; } | |
| 67 | − if (!this.activated) { return; } | |
| 63 | + if (content == null) { | |
| 64 | + content = ""; | |
| 65 | + } | |
| 66 | + if (fromCache == null) { | |
| 67 | + fromCache = false; | |
| 68 | + } | |
| 69 | + if (!this.activated) { | |
| 70 | + return; | |
| 71 | + } | |
| 68 | 72 | this.empty(); |
| 69 | 73 | this.subview = new (this.subViewClass())(this.el, this.entry); |
| 70 | 74 | |
| 71 | 75 | $.batchUpdate(this.el, () => { |
| 72 | 76 | this.subview.render(content, fromCache); |
| 73 | − if (!fromCache) { this.addCopyButtons(); } | |
| 77 | + if (!fromCache) { | |
| 78 | + this.addCopyButtons(); | |
| 79 | + } | |
| 74 | 80 | }); |
| 75 | 81 | |
| 76 | − if (app.disabledDocs.findBy('slug', this.entry.doc.slug)) { | |
| 82 | + if (app.disabledDocs.findBy("slug", this.entry.doc.slug)) { | |
| 77 | 83 | this.hiddenView = new app.views.HiddenPage(this.el, this.entry); |
| 78 | 84 | } |
| 79 | 85 | |
| 80 | 86 | setFaviconForDoc(this.entry.doc); |
| 81 | 87 | this.delay(this.polyfillMathML); |
| 82 | − this.trigger('loaded'); | |
| 88 | + this.trigger("loaded"); | |
| 83 | 89 | } |
| 84 | 90 | |
| 85 | 91 | addCopyButtons() { |
| 86 | 92 | if (!this.copyButton) { |
| 87 | − this.copyButton = document.createElement('button'); | |
| 93 | + this.copyButton = document.createElement("button"); | |
| 88 | 94 | this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>'; |
| 89 | − this.copyButton.type = 'button'; | |
| 90 | − this.copyButton.className = '_pre-clip'; | |
| 91 | − this.copyButton.title = 'Copy to clipboard'; | |
| 92 | − this.copyButton.setAttribute('aria-label', 'Copy to clipboard'); | |
| 95 | + this.copyButton.type = "button"; | |
| 96 | + this.copyButton.className = "_pre-clip"; | |
| 97 | + this.copyButton.title = "Copy to clipboard"; | |
| 98 | + this.copyButton.setAttribute("aria-label", "Copy to clipboard"); | |
| 99 | + } | |
| 100 | + for (var el of Array.from(this.findAllByTag("pre"))) { | |
| 101 | + el.appendChild(this.copyButton.cloneNode(true)); | |
| 93 | 102 | } |
| 94 | − for (var el of Array.from(this.findAllByTag('pre'))) { el.appendChild(this.copyButton.cloneNode(true)); } | |
| 95 | 103 | } |
| 96 | 104 | |
| 97 | 105 | polyfillMathML() { |
| 98 | − if ((window.supportsMathML !== false) || !!this.polyfilledMathML || !this.findByTag('math')) { return; } | |
| 106 | + if ( | |
| 107 | + window.supportsMathML !== false || | |
| 108 | + !!this.polyfilledMathML || | |
| 109 | + !this.findByTag("math") | |
| 110 | + ) { | |
| 111 | + return; | |
| 112 | + } | |
| 99 | 113 | this.polyfilledMathML = true; |
| 100 | − $.append(document.head, `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`); | |
| 114 | + $.append( | |
| 115 | + document.head, | |
| 116 | + `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`, | |
| 117 | + ); | |
| 101 | 118 | } |
| 102 | 119 | |
| 103 | 120 | prepareContent(content) { |
| 104 | − if (!this.entry.isIndex() || !this.entry.doc.links) { return content; } | |
| 121 | + if (!this.entry.isIndex() || !this.entry.doc.links) { | |
| 122 | + return content; | |
| 123 | + } | |
| 105 | 124 | |
| 106 | 125 | const links = (() => { |
| 107 | 126 | const result = []; |
| 108 | 127 | for (var link in this.entry.doc.links) { |
| 109 | 128 | var url = this.entry.doc.links[link]; |
| 110 | − result.push(`<a href="${url}" class="_links-link">${LINKS[link]}</a>`); | |
| 129 | + result.push( | |
| 130 | + `<a href="${url}" class="_links-link">${LINKS[link]}</a>`, | |
| 131 | + ); | |
| 111 | 132 | } |
| 112 | 133 | return result; |
| 113 | 134 | })(); |
| 114 | 135 | |
| 115 | − return `<p class="_links">${links.join('')}</p>${content}`; | |
| 136 | + return `<p class="_links">${links.join("")}</p>${content}`; | |
| 116 | 137 | } |
| 117 | 138 | |
| 118 | 139 | empty() { |
| @@ -131,11 +152,17 @@ · 12 unmodified lines | ||
| 131 | 152 | } |
| 132 | 153 | |
| 133 | 154 | subViewClass() { |
| 134 | − return app.views[`${$.classify(this.entry.doc.type)}Page`] || app.views.BasePage; | |
| 155 | + return ( | |
| 156 | + app.views[`${$.classify(this.entry.doc.type)}Page`] || | |
| 157 | + app.views.BasePage | |
| 158 | + ); | |
| 135 | 159 | } |
| 136 | 160 | |
| 137 | 161 | getTitle() { |
| 138 | − return this.entry.doc.fullName + (this.entry.isIndex() ? ' documentation' : ` / ${this.entry.name}`); | |
| 162 | + return ( | |
| 163 | + this.entry.doc.fullName + | |
| 164 | + (this.entry.isIndex() ? " documentation" : ` / ${this.entry.name}`) | |
| 165 | + ); | |
| 139 | 166 | } |
| 140 | 167 | |
| 141 | 168 | beforeRoute() { |
| @@ -144,9 +171,13 @@ · 2 unmodified lines | ||
| 144 | 171 | } |
| 145 | 172 | |
| 146 | 173 | onRoute(context) { |
| 147 | − const isSameFile = context.entry.filePath() === (this.entry != null ? this.entry.filePath() : undefined); | |
| 174 | + const isSameFile = | |
| 175 | + context.entry.filePath() === | |
| 176 | + (this.entry != null ? this.entry.filePath() : undefined); | |
| 148 | 177 | this.entry = context.entry; |
| 149 | − if (!isSameFile) { this.restore() || this.load(); } | |
| 178 | + if (!isSameFile) { | |
| 179 | + this.restore() || this.load(); | |
| 180 | + } | |
| 150 | 181 | } |
| 151 | 182 | |
| 152 | 183 | load() { |
| @@ -157,19 +188,21 @@ · 4 unmodified lines | ||
| 157 | 188 | abort() { |
| 158 | 189 | if (this.xhr) { |
| 159 | 190 | this.xhr.abort(); |
| 160 | − this.xhr = (this.entry = null); | |
| 191 | + this.xhr = this.entry = null; | |
| 161 | 192 | } |
| 162 | 193 | } |
| 163 | 194 | |
| 164 | 195 | onSuccess(response) { |
| 165 | − if (!this.activated) { return; } | |
| 196 | + if (!this.activated) { | |
| 197 | + return; | |
| 198 | + } | |
| 166 | 199 | this.xhr = null; |
| 167 | 200 | this.render(this.prepareContent(response)); |
| 168 | 201 | } |
| 169 | 202 | |
| 170 | 203 | onError() { |
| 171 | 204 | this.xhr = null; |
| 172 | − this.render(this.tmpl('pageLoadError')); | |
| 205 | + this.render(this.tmpl("pageLoadError")); | |
| 173 | 206 | this.resetClass(); |
| 174 | 207 | this.addClass(this.constructor.errorClass); |
| 175 | 208 | if (app.serviceWorker != null) { |
| @@ -179,7 +212,13 @@ · 3 unmodified lines | ||
| 179 | 212 | |
| 180 | 213 | cache() { |
| 181 | 214 | let path; |
| 182 | − if (this.xhr || !this.entry || this.cacheMap[(path = this.entry.filePath())]) { return; } | |
| 215 | + if ( | |
| 216 | + this.xhr || | |
| 217 | + !this.entry || | |
| 218 | + this.cacheMap[(path = this.entry.filePath())] | |
| 219 | + ) { | |
| 220 | + return; | |
| 221 | + } | |
| 183 | 222 | |
| 184 | 223 | this.cacheMap[path] = this.el.innerHTML; |
| 185 | 224 | this.cacheStack.push(path); |
| @@ -199,26 +238,34 @@ · 13 unmodified lines | ||
| 199 | 238 | |
| 200 | 239 | onClick(event) { |
| 201 | 240 | const target = $.eventTarget(event); |
| 202 | − if (target.hasAttribute('data-retry')) { | |
| 241 | + if (target.hasAttribute("data-retry")) { | |
| 203 | 242 | $.stopEvent(event); |
| 204 | 243 | this.load(); |
| 205 | − } else if (target.classList.contains('_pre-clip')) { | |
| 244 | + } else if (target.classList.contains("_pre-clip")) { | |
| 206 | 245 | $.stopEvent(event); |
| 207 | − target.classList.add($.copyToClipboard(target.parentNode.textContent) ? '_pre-clip-success' : '_pre-clip-error'); | |
| 208 | − setTimeout((() => target.className = '_pre-clip'), 2000); | |
| 246 | + target.classList.add( | |
| 247 | + $.copyToClipboard(target.parentNode.textContent) | |
| 248 | + ? "_pre-clip-success" | |
| 249 | + : "_pre-clip-error", | |
| 250 | + ); | |
| 251 | + setTimeout(() => (target.className = "_pre-clip"), 2000); | |
| 209 | 252 | } |
| 210 | 253 | } |
| 211 | 254 | |
| 212 | 255 | onAltC() { |
| 213 | 256 | let link; |
| 214 | − if (!(link = this.find('._attribution:last-child ._attribution-link'))) { return; } | |
| 257 | + if (!(link = this.find("._attribution:last-child ._attribution-link"))) { | |
| 258 | + return; | |
| 259 | + } | |
| 215 | 260 | console.log(link.href + location.hash); |
| 216 | 261 | navigator.clipboard.writeText(link.href + location.hash); |
| 217 | 262 | } |
| 218 | 263 | |
| 219 | 264 | onAltO() { |
| 220 | 265 | let link; |
| 221 | − if (!(link = this.find('._attribution:last-child ._attribution-link'))) { return; } | |
| 266 | + if (!(link = this.find("._attribution:last-child ._attribution-link"))) { | |
| 267 | + return; | |
| 268 | + } | |
| 222 | 269 | this.delay(() => $.popup(link.href + location.hash)); |
| 223 | 270 | } |
| 224 | 271 | }); |
| @@ -15,11 +15,11 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View { · 14 unmodified lines | ||
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | static initClass() { |
| 18 | − this.className = '_static'; | |
| 19 | − | |
| 18 | + this.className = "_static"; | |
| 19 | + | |
| 20 | 20 | this.events = { |
| 21 | − click: 'onClick', | |
| 22 | − change: 'onChange' | |
| 21 | + click: "onClick", | |
| 22 | + change: "onChange", | |
| 23 | 23 | }; |
| 24 | 24 | } |
| 25 | 25 | |
| @@ -31,41 +31,49 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View { · 5 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | render() { |
| 33 | 33 | if (app.cookieBlocked) { |
| 34 | − this.html(this.tmpl('offlineError', 'cookie_blocked')); | |
| 34 | + this.html(this.tmpl("offlineError", "cookie_blocked")); | |
| 35 | 35 | return; |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | − app.docs.getInstallStatuses(statuses => { | |
| 39 | − if (!this.activated) { return; } | |
| 38 | + app.docs.getInstallStatuses((statuses) => { | |
| 39 | + if (!this.activated) { | |
| 40 | + return; | |
| 41 | + } | |
| 40 | 42 | if (statuses === false) { |
| 41 | − this.html(this.tmpl('offlineError', app.db.reason, app.db.error)); | |
| 43 | + this.html(this.tmpl("offlineError", app.db.reason, app.db.error)); | |
| 42 | 44 | } else { |
| 43 | − let html = ''; | |
| 44 | − for (var doc of Array.from(app.docs.all())) { html += this.renderDoc(doc, statuses[doc.slug]); } | |
| 45 | − this.html(this.tmpl('offlinePage', html)); | |
| 45 | + let html = ""; | |
| 46 | + for (var doc of Array.from(app.docs.all())) { | |
| 47 | + html += this.renderDoc(doc, statuses[doc.slug]); | |
| 48 | + } | |
| 49 | + this.html(this.tmpl("offlinePage", html)); | |
| 46 | 50 | this.refreshLinks(); |
| 47 | 51 | } |
| 48 | 52 | }); |
| 49 | 53 | } |
| 50 | 54 | |
| 51 | 55 | renderDoc(doc, status) { |
| 52 | − return app.templates.render('offlineDoc', doc, status); | |
| 56 | + return app.templates.render("offlineDoc", doc, status); | |
| 53 | 57 | } |
| 54 | 58 | |
| 55 | 59 | getTitle() { |
| 56 | − return 'Offline'; | |
| 60 | + return "Offline"; | |
| 57 | 61 | } |
| 58 | 62 | |
| 59 | 63 | refreshLinks() { |
| 60 | − for (var action of ['install', 'update', 'uninstall']) { | |
| 61 | − this.find(`[data-action-all='${action}']`).classList[this.find(`[data-action='${action}']`) ? 'add' : 'remove']('_show'); | |
| 64 | + for (var action of ["install", "update", "uninstall"]) { | |
| 65 | + this.find(`[data-action-all='${action}']`).classList[ | |
| 66 | + this.find(`[data-action='${action}']`) ? "add" : "remove" | |
| 67 | + ]("_show"); | |
| 62 | 68 | } |
| 63 | 69 | } |
| 64 | 70 | |
| 65 | 71 | docByEl(el) { |
| 66 | 72 | let slug; |
| 67 | − while (!(slug = el.getAttribute('data-slug'))) { el = el.parentNode; } | |
| 68 | − return app.docs.findBy('slug', slug); | |
| 73 | + while (!(slug = el.getAttribute("data-slug"))) { | |
| 74 | + el = el.parentNode; | |
| 75 | + } | |
| 76 | + return app.docs.findBy("slug", slug); | |
| 69 | 77 | } |
| 70 | 78 | |
| 71 | 79 | docEl(doc) { |
| @@ -79,26 +87,44 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View { · 7 unmodified lines | ||
| 79 | 87 | onClick(event) { |
| 80 | 88 | let action; |
| 81 | 89 | let el = $.eventTarget(event); |
| 82 | − if (action = el.getAttribute('data-action')) { | |
| 90 | + if ((action = el.getAttribute("data-action"))) { | |
| 83 | 91 | const doc = this.docByEl(el); |
| 84 | − if (action === 'update') { action = 'install'; } | |
| 85 | − doc[action](this.onInstallSuccess.bind(this, doc), this.onInstallError.bind(this, doc), this.onInstallProgress.bind(this, doc)); | |
| 86 | − el.parentNode.innerHTML = `${el.textContent.replace(/e$/, '')}ing…`; | |
| 87 | − } else if (action = el.getAttribute('data-action-all') || el.parentElement.getAttribute('data-action-all')) { | |
| 88 | − if ((action === 'uninstall') && !window.confirm('Uninstall all docs?')) { return; } | |
| 92 | + if (action === "update") { | |
| 93 | + action = "install"; | |
| 94 | + } | |
| 95 | + doc[action]( | |
| 96 | + this.onInstallSuccess.bind(this, doc), | |
| 97 | + this.onInstallError.bind(this, doc), | |
| 98 | + this.onInstallProgress.bind(this, doc), | |
| 99 | + ); | |
| 100 | + el.parentNode.innerHTML = `${el.textContent.replace(/e$/, "")}ing…`; | |
| 101 | + } else if ( | |
| 102 | + (action = | |
| 103 | + el.getAttribute("data-action-all") || | |
| 104 | + el.parentElement.getAttribute("data-action-all")) | |
| 105 | + ) { | |
| 106 | + if (action === "uninstall" && !window.confirm("Uninstall all docs?")) { | |
| 107 | + return; | |
| 108 | + } | |
| 89 | 109 | app.db.migrate(); |
| 90 | − for (el of Array.from(this.findAll(`[data-action='${action}']`))) { $.click(el); } | |
| 110 | + for (el of Array.from(this.findAll(`[data-action='${action}']`))) { | |
| 111 | + $.click(el); | |
| 112 | + } | |
| 91 | 113 | } |
| 92 | 114 | } |
| 93 | 115 | |
| 94 | 116 | onInstallSuccess(doc) { |
| 95 | − if (!this.activated) { return; } | |
| 96 | − doc.getInstallStatus(status => { | |
| 117 | + if (!this.activated) { | |
| 118 | + return; | |
| 119 | + } | |
| 120 | + doc.getInstallStatus((status) => { | |
| 97 | 121 | let el; |
| 98 | − if (!this.activated) { return; } | |
| 99 | − if (el = this.docEl(doc)) { | |
| 122 | + if (!this.activated) { | |
| 123 | + return; | |
| 124 | + } | |
| 125 | + if ((el = this.docEl(doc))) { | |
| 100 | 126 | el.outerHTML = this.renderDoc(doc, status); |
| 101 | − $.highlight(el, {className: '_highlight'}); | |
| 127 | + $.highlight(el, { className: "_highlight" }); | |
| 102 | 128 | this.refreshLinks(); |
| 103 | 129 | } |
| 104 | 130 | }); |
| @@ -106,24 +132,31 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View { · 1 unmodified line | ||
| 106 | 132 | |
| 107 | 133 | onInstallError(doc) { |
| 108 | 134 | let el; |
| 109 | − if (!this.activated) { return; } | |
| 110 | − if (el = this.docEl(doc)) { | |
| 111 | − el.lastElementChild.textContent = 'Error'; | |
| 135 | + if (!this.activated) { | |
| 136 | + return; | |
| 137 | + } | |
| 138 | + if ((el = this.docEl(doc))) { | |
| 139 | + el.lastElementChild.textContent = "Error"; | |
| 112 | 140 | } |
| 113 | 141 | } |
| 114 | 142 | |
| 115 | 143 | onInstallProgress(doc, event) { |
| 116 | 144 | let el; |
| 117 | − if (!this.activated || !event.lengthComputable) { return; } | |
| 118 | − if (el = this.docEl(doc)) { | |
| 145 | + if (!this.activated || !event.lengthComputable) { | |
| 146 | + return; | |
| 147 | + } | |
| 148 | + if ((el = this.docEl(doc))) { | |
| 119 | 149 | const percentage = Math.round((event.loaded * 100) / event.total); |
| 120 | − el.lastElementChild.textContent = el.lastElementChild.textContent.replace(/(\s.+)?$/, ` (${percentage}%)`); | |
| 150 | + el.lastElementChild.textContent = el.lastElementChild.textContent.replace( | |
| 151 | + /(\s.+)?$/, | |
| 152 | + ` (${percentage}%)`, | |
| 153 | + ); | |
| 121 | 154 | } |
| 122 | 155 | } |
| 123 | 156 | |
| 124 | 157 | onChange(event) { |
| 125 | − if (event.target.name === 'autoUpdate') { | |
| 126 | − app.settings.set('manualUpdate', !event.target.checked); | |
| 158 | + if (event.target.name === "autoUpdate") { | |
| 159 | + app.settings.set("manualUpdate", !event.target.checked); | |
| 127 | 160 | } |
| 128 | 161 | } |
| 129 | 162 | }); |
| @@ -14,26 +14,26 @@ const Cls = (app.views.RootPage = class RootPage extends app.View { · 13 unmodified lines | ||
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | static initClass() { |
| 17 | − this.events = | |
| 18 | − {click: 'onClick'}; | |
| 17 | + this.events = { click: "onClick" }; | |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | 20 | init() { |
| 22 | − if (!this.isHidden()) { this.setHidden(false); } // reserve space in local storage | |
| 21 | + if (!this.isHidden()) { | |
| 22 | + this.setHidden(false); | |
| 23 | + } // reserve space in local storage | |
| 23 | 24 | this.render(); |
| 24 | 25 | } |
| 25 | 26 | |
| 26 | 27 | render() { |
| 27 | 28 | this.empty(); |
| 28 | 29 | |
| 29 | − const tmpl = app.isAndroidWebview() ? | |
| 30 | − 'androidWarning' | |
| 31 | − : this.isHidden() ? | |
| 32 | − 'splash' | |
| 33 | − : app.isMobile() ? | |
| 34 | − 'mobileIntro' | |
| 35 | − : | |
| 36 | − 'intro'; | |
| 30 | + const tmpl = app.isAndroidWebview() | |
| 31 | + ? "androidWarning" | |
| 32 | + : this.isHidden() | |
| 33 | + ? "splash" | |
| 34 | + : app.isMobile() | |
| 35 | + ? "mobileIntro" | |
| 36 | + : "intro"; | |
| 37 | 37 | |
| 38 | 38 | this.append(this.tmpl(tmpl)); |
| 39 | 39 | } |
| @@ -44,17 +44,17 @@ const Cls = (app.views.RootPage = class RootPage extends app.View { · 4 unmodified lines | ||
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | setHidden(value) { |
| 47 | − app.settings.set('hideIntro', value); | |
| 47 | + app.settings.set("hideIntro", value); | |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | isHidden() { |
| 51 | − return app.isSingleDoc() || app.settings.get('hideIntro'); | |
| 51 | + return app.isSingleDoc() || app.settings.get("hideIntro"); | |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | onRoute() {} |
| 55 | 55 | |
| 56 | 56 | onClick(event) { |
| 57 | − if ($.eventTarget(event).hasAttribute('data-hide-intro')) { | |
| 57 | + if ($.eventTarget(event).hasAttribute("data-hide-intro")) { | |
| 58 | 58 | $.stopEvent(event); |
| 59 | 59 | this.hideIntro(); |
| 60 | 60 | } |
| @@ -17,39 +17,41 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View { · 16 unmodified lines | ||
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | static initClass() { |
| 20 | − this.className = '_static'; | |
| 21 | − | |
| 20 | + this.className = "_static"; | |
| 21 | + | |
| 22 | 22 | this.events = { |
| 23 | − click: 'onClick', | |
| 24 | − change: 'onChange' | |
| 23 | + click: "onClick", | |
| 24 | + change: "onChange", | |
| 25 | 25 | }; |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | render() { |
| 29 | − this.html(this.tmpl('settingsPage', this.currentSettings())); | |
| 29 | + this.html(this.tmpl("settingsPage", this.currentSettings())); | |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | 32 | currentSettings() { |
| 33 | 33 | const settings = {}; |
| 34 | − settings.theme = app.settings.get('theme'); | |
| 35 | − settings.smoothScroll = !app.settings.get('fastScroll'); | |
| 36 | − settings.arrowScroll = app.settings.get('arrowScroll'); | |
| 37 | − settings.noAutofocus = app.settings.get('noAutofocus'); | |
| 38 | − settings.autoInstall = app.settings.get('autoInstall'); | |
| 39 | − settings.analyticsConsent = app.settings.get('analyticsConsent'); | |
| 40 | − settings.spaceScroll = app.settings.get('spaceScroll'); | |
| 41 | − settings.spaceTimeout = app.settings.get('spaceTimeout'); | |
| 34 | + settings.theme = app.settings.get("theme"); | |
| 35 | + settings.smoothScroll = !app.settings.get("fastScroll"); | |
| 36 | + settings.arrowScroll = app.settings.get("arrowScroll"); | |
| 37 | + settings.noAutofocus = app.settings.get("noAutofocus"); | |
| 38 | + settings.autoInstall = app.settings.get("autoInstall"); | |
| 39 | + settings.analyticsConsent = app.settings.get("analyticsConsent"); | |
| 40 | + settings.spaceScroll = app.settings.get("spaceScroll"); | |
| 41 | + settings.spaceTimeout = app.settings.get("spaceTimeout"); | |
| 42 | 42 | settings.autoSupported = app.settings.autoSupported; |
| 43 | − for (var layout of Array.from(app.settings.LAYOUTS)) { settings[layout] = app.settings.hasLayout(layout); } | |
| 43 | + for (var layout of Array.from(app.settings.LAYOUTS)) { | |
| 44 | + settings[layout] = app.settings.hasLayout(layout); | |
| 45 | + } | |
| 44 | 46 | return settings; |
| 45 | 47 | } |
| 46 | 48 | |
| 47 | 49 | getTitle() { |
| 48 | − return 'Preferences'; | |
| 50 | + return "Preferences"; | |
| 49 | 51 | } |
| 50 | 52 | |
| 51 | 53 | setTheme(value) { |
| 52 | − app.settings.set('theme', value); | |
| 54 | + app.settings.set("theme", value); | |
| 53 | 55 | } |
| 54 | 56 | |
| 55 | 57 | toggleLayout(layout, enable) { |
| @@ -57,20 +59,22 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View { · 1 unmodified line | ||
| 57 | 59 | } |
| 58 | 60 | |
| 59 | 61 | toggleSmoothScroll(enable) { |
| 60 | − app.settings.set('fastScroll', !enable); | |
| 62 | + app.settings.set("fastScroll", !enable); | |
| 61 | 63 | } |
| 62 | 64 | |
| 63 | 65 | toggleAnalyticsConsent(enable) { |
| 64 | − app.settings.set('analyticsConsent', enable ? '1' : '0'); | |
| 65 | − if (!enable) { resetAnalytics(); } | |
| 66 | + app.settings.set("analyticsConsent", enable ? "1" : "0"); | |
| 67 | + if (!enable) { | |
| 68 | + resetAnalytics(); | |
| 69 | + } | |
| 66 | 70 | } |
| 67 | 71 | |
| 68 | 72 | toggleSpaceScroll(enable) { |
| 69 | − app.settings.set('spaceScroll', enable ? 1 : 0); | |
| 73 | + app.settings.set("spaceScroll", enable ? 1 : 0); | |
| 70 | 74 | } |
| 71 | 75 | |
| 72 | 76 | setScrollTimeout(value) { |
| 73 | − return app.settings.set('spaceTimeout', value); | |
| 77 | + return app.settings.set("spaceTimeout", value); | |
| 74 | 78 | } |
| 75 | 79 | |
| 76 | 80 | toggle(name, enable) { |
| @@ -78,31 +82,37 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View { · 1 unmodified line | ||
| 78 | 82 | } |
| 79 | 83 | |
| 80 | 84 | export() { |
| 81 | − const data = new Blob([JSON.stringify(app.settings.export())], {type: 'application/json'}); | |
| 82 | − const link = document.createElement('a'); | |
| 85 | + const data = new Blob([JSON.stringify(app.settings.export())], { | |
| 86 | + type: "application/json", | |
| 87 | + }); | |
| 88 | + const link = document.createElement("a"); | |
| 83 | 89 | link.href = URL.createObjectURL(data); |
| 84 | − link.download = 'devdocs.json'; | |
| 85 | − link.style.display = 'none'; | |
| 90 | + link.download = "devdocs.json"; | |
| 91 | + link.style.display = "none"; | |
| 86 | 92 | document.body.appendChild(link); |
| 87 | 93 | link.click(); |
| 88 | 94 | document.body.removeChild(link); |
| 89 | 95 | } |
| 90 | 96 | |
| 91 | 97 | import(file, input) { |
| 92 | − if (!file || (file.type !== 'application/json')) { | |
| 93 | − new app.views.Notif('ImportInvalid', {autoHide: false}); | |
| 98 | + if (!file || file.type !== "application/json") { | |
| 99 | + new app.views.Notif("ImportInvalid", { autoHide: false }); | |
| 94 | 100 | return; |
| 95 | 101 | } |
| 96 | 102 | |
| 97 | 103 | const reader = new FileReader(); |
| 98 | − reader.onloadend = function() { | |
| 99 | − const data = (() => { try { return JSON.parse(reader.result); } catch (error) {} })(); | |
| 100 | − if (!data || (data.constructor !== Object)) { | |
| 101 | − new app.views.Notif('ImportInvalid', {autoHide: false}); | |
| 104 | + reader.onloadend = function () { | |
| 105 | + const data = (() => { | |
| 106 | + try { | |
| 107 | + return JSON.parse(reader.result); | |
| 108 | + } catch (error) {} | |
| 109 | + })(); | |
| 110 | + if (!data || data.constructor !== Object) { | |
| 111 | + new app.views.Notif("ImportInvalid", { autoHide: false }); | |
| 102 | 112 | return; |
| 103 | 113 | } |
| 104 | 114 | app.settings.import(data); |
| 105 | − $.trigger(input.form, 'import'); | |
| 115 | + $.trigger(input.form, "import"); | |
| 106 | 116 | }; |
| 107 | 117 | reader.readAsText(file); |
| 108 | 118 | } |
| @@ -110,25 +120,25 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View { · 1 unmodified line | ||
| 110 | 120 | onChange(event) { |
| 111 | 121 | const input = event.target; |
| 112 | 122 | switch (input.name) { |
| 113 | − case 'theme': | |
| 123 | + case "theme": | |
| 114 | 124 | this.setTheme(input.value); |
| 115 | 125 | break; |
| 116 | − case 'layout': | |
| 126 | + case "layout": | |
| 117 | 127 | this.toggleLayout(input.value, input.checked); |
| 118 | 128 | break; |
| 119 | − case 'smoothScroll': | |
| 129 | + case "smoothScroll": | |
| 120 | 130 | this.toggleSmoothScroll(input.checked); |
| 121 | 131 | break; |
| 122 | − case 'import': | |
| 132 | + case "import": | |
| 123 | 133 | this.import(input.files[0], input); |
| 124 | 134 | break; |
| 125 | − case 'analyticsConsent': | |
| 135 | + case "analyticsConsent": | |
| 126 | 136 | this.toggleAnalyticsConsent(input.checked); |
| 127 | 137 | break; |
| 128 | − case 'spaceScroll': | |
| 138 | + case "spaceScroll": | |
| 129 | 139 | this.toggleSpaceScroll(input.checked); |
| 130 | 140 | break; |
| 131 | − case 'spaceTimeout': | |
| 141 | + case "spaceTimeout": | |
| 132 | 142 | this.setScrollTimeout(input.value); |
| 133 | 143 | break; |
| 134 | 144 | default: |
| @@ -138,8 +148,8 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View { · 3 unmodified lines | ||
| 138 | 148 | |
| 139 | 149 | onClick(event) { |
| 140 | 150 | const target = $.eventTarget(event); |
| 141 | − switch (target.getAttribute('data-action')) { | |
| 142 | − case 'export': | |
| 151 | + switch (target.getAttribute("data-action")) { | |
| 152 | + case "export": | |
| 143 | 153 | $.stopEvent(event); |
| 144 | 154 | this.export(); |
| 145 | 155 | break; |
| @@ -8,13 +8,13 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | const Cls = (app.views.StaticPage = class StaticPage extends app.View { |
| 10 | 10 | static initClass() { |
| 11 | − this.className = '_static'; | |
| 12 | − | |
| 11 | + this.className = "_static"; | |
| 12 | + | |
| 13 | 13 | this.titles = { |
| 14 | − about: 'About', | |
| 15 | − news: 'News', | |
| 16 | − help: 'User Guide', | |
| 17 | − notFound: '404' | |
| 14 | + about: "About", | |
| 15 | + news: "News", | |
| 16 | + help: "User Guide", | |
| 17 | + notFound: "404", | |
| 18 | 18 | }; |
| 19 | 19 | } |
| 20 | 20 | |
| @@ -35,7 +35,7 @@ const Cls = (app.views.StaticPage = class StaticPage extends app.View { · 14 unmodified lines | ||
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | onRoute(context) { |
| 38 | − this.render(context.page || 'notFound'); | |
| 38 | + this.render(context.page || "notFound"); | |
| 39 | 39 | } |
| 40 | 40 | }); |
| 41 | 41 | Cls.initClass(); |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | const Cls = (app.views.TypePage = class TypePage extends app.View { |
| 10 | 10 | static initClass() { |
| 11 | − this.className = '_page'; | |
| 11 | + this.className = "_page"; | |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | deactivate() { |
| @@ -20,7 +20,7 @@ const Cls = (app.views.TypePage = class TypePage extends app.View { · 5 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | render(type) { |
| 22 | 22 | this.type = type; |
| 23 | − this.html(this.tmpl('typePage', this.type)); | |
| 23 | + this.html(this.tmpl("typePage", this.type)); | |
| 24 | 24 | setFaviconForDoc(this.type.doc); |
| 25 | 25 | } |
| 26 | 26 | |
| @@ -17,41 +17,49 @@ const Cls = (app.views.Document = class Document extends app.View { · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | static initClass() { |
| 19 | 19 | this.el = document; |
| 20 | − | |
| 21 | − this.events = | |
| 22 | − {visibilitychange: 'onVisibilityChange'}; | |
| 23 | − | |
| 20 | + | |
| 21 | + this.events = { visibilitychange: "onVisibilityChange" }; | |
| 22 | + | |
| 24 | 23 | this.shortcuts = { |
| 25 | − help: 'onHelp', | |
| 26 | − preferences: 'onPreferences', | |
| 27 | − escape: 'onEscape', | |
| 28 | − superLeft: 'onBack', | |
| 29 | − superRight: 'onForward' | |
| 24 | + help: "onHelp", | |
| 25 | + preferences: "onPreferences", | |
| 26 | + escape: "onEscape", | |
| 27 | + superLeft: "onBack", | |
| 28 | + superRight: "onForward", | |
| 30 | 29 | }; |
| 31 | − | |
| 32 | − this.routes = | |
| 33 | − {after: 'afterRoute'}; | |
| 30 | + | |
| 31 | + this.routes = { after: "afterRoute" }; | |
| 34 | 32 | } |
| 35 | 33 | |
| 36 | 34 | init() { |
| 37 | − this.addSubview((this.menu = new app.views.Menu), | |
| 38 | − this.addSubview(this.sidebar = new app.views.Sidebar)); | |
| 39 | − if (app.views.Resizer.isSupported()) { this.addSubview(this.resizer = new app.views.Resizer); } | |
| 40 | − this.addSubview(this.content = new app.views.Content); | |
| 41 | − if (!app.isSingleDoc() && !app.isMobile()) { this.addSubview(this.path = new app.views.Path); } | |
| 42 | − if (!app.isSingleDoc()) { this.settings = new app.views.Settings; } | |
| 35 | + this.addSubview( | |
| 36 | + (this.menu = new app.views.Menu()), | |
| 37 | + this.addSubview((this.sidebar = new app.views.Sidebar())), | |
| 38 | + ); | |
| 39 | + if (app.views.Resizer.isSupported()) { | |
| 40 | + this.addSubview((this.resizer = new app.views.Resizer())); | |
| 41 | + } | |
| 42 | + this.addSubview((this.content = new app.views.Content())); | |
| 43 | + if (!app.isSingleDoc() && !app.isMobile()) { | |
| 44 | + this.addSubview((this.path = new app.views.Path())); | |
| 45 | + } | |
| 46 | + if (!app.isSingleDoc()) { | |
| 47 | + this.settings = new app.views.Settings(); | |
| 48 | + } | |
| 43 | 49 | |
| 44 | − $.on(document.body, 'click', this.onClick); | |
| 50 | + $.on(document.body, "click", this.onClick); | |
| 45 | 51 | |
| 46 | 52 | this.activate(); |
| 47 | 53 | } |
| 48 | 54 | |
| 49 | 55 | setTitle(title) { |
| 50 | − return this.el.title = title ? `${title} — DevDocs` : 'DevDocs API Documentation'; | |
| 56 | + return (this.el.title = title | |
| 57 | + ? `${title} — DevDocs` | |
| 58 | + : "DevDocs API Documentation"); | |
| 51 | 59 | } |
| 52 | 60 | |
| 53 | 61 | afterRoute(route) { |
| 54 | − if (route === 'settings') { | |
| 62 | + if (route === "settings") { | |
| 55 | 63 | if (this.settings != null) { |
| 56 | 64 | this.settings.activate(); |
| 57 | 65 | } |
| @@ -63,26 +71,29 @@ const Cls = (app.views.Document = class Document extends app.View { · 5 unmodified lines | ||
| 63 | 71 | } |
| 64 | 72 | |
| 65 | 73 | onVisibilityChange() { |
| 66 | − if (this.el.visibilityState !== 'visible') { return; } | |
| 67 | − this.delay(function() { | |
| 68 | − if (app.isMobile() !== app.views.Mobile.detect()) { location.reload(); } | |
| 74 | + if (this.el.visibilityState !== "visible") { | |
| 75 | + return; | |
| 69 | 76 | } |
| 70 | − , 300); | |
| 77 | + this.delay(function () { | |
| 78 | + if (app.isMobile() !== app.views.Mobile.detect()) { | |
| 79 | + location.reload(); | |
| 80 | + } | |
| 81 | + }, 300); | |
| 71 | 82 | } |
| 72 | 83 | |
| 73 | 84 | onHelp() { |
| 74 | − app.router.show('/help#shortcuts'); | |
| 85 | + app.router.show("/help#shortcuts"); | |
| 75 | 86 | } |
| 76 | 87 | |
| 77 | 88 | onPreferences() { |
| 78 | − app.router.show('/settings'); | |
| 89 | + app.router.show("/settings"); | |
| 79 | 90 | } |
| 80 | 91 | |
| 81 | 92 | onEscape() { |
| 82 | − const path = !app.isSingleDoc() || (location.pathname === app.doc.fullPath()) ? | |
| 83 | − '/' | |
| 84 | − : | |
| 85 | − app.doc.fullPath(); | |
| 93 | + const path = | |
| 94 | + !app.isSingleDoc() || location.pathname === app.doc.fullPath() | |
| 95 | + ? "/" | |
| 96 | + : app.doc.fullPath(); | |
| 86 | 97 | |
| 87 | 98 | app.router.show(path); |
| 88 | 99 | } |
| @@ -97,16 +108,34 @@ const Cls = (app.views.Document = class Document extends app.View { · 8 unmodified lines | ||
| 97 | 108 | |
| 98 | 109 | onClick(event) { |
| 99 | 110 | const target = $.eventTarget(event); |
| 100 | − if (!target.hasAttribute('data-behavior')) { return; } | |
| 111 | + if (!target.hasAttribute("data-behavior")) { | |
| 112 | + return; | |
| 113 | + } | |
| 101 | 114 | $.stopEvent(event); |
| 102 | − switch (target.getAttribute('data-behavior')) { | |
| 103 | − case 'back': history.back(); break; | |
| 104 | − case 'reload': window.location.reload(); break; | |
| 105 | − case 'reboot': app.reboot(); break; | |
| 106 | − case 'hard-reload': app.reload(); break; | |
| 107 | − case 'reset': if (confirm('Are you sure you want to reset DevDocs?')) { app.reset(); } break; | |
| 108 | − case 'accept-analytics': Cookies.set('analyticsConsent', '1', {expires: 1e8}) && app.reboot(); break; | |
| 109 | − case 'decline-analytics': Cookies.set('analyticsConsent', '0', {expires: 1e8}) && app.reboot(); break; | |
| 115 | + switch (target.getAttribute("data-behavior")) { | |
| 116 | + case "back": | |
| 117 | + history.back(); | |
| 118 | + break; | |
| 119 | + case "reload": | |
| 120 | + window.location.reload(); | |
| 121 | + break; | |
| 122 | + case "reboot": | |
| 123 | + app.reboot(); | |
| 124 | + break; | |
| 125 | + case "hard-reload": | |
| 126 | + app.reload(); | |
| 127 | + break; | |
| 128 | + case "reset": | |
| 129 | + if (confirm("Are you sure you want to reset DevDocs?")) { | |
| 130 | + app.reset(); | |
| 131 | + } | |
| 132 | + break; | |
| 133 | + case "accept-analytics": | |
| 134 | + Cookies.set("analyticsConsent", "1", { expires: 1e8 }) && app.reboot(); | |
| 135 | + break; | |
| 136 | + case "decline-analytics": | |
| 137 | + Cookies.set("analyticsConsent", "0", { expires: 1e8 }) && app.reboot(); | |
| 138 | + break; | |
| 110 | 139 | } |
| 111 | 140 | } |
| 112 | 141 | }); |
| @@ -13,25 +13,32 @@ const Cls = (app.views.Menu = class Menu extends app.View { · 12 unmodified lines | ||
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | static initClass() { |
| 16 | − this.el = '._menu'; | |
| 17 | − this.activeClass = 'active'; | |
| 18 | − | |
| 19 | − this.events = | |
| 20 | − {click: 'onClick'}; | |
| 16 | + this.el = "._menu"; | |
| 17 | + this.activeClass = "active"; | |
| 18 | + | |
| 19 | + this.events = { click: "onClick" }; | |
| 21 | 20 | } |
| 22 | 21 | |
| 23 | 22 | init() { |
| 24 | − $.on(document.body, 'click', this.onGlobalClick); | |
| 23 | + $.on(document.body, "click", this.onGlobalClick); | |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | onClick(event) { |
| 28 | 27 | const target = $.eventTarget(event); |
| 29 | − if (target.tagName === 'A') { target.blur(); } | |
| 28 | + if (target.tagName === "A") { | |
| 29 | + target.blur(); | |
| 30 | + } | |
| 30 | 31 | } |
| 31 | 32 | |
| 32 | 33 | onGlobalClick(event) { |
| 33 | − if (event.which !== 1) { return; } | |
| 34 | − if (typeof event.target.hasAttribute === 'function' ? event.target.hasAttribute('data-toggle-menu') : undefined) { | |
| 34 | + if (event.which !== 1) { | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + if ( | |
| 38 | + typeof event.target.hasAttribute === "function" | |
| 39 | + ? event.target.hasAttribute("data-toggle-menu") | |
| 40 | + : undefined | |
| 41 | + ) { | |
| 35 | 42 | this.toggleClass(this.constructor.activeClass); |
| 36 | 43 | } else if (this.hasClass(this.constructor.activeClass)) { |
| 37 | 44 | this.removeClass(this.constructor.activeClass); |
| @@ -10,34 +10,36 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | const Cls = (app.views.Mobile = class Mobile extends app.View { |
| 12 | 12 | static initClass() { |
| 13 | − this.className = '_mobile'; | |
| 14 | − | |
| 13 | + this.className = "_mobile"; | |
| 14 | + | |
| 15 | 15 | this.elements = { |
| 16 | − body: 'body', | |
| 17 | − content: '._container', | |
| 18 | − sidebar: '._sidebar', | |
| 19 | − docPicker: '._settings ._sidebar' | |
| 16 | + body: "body", | |
| 17 | + content: "._container", | |
| 18 | + sidebar: "._sidebar", | |
| 19 | + docPicker: "._settings ._sidebar", | |
| 20 | 20 | }; |
| 21 | − | |
| 22 | − this.shortcuts = | |
| 23 | − {escape: 'onEscape'}; | |
| 24 | − | |
| 25 | − this.routes = | |
| 26 | − {after: 'afterRoute'}; | |
| 21 | + | |
| 22 | + this.shortcuts = { escape: "onEscape" }; | |
| 23 | + | |
| 24 | + this.routes = { after: "afterRoute" }; | |
| 27 | 25 | } |
| 28 | 26 | |
| 29 | 27 | static detect() { |
| 30 | − if (Cookies.get('override-mobile-detect') != null) { | |
| 31 | − return JSON.parse(Cookies.get('override-mobile-detect')); | |
| 28 | + if (Cookies.get("override-mobile-detect") != null) { | |
| 29 | + return JSON.parse(Cookies.get("override-mobile-detect")); | |
| 32 | 30 | } |
| 33 | 31 | try { |
| 34 | − return (window.matchMedia('(max-width: 480px)').matches) || | |
| 35 | − (window.matchMedia('(max-width: 767px)').matches) || | |
| 36 | − (window.matchMedia('(max-height: 767px) and (max-width: 1024px)').matches) || | |
| 37 | − // Need to sniff the user agent because some Android and Windows Phone devices don't take | |
| 38 | − // resolution (dpi) into account when reporting device width/height. | |
| 39 | − ((navigator.userAgent.indexOf('Android') !== -1) && (navigator.userAgent.indexOf('Mobile') !== -1)) || | |
| 40 | − (navigator.userAgent.indexOf('IEMobile') !== -1); | |
| 32 | + return ( | |
| 33 | + window.matchMedia("(max-width: 480px)").matches || | |
| 34 | + window.matchMedia("(max-width: 767px)").matches || | |
| 35 | + window.matchMedia("(max-height: 767px) and (max-width: 1024px)") | |
| 36 | + .matches || | |
| 37 | + // Need to sniff the user agent because some Android and Windows Phone devices don't take | |
| 38 | + // resolution (dpi) into account when reporting device width/height. | |
| 39 | + (navigator.userAgent.indexOf("Android") !== -1 && | |
| 40 | + navigator.userAgent.indexOf("Mobile") !== -1) || | |
| 41 | + navigator.userAgent.indexOf("IEMobile") !== -1 | |
| 42 | + ); | |
| 41 | 43 | } catch (error) { |
| 42 | 44 | return false; |
| 43 | 45 | } |
| @@ -67,30 +69,29 @@ const Cls = (app.views.Mobile = class Mobile extends app.View { · 23 unmodified lines | ||
| 67 | 69 | } |
| 68 | 70 | |
| 69 | 71 | init() { |
| 70 | − $.on($('._search'), 'touchend', this.onTapSearch); | |
| 72 | + $.on($("._search"), "touchend", this.onTapSearch); | |
| 71 | 73 | |
| 72 | − this.toggleSidebar = $('button[data-toggle-sidebar]'); | |
| 73 | − this.toggleSidebar.removeAttribute('hidden'); | |
| 74 | − $.on(this.toggleSidebar, 'click', this.onClickToggleSidebar); | |
| 74 | + this.toggleSidebar = $("button[data-toggle-sidebar]"); | |
| 75 | + this.toggleSidebar.removeAttribute("hidden"); | |
| 76 | + $.on(this.toggleSidebar, "click", this.onClickToggleSidebar); | |
| 75 | 77 | |
| 76 | − this.back = $('button[data-back]'); | |
| 77 | − this.back.removeAttribute('hidden'); | |
| 78 | − $.on(this.back, 'click', this.onClickBack); | |
| 78 | + this.back = $("button[data-back]"); | |
| 79 | + this.back.removeAttribute("hidden"); | |
| 80 | + $.on(this.back, "click", this.onClickBack); | |
| 79 | 81 | |
| 80 | − this.forward = $('button[data-forward]'); | |
| 81 | − this.forward.removeAttribute('hidden'); | |
| 82 | − $.on(this.forward, 'click', this.onClickForward); | |
| 82 | + this.forward = $("button[data-forward]"); | |
| 83 | + this.forward.removeAttribute("hidden"); | |
| 84 | + $.on(this.forward, "click", this.onClickForward); | |
| 83 | 85 | |
| 84 | 86 | this.docPickerTab = $('button[data-tab="doc-picker"]'); |
| 85 | − this.docPickerTab.removeAttribute('hidden'); | |
| 86 | − $.on(this.docPickerTab, 'click', this.onClickDocPickerTab); | |
| 87 | + this.docPickerTab.removeAttribute("hidden"); | |
| 88 | + $.on(this.docPickerTab, "click", this.onClickDocPickerTab); | |
| 87 | 89 | |
| 88 | 90 | this.settingsTab = $('button[data-tab="settings"]'); |
| 89 | − this.settingsTab.removeAttribute('hidden'); | |
| 90 | − $.on(this.settingsTab, 'click', this.onClickSettingsTab); | |
| 91 | + this.settingsTab.removeAttribute("hidden"); | |
| 92 | + $.on(this.settingsTab, "click", this.onClickSettingsTab); | |
| 91 | 93 | |
| 92 | − app.document.sidebar.search | |
| 93 | − .on('searching', this.showSidebar); | |
| 94 | + app.document.sidebar.search.on("searching", this.showSidebar); | |
| 94 | 95 | |
| 95 | 96 | this.activate(); |
| 96 | 97 | } |
| @@ -103,27 +104,36 @@ const Cls = (app.views.Mobile = class Mobile extends app.View { · 6 unmodified lines | ||
| 103 | 104 | } |
| 104 | 105 | |
| 105 | 106 | this.contentTop = window.scrollY; |
| 106 | − this.content.style.display = 'none'; | |
| 107 | − this.sidebar.style.display = 'block'; | |
| 108 | − | |
| 109 | − if (selection = this.findByClass(app.views.ListSelect.activeClass)) { | |
| 110 | − const scrollContainer = window.scrollY === this.body.scrollTop ? this.body : document.documentElement; | |
| 111 | − $.scrollTo(selection, scrollContainer, 'center'); | |
| 107 | + this.content.style.display = "none"; | |
| 108 | + this.sidebar.style.display = "block"; | |
| 109 | + | |
| 110 | + if ((selection = this.findByClass(app.views.ListSelect.activeClass))) { | |
| 111 | + const scrollContainer = | |
| 112 | + window.scrollY === this.body.scrollTop | |
| 113 | + ? this.body | |
| 114 | + : document.documentElement; | |
| 115 | + $.scrollTo(selection, scrollContainer, "center"); | |
| 112 | 116 | } else { |
| 113 | − window.scrollTo(0, (this.findByClass(app.views.ListFold.activeClass) && this.sidebarTop) || 0); | |
| 117 | + window.scrollTo( | |
| 118 | + 0, | |
| 119 | + (this.findByClass(app.views.ListFold.activeClass) && this.sidebarTop) || | |
| 120 | + 0, | |
| 121 | + ); | |
| 114 | 122 | } |
| 115 | 123 | } |
| 116 | 124 | |
| 117 | 125 | hideSidebar() { |
| 118 | − if (!this.isSidebarShown()) { return; } | |
| 126 | + if (!this.isSidebarShown()) { | |
| 127 | + return; | |
| 128 | + } | |
| 119 | 129 | this.sidebarTop = window.scrollY; |
| 120 | − this.sidebar.style.display = 'none'; | |
| 121 | − this.content.style.display = 'block'; | |
| 130 | + this.sidebar.style.display = "none"; | |
| 131 | + this.content.style.display = "block"; | |
| 122 | 132 | window.scrollTo(0, this.contentTop || 0); |
| 123 | 133 | } |
| 124 | 134 | |
| 125 | 135 | isSidebarShown() { |
| 126 | − return this.sidebar.style.display !== 'none'; | |
| 136 | + return this.sidebar.style.display !== "none"; | |
| 127 | 137 | } |
| 128 | 138 | |
| 129 | 139 | onClickBack() { |
| @@ -135,7 +145,11 @@ const Cls = (app.views.Mobile = class Mobile extends app.View { · 5 unmodified lines | ||
| 135 | 145 | } |
| 136 | 146 | |
| 137 | 147 | onClickToggleSidebar() { |
| 138 | − if (this.isSidebarShown()) { this.hideSidebar(); } else { this.showSidebar(); } | |
| 148 | + if (this.isSidebarShown()) { | |
| 149 | + this.hideSidebar(); | |
| 150 | + } else { | |
| 151 | + this.showSidebar(); | |
| 152 | + } | |
| 139 | 153 | } |
| 140 | 154 | |
| 141 | 155 | onClickDocPickerTab(event) { |
| @@ -150,18 +164,18 @@ const Cls = (app.views.Mobile = class Mobile extends app.View { · 8 unmodified lines | ||
| 150 | 164 | |
| 151 | 165 | showDocPicker() { |
| 152 | 166 | window.scrollTo(0, 0); |
| 153 | − this.docPickerTab.classList.add('active'); | |
| 154 | − this.settingsTab.classList.remove('active'); | |
| 155 | − this.docPicker.style.display = 'block'; | |
| 156 | − this.content.style.display = 'none'; | |
| 167 | + this.docPickerTab.classList.add("active"); | |
| 168 | + this.settingsTab.classList.remove("active"); | |
| 169 | + this.docPicker.style.display = "block"; | |
| 170 | + this.content.style.display = "none"; | |
| 157 | 171 | } |
| 158 | 172 | |
| 159 | 173 | showSettings() { |
| 160 | 174 | window.scrollTo(0, 0); |
| 161 | − this.docPickerTab.classList.remove('active'); | |
| 162 | − this.settingsTab.classList.add('active'); | |
| 163 | − this.docPicker.style.display = 'none'; | |
| 164 | − this.content.style.display = 'block'; | |
| 175 | + this.docPickerTab.classList.remove("active"); | |
| 176 | + this.settingsTab.classList.add("active"); | |
| 177 | + this.docPicker.style.display = "none"; | |
| 178 | + this.content.style.display = "block"; | |
| 165 | 179 | } |
| 166 | 180 | |
| 167 | 181 | onTapSearch() { |
| @@ -175,22 +189,22 @@ const Cls = (app.views.Mobile = class Mobile extends app.View { · 7 unmodified lines | ||
| 175 | 189 | afterRoute(route) { |
| 176 | 190 | this.hideSidebar(); |
| 177 | 191 | |
| 178 | − if (route === 'settings') { | |
| 192 | + if (route === "settings") { | |
| 179 | 193 | this.showDocPicker(); |
| 180 | 194 | } else { |
| 181 | − this.content.style.display = 'block'; | |
| 195 | + this.content.style.display = "block"; | |
| 182 | 196 | } |
| 183 | 197 | |
| 184 | 198 | if (page.canGoBack()) { |
| 185 | − this.back.removeAttribute('disabled'); | |
| 199 | + this.back.removeAttribute("disabled"); | |
| 186 | 200 | } else { |
| 187 | − this.back.setAttribute('disabled', 'disabled'); | |
| 201 | + this.back.setAttribute("disabled", "disabled"); | |
| 188 | 202 | } |
| 189 | 203 | |
| 190 | 204 | if (page.canGoForward()) { |
| 191 | − this.forward.removeAttribute('disabled'); | |
| 205 | + this.forward.removeAttribute("disabled"); | |
| 192 | 206 | } else { |
| 193 | − this.forward.setAttribute('disabled', 'disabled'); | |
| 207 | + this.forward.setAttribute("disabled", "disabled"); | |
| 194 | 208 | } |
| 195 | 209 | } |
| 196 | 210 | }); |
| @@ -15,33 +15,36 @@ const Cls = (app.views.Path = class Path extends app.View { · 14 unmodified lines | ||
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | static initClass() { |
| 18 | − this.className = '_path'; | |
| 19 | − this.attributes = | |
| 20 | − {role: 'complementary'}; | |
| 21 | − | |
| 22 | − this.events = | |
| 23 | − {click: 'onClick'}; | |
| 24 | − | |
| 25 | − this.routes = | |
| 26 | − {after: 'afterRoute'}; | |
| 18 | + this.className = "_path"; | |
| 19 | + this.attributes = { role: "complementary" }; | |
| 20 | + | |
| 21 | + this.events = { click: "onClick" }; | |
| 22 | + | |
| 23 | + this.routes = { after: "afterRoute" }; | |
| 27 | 24 | } |
| 28 | 25 | |
| 29 | 26 | render(...args) { |
| 30 | − this.html(this.tmpl('path', ...Array.from(args))); | |
| 27 | + this.html(this.tmpl("path", ...Array.from(args))); | |
| 31 | 28 | this.show(); |
| 32 | 29 | } |
| 33 | 30 | |
| 34 | 31 | show() { |
| 35 | − if (!this.el.parentNode) { this.prependTo(app.el); } | |
| 32 | + if (!this.el.parentNode) { | |
| 33 | + this.prependTo(app.el); | |
| 34 | + } | |
| 36 | 35 | } |
| 37 | 36 | |
| 38 | 37 | hide() { |
| 39 | − if (this.el.parentNode) { $.remove(this.el); } | |
| 38 | + if (this.el.parentNode) { | |
| 39 | + $.remove(this.el); | |
| 40 | + } | |
| 40 | 41 | } |
| 41 | 42 | |
| 42 | 43 | onClick(event) { |
| 43 | 44 | let link; |
| 44 | − if (link = $.closestLink(event.target, this.el)) { this.clicked = true; } | |
| 45 | + if ((link = $.closestLink(event.target, this.el))) { | |
| 46 | + this.clicked = true; | |
| 47 | + } | |
| 45 | 48 | } |
| 46 | 49 | |
| 47 | 50 | afterRoute(route, context) { |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | * DS206: Consider reworking classes to avoid initClass |
| 8 | 8 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 9 | 9 | */ |
| 10 | −(function() { | |
| 10 | +(function () { | |
| 11 | 11 | let MIN = undefined; |
| 12 | 12 | let MAX = undefined; |
| 13 | 13 | const Cls = (app.views.Resizer = class Resizer extends app.View { |
| @@ -19,54 +19,66 @@ · 5 unmodified lines | ||
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | static initClass() { |
| 22 | − this.className = '_resizer'; | |
| 23 | − | |
| 22 | + this.className = "_resizer"; | |
| 23 | + | |
| 24 | 24 | this.events = { |
| 25 | − dragstart: 'onDragStart', | |
| 26 | − dragend: 'onDragEnd' | |
| 25 | + dragstart: "onDragStart", | |
| 26 | + dragend: "onDragEnd", | |
| 27 | 27 | }; |
| 28 | − | |
| 28 | + | |
| 29 | 29 | MIN = 260; |
| 30 | 30 | MAX = 600; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | static isSupported() { |
| 34 | − return 'ondragstart' in document.createElement('div') && !app.isMobile(); | |
| 34 | + return "ondragstart" in document.createElement("div") && !app.isMobile(); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | init() { |
| 38 | − this.el.setAttribute('draggable', 'true'); | |
| 39 | − this.appendTo($('._app')); | |
| 38 | + this.el.setAttribute("draggable", "true"); | |
| 39 | + this.appendTo($("._app")); | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | resize(value, save) { |
| 43 | 43 | value -= app.el.offsetLeft; |
| 44 | − if (!(value > 0)) { return; } | |
| 44 | + if (!(value > 0)) { | |
| 45 | + return; | |
| 46 | + } | |
| 45 | 47 | value = Math.min(Math.max(Math.round(value), MIN), MAX); |
| 46 | 48 | const newSize = `${value}px`; |
| 47 | − document.documentElement.style.setProperty('--sidebarWidth', newSize); | |
| 48 | − if (save) { app.settings.setSize(value); } | |
| 49 | + document.documentElement.style.setProperty("--sidebarWidth", newSize); | |
| 50 | + if (save) { | |
| 51 | + app.settings.setSize(value); | |
| 52 | + } | |
| 49 | 53 | } |
| 50 | 54 | |
| 51 | 55 | onDragStart(event) { |
| 52 | − event.dataTransfer.effectAllowed = 'link'; | |
| 53 | − event.dataTransfer.setData('Text', ''); | |
| 54 | − $.on(window, 'dragover', this.onDrag); | |
| 56 | + event.dataTransfer.effectAllowed = "link"; | |
| 57 | + event.dataTransfer.setData("Text", ""); | |
| 58 | + $.on(window, "dragover", this.onDrag); | |
| 55 | 59 | } |
| 56 | 60 | |
| 57 | 61 | onDrag(event) { |
| 58 | 62 | const value = event.pageX; |
| 59 | − if (!(value > 0)) { return; } | |
| 63 | + if (!(value > 0)) { | |
| 64 | + return; | |
| 65 | + } | |
| 60 | 66 | this.lastDragValue = value; |
| 61 | − if (this.lastDrag && (this.lastDrag > (Date.now() - 50))) { return; } | |
| 67 | + if (this.lastDrag && this.lastDrag > Date.now() - 50) { | |
| 68 | + return; | |
| 69 | + } | |
| 62 | 70 | this.lastDrag = Date.now(); |
| 63 | 71 | this.resize(value, false); |
| 64 | 72 | } |
| 65 | 73 | |
| 66 | 74 | onDragEnd(event) { |
| 67 | − $.off(window, 'dragover', this.onDrag); | |
| 68 | − let value = event.pageX || (event.screenX - window.screenX); | |
| 69 | − if (this.lastDragValue && !(this.lastDragValue - 5 < value && value < this.lastDragValue + 5)) { // https://github.com/freeCodeCamp/devdocs/issues/265 | |
| 75 | + $.off(window, "dragover", this.onDrag); | |
| 76 | + let value = event.pageX || event.screenX - window.screenX; | |
| 77 | + if ( | |
| 78 | + this.lastDragValue && | |
| 79 | + !(this.lastDragValue - 5 < value && value < this.lastDragValue + 5) | |
| 80 | + ) { | |
| 81 | + // https://github.com/freeCodeCamp/devdocs/issues/265 | |
| 70 | 82 | value = this.lastDragValue; |
| 71 | 83 | } |
| 72 | 84 | this.resize(value, true); |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | * DS207: Consider shorter variations of null checks |
| 11 | 11 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 12 | 12 | */ |
| 13 | −(function() { | |
| 13 | +(function () { | |
| 14 | 14 | let SIDEBAR_HIDDEN_LAYOUT = undefined; |
| 15 | 15 | const Cls = (app.views.Settings = class Settings extends app.View { |
| 16 | 16 | constructor(...args) { |
| @@ -23,29 +23,28 @@ · 6 unmodified lines | ||
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | static initClass() { |
| 26 | − SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'; | |
| 27 | − | |
| 28 | − this.el = '._settings'; | |
| 29 | − | |
| 26 | + SIDEBAR_HIDDEN_LAYOUT = "_sidebar-hidden"; | |
| 27 | + | |
| 28 | + this.el = "._settings"; | |
| 29 | + | |
| 30 | 30 | this.elements = { |
| 31 | − sidebar: '._sidebar', | |
| 31 | + sidebar: "._sidebar", | |
| 32 | 32 | saveBtn: 'button[type="submit"]', |
| 33 | − backBtn: 'button[data-back]' | |
| 33 | + backBtn: "button[data-back]", | |
| 34 | 34 | }; |
| 35 | − | |
| 35 | + | |
| 36 | 36 | this.events = { |
| 37 | − import: 'onImport', | |
| 38 | − change: 'onChange', | |
| 39 | − submit: 'onSubmit', | |
| 40 | − click: 'onClick' | |
| 37 | + import: "onImport", | |
| 38 | + change: "onChange", | |
| 39 | + submit: "onSubmit", | |
| 40 | + click: "onClick", | |
| 41 | 41 | }; |
| 42 | − | |
| 43 | − this.shortcuts = | |
| 44 | − {enter: 'onEnter'}; | |
| 42 | + | |
| 43 | + this.shortcuts = { enter: "onEnter" }; | |
| 45 | 44 | } |
| 46 | 45 | |
| 47 | 46 | init() { |
| 48 | − this.addSubview(this.docPicker = new app.views.DocPicker); | |
| 47 | + this.addSubview((this.docPicker = new app.views.DocPicker())); | |
| 49 | 48 | } |
| 50 | 49 | |
| 51 | 50 | activate() { |
| @@ -59,18 +58,22 @@ · 7 unmodified lines | ||
| 59 | 58 | if (super.deactivate(...arguments)) { |
| 60 | 59 | this.resetClass(); |
| 61 | 60 | this.docPicker.detach(); |
| 62 | − if (app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)) { document.body.classList.add(SIDEBAR_HIDDEN_LAYOUT); } | |
| 61 | + if (app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)) { | |
| 62 | + document.body.classList.add(SIDEBAR_HIDDEN_LAYOUT); | |
| 63 | + } | |
| 63 | 64 | } |
| 64 | 65 | } |
| 65 | 66 | |
| 66 | 67 | render() { |
| 67 | 68 | this.docPicker.appendTo(this.sidebar); |
| 68 | 69 | this.refreshElements(); |
| 69 | − this.addClass('_in'); | |
| 70 | + this.addClass("_in"); | |
| 70 | 71 | } |
| 71 | 72 | |
| 72 | 73 | save(options) { |
| 73 | − if (options == null) { options = {}; } | |
| 74 | + if (options == null) { | |
| 75 | + options = {}; | |
| 76 | + } | |
| 74 | 77 | if (!this.saving) { |
| 75 | 78 | let docs; |
| 76 | 79 | this.saving = true; |
| @@ -82,16 +85,19 @@ · 5 unmodified lines | ||
| 82 | 85 | app.settings.setDocs(docs); |
| 83 | 86 | } |
| 84 | 87 | |
| 85 | − this.saveBtn.textContent = 'Saving\u2026'; | |
| 86 | − const disabledDocs = new app.collections.Docs((() => { | |
| 87 | − const result = []; | |
| 88 | − for (var doc of Array.from(app.docs.all())) { if (docs.indexOf(doc.slug) === -1) { | |
| 89 | − result.push(doc); | |
| 88 | + this.saveBtn.textContent = "Saving\u2026"; | |
| 89 | + const disabledDocs = new app.collections.Docs( | |
| 90 | + (() => { | |
| 91 | + const result = []; | |
| 92 | + for (var doc of Array.from(app.docs.all())) { | |
| 93 | + if (docs.indexOf(doc.slug) === -1) { | |
| 94 | + result.push(doc); | |
| 95 | + } | |
| 90 | 96 | } |
| 91 | − } | |
| 92 | − return result; | |
| 93 | − })()); | |
| 94 | − disabledDocs.uninstall(function() { | |
| 97 | + return result; | |
| 98 | + })(), | |
| 99 | + ); | |
| 100 | + disabledDocs.uninstall(function () { | |
| 95 | 101 | app.db.migrate(); |
| 96 | 102 | return app.reload(); |
| 97 | 103 | }); |
| @@ -99,7 +105,7 @@ · 1 unmodified line | ||
| 99 | 105 | } |
| 100 | 106 | |
| 101 | 107 | onChange() { |
| 102 | − this.addClass('_dirty'); | |
| 108 | + this.addClass("_dirty"); | |
| 103 | 109 | } |
| 104 | 110 | |
| 105 | 111 | onEnter() { |
| @@ -112,15 +118,17 @@ · 6 unmodified lines | ||
| 112 | 118 | } |
| 113 | 119 | |
| 114 | 120 | onImport() { |
| 115 | − this.addClass('_dirty'); | |
| 116 | − this.save({import: true}); | |
| 121 | + this.addClass("_dirty"); | |
| 122 | + this.save({ import: true }); | |
| 117 | 123 | } |
| 118 | 124 | |
| 119 | 125 | onClick(event) { |
| 120 | − if (event.which !== 1) { return; } | |
| 126 | + if (event.which !== 1) { | |
| 127 | + return; | |
| 128 | + } | |
| 121 | 129 | if (event.target === this.backBtn) { |
| 122 | 130 | $.stopEvent(event); |
| 123 | − app.router.show('/'); | |
| 131 | + app.router.show("/"); | |
| 124 | 132 | } |
| 125 | 133 | } |
| 126 | 134 | }); |
| @@ -10,18 +10,17 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | const Cls = (app.views.ListFocus = class ListFocus extends app.View { |
| 12 | 12 | static initClass() { |
| 13 | − this.activeClass = 'focus'; | |
| 14 | − | |
| 15 | − this.events = | |
| 16 | − {click: 'onClick'}; | |
| 17 | − | |
| 13 | + this.activeClass = "focus"; | |
| 14 | + | |
| 15 | + this.events = { click: "onClick" }; | |
| 16 | + | |
| 18 | 17 | this.shortcuts = { |
| 19 | − up: 'onUp', | |
| 20 | − down: 'onDown', | |
| 21 | − left: 'onLeft', | |
| 22 | − enter: 'onEnter', | |
| 23 | − superEnter: 'onSuperEnter', | |
| 24 | − escape: 'blur' | |
| 18 | + up: "onUp", | |
| 19 | + down: "onDown", | |
| 20 | + left: "onLeft", | |
| 21 | + enter: "onEnter", | |
| 22 | + superEnter: "onSuperEnter", | |
| 23 | + escape: "blur", | |
| 25 | 24 | }; |
| 26 | 25 | } |
| 27 | 26 | |
| @@ -39,41 +38,51 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 11 unmodified lines | ||
| 39 | 38 | } |
| 40 | 39 | |
| 41 | 40 | focus(el, options) { |
| 42 | − if (options == null) { options = {}; } | |
| 41 | + if (options == null) { | |
| 42 | + options = {}; | |
| 43 | + } | |
| 43 | 44 | if (el && !el.classList.contains(this.constructor.activeClass)) { |
| 44 | 45 | this.blur(); |
| 45 | 46 | el.classList.add(this.constructor.activeClass); |
| 46 | − if (options.silent !== true) { $.trigger(el, 'focus'); } | |
| 47 | + if (options.silent !== true) { | |
| 48 | + $.trigger(el, "focus"); | |
| 49 | + } | |
| 47 | 50 | } |
| 48 | 51 | } |
| 49 | 52 | |
| 50 | 53 | blur() { |
| 51 | 54 | let cursor; |
| 52 | − if (cursor = this.getCursor()) { | |
| 55 | + if ((cursor = this.getCursor())) { | |
| 53 | 56 | cursor.classList.remove(this.constructor.activeClass); |
| 54 | − $.trigger(cursor, 'blur'); | |
| 57 | + $.trigger(cursor, "blur"); | |
| 55 | 58 | } |
| 56 | 59 | } |
| 57 | 60 | |
| 58 | 61 | getCursor() { |
| 59 | − return this.findByClass(this.constructor.activeClass) || this.findByClass(app.views.ListSelect.activeClass); | |
| 62 | + return ( | |
| 63 | + this.findByClass(this.constructor.activeClass) || | |
| 64 | + this.findByClass(app.views.ListSelect.activeClass) | |
| 65 | + ); | |
| 60 | 66 | } |
| 61 | 67 | |
| 62 | 68 | findNext(cursor) { |
| 63 | 69 | let next; |
| 64 | − if (next = cursor.nextSibling) { | |
| 65 | − if (next.tagName === 'A') { | |
| 70 | + if ((next = cursor.nextSibling)) { | |
| 71 | + if (next.tagName === "A") { | |
| 66 | 72 | return next; |
| 67 | − } else if (next.tagName === 'SPAN') { // pagination link | |
| 73 | + } else if (next.tagName === "SPAN") { | |
| 74 | + // pagination link | |
| 68 | 75 | $.click(next); |
| 69 | 76 | return this.findNext(cursor); |
| 70 | − } else if (next.tagName === 'DIV') { // sub-list | |
| 71 | − if (cursor.className.indexOf(' open') >= 0) { | |
| 77 | + } else if (next.tagName === "DIV") { | |
| 78 | + // sub-list | |
| 79 | + if (cursor.className.indexOf(" open") >= 0) { | |
| 72 | 80 | return this.findFirst(next) || this.findNext(next); |
| 73 | 81 | } else { |
| 74 | 82 | return this.findNext(next); |
| 75 | 83 | } |
| 76 | − } else if (next.tagName === 'H6') { // title | |
| 84 | + } else if (next.tagName === "H6") { | |
| 85 | + // title | |
| 77 | 86 | return this.findNext(next); |
| 78 | 87 | } |
| 79 | 88 | } else if (cursor.parentNode !== this.el) { |
| @@ -83,11 +92,14 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 3 unmodified lines | ||
| 83 | 92 | |
| 84 | 93 | findFirst(cursor) { |
| 85 | 94 | let first; |
| 86 | − if (!(first = cursor.firstChild)) { return; } | |
| 95 | + if (!(first = cursor.firstChild)) { | |
| 96 | + return; | |
| 97 | + } | |
| 87 | 98 | |
| 88 | − if (first.tagName === 'A') { | |
| 99 | + if (first.tagName === "A") { | |
| 89 | 100 | return first; |
| 90 | − } else if (first.tagName === 'SPAN') { // pagination link | |
| 101 | + } else if (first.tagName === "SPAN") { | |
| 102 | + // pagination link | |
| 91 | 103 | $.click(first); |
| 92 | 104 | return this.findFirst(cursor); |
| 93 | 105 | } |
| @@ -95,19 +107,22 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 1 unmodified line | ||
| 95 | 107 | |
| 96 | 108 | findPrev(cursor) { |
| 97 | 109 | let prev; |
| 98 | − if (prev = cursor.previousSibling) { | |
| 99 | − if (prev.tagName === 'A') { | |
| 110 | + if ((prev = cursor.previousSibling)) { | |
| 111 | + if (prev.tagName === "A") { | |
| 100 | 112 | return prev; |
| 101 | − } else if (prev.tagName === 'SPAN') { // pagination link | |
| 113 | + } else if (prev.tagName === "SPAN") { | |
| 114 | + // pagination link | |
| 102 | 115 | $.click(prev); |
| 103 | 116 | return this.findPrev(cursor); |
| 104 | − } else if (prev.tagName === 'DIV') { // sub-list | |
| 105 | − if (prev.previousSibling.className.indexOf('open') >= 0) { | |
| 117 | + } else if (prev.tagName === "DIV") { | |
| 118 | + // sub-list | |
| 119 | + if (prev.previousSibling.className.indexOf("open") >= 0) { | |
| 106 | 120 | return this.findLast(prev) || this.findPrev(prev); |
| 107 | 121 | } else { |
| 108 | 122 | return this.findPrev(prev); |
| 109 | 123 | } |
| 110 | − } else if (prev.tagName === 'H6') { // title | |
| 124 | + } else if (prev.tagName === "H6") { | |
| 125 | + // title | |
| 111 | 126 | return this.findPrev(prev); |
| 112 | 127 | } |
| 113 | 128 | } else if (cursor.parentNode !== this.el) { |
| @@ -117,13 +132,17 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 3 unmodified lines | ||
| 117 | 132 | |
| 118 | 133 | findLast(cursor) { |
| 119 | 134 | let last; |
| 120 | − if (!(last = cursor.lastChild)) { return; } | |
| 135 | + if (!(last = cursor.lastChild)) { | |
| 136 | + return; | |
| 137 | + } | |
| 121 | 138 | |
| 122 | − if (last.tagName === 'A') { | |
| 139 | + if (last.tagName === "A") { | |
| 123 | 140 | return last; |
| 124 | − } else if ((last.tagName === 'SPAN') || (last.tagName === 'H6')) { // pagination link or title | |
| 141 | + } else if (last.tagName === "SPAN" || last.tagName === "H6") { | |
| 142 | + // pagination link or title | |
| 125 | 143 | return this.findPrev(last); |
| 126 | − } else if (last.tagName === 'DIV') { // sub-list | |
| 144 | + } else if (last.tagName === "DIV") { | |
| 145 | + // sub-list | |
| 127 | 146 | return this.findLast(last); |
| 128 | 147 | } |
| 129 | 148 | } |
| @@ -133,7 +152,7 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 3 unmodified lines | ||
| 133 | 152 | if ((cursor = this.getCursor())) { |
| 134 | 153 | this.focusOnNextFrame(this.findNext(cursor)); |
| 135 | 154 | } else { |
| 136 | − this.focusOnNextFrame(this.findByTag('a')); | |
| 155 | + this.focusOnNextFrame(this.findByTag("a")); | |
| 137 | 156 | } |
| 138 | 157 | } |
| 139 | 158 | |
| @@ -142,37 +161,45 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View { · 2 unmodified lines | ||
| 142 | 161 | if ((cursor = this.getCursor())) { |
| 143 | 162 | this.focusOnNextFrame(this.findPrev(cursor)); |
| 144 | 163 | } else { |
| 145 | − this.focusOnNextFrame(this.findLastByTag('a')); | |
| 164 | + this.focusOnNextFrame(this.findLastByTag("a")); | |
| 146 | 165 | } |
| 147 | 166 | } |
| 148 | 167 | |
| 149 | 168 | onLeft() { |
| 150 | 169 | const cursor = this.getCursor(); |
| 151 | − if (cursor && !cursor.classList.contains(app.views.ListFold.activeClass) && (cursor.parentNode !== this.el)) { | |
| 170 | + if ( | |
| 171 | + cursor && | |
| 172 | + !cursor.classList.contains(app.views.ListFold.activeClass) && | |
| 173 | + cursor.parentNode !== this.el | |
| 174 | + ) { | |
| 152 | 175 | const prev = cursor.parentNode.previousSibling; |
| 153 | − if (prev && prev.classList.contains(app.views.ListFold.targetClass)) { this.focusOnNextFrame(cursor.parentNode.previousSibling); } | |
| 176 | + if (prev && prev.classList.contains(app.views.ListFold.targetClass)) { | |
| 177 | + this.focusOnNextFrame(cursor.parentNode.previousSibling); | |
| 178 | + } | |
| 154 | 179 | } |
| 155 | 180 | } |
| 156 | 181 | |
| 157 | 182 | onEnter() { |
| 158 | 183 | let cursor; |
| 159 | − if (cursor = this.getCursor()) { | |
| 184 | + if ((cursor = this.getCursor())) { | |
| 160 | 185 | $.click(cursor); |
| 161 | 186 | } |
| 162 | 187 | } |
| 163 | 188 | |
| 164 | 189 | onSuperEnter() { |
| 165 | 190 | let cursor; |
| 166 | − if (cursor = this.getCursor()) { | |
| 191 | + if ((cursor = this.getCursor())) { | |
| 167 | 192 | $.popup(cursor); |
| 168 | 193 | } |
| 169 | 194 | } |
| 170 | 195 | |
| 171 | 196 | onClick(event) { |
| 172 | − if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } | |
| 197 | + if (event.which !== 1 || event.metaKey || event.ctrlKey) { | |
| 198 | + return; | |
| 199 | + } | |
| 173 | 200 | const target = $.eventTarget(event); |
| 174 | − if (target.tagName === 'A') { | |
| 175 | − this.focus(target, {silent: true}); | |
| 201 | + if (target.tagName === "A") { | |
| 202 | + this.focus(target, { silent: true }); | |
| 176 | 203 | } |
| 177 | 204 | } |
| 178 | 205 | }); |
| @@ -10,32 +10,37 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | const Cls = (app.views.ListFold = class ListFold extends app.View { |
| 12 | 12 | static initClass() { |
| 13 | − this.targetClass = '_list-dir'; | |
| 14 | − this.handleClass = '_list-arrow'; | |
| 15 | − this.activeClass = 'open'; | |
| 16 | − | |
| 17 | − this.events = | |
| 18 | − {click: 'onClick'}; | |
| 19 | − | |
| 13 | + this.targetClass = "_list-dir"; | |
| 14 | + this.handleClass = "_list-arrow"; | |
| 15 | + this.activeClass = "open"; | |
| 16 | + | |
| 17 | + this.events = { click: "onClick" }; | |
| 18 | + | |
| 20 | 19 | this.shortcuts = { |
| 21 | − left: 'onLeft', | |
| 22 | − right: 'onRight' | |
| 20 | + left: "onLeft", | |
| 21 | + right: "onRight", | |
| 23 | 22 | }; |
| 24 | 23 | } |
| 25 | 24 | |
| 26 | − constructor(el) { this.onLeft = this.onLeft.bind(this); this.onRight = this.onRight.bind(this); this.onClick = this.onClick.bind(this); this.el = el; super(...arguments); } | |
| 25 | + constructor(el) { | |
| 26 | + this.onLeft = this.onLeft.bind(this); | |
| 27 | + this.onRight = this.onRight.bind(this); | |
| 28 | + this.onClick = this.onClick.bind(this); | |
| 29 | + this.el = el; | |
| 30 | + super(...arguments); | |
| 31 | + } | |
| 27 | 32 | |
| 28 | 33 | open(el) { |
| 29 | 34 | if (el && !el.classList.contains(this.constructor.activeClass)) { |
| 30 | 35 | el.classList.add(this.constructor.activeClass); |
| 31 | − $.trigger(el, 'open'); | |
| 36 | + $.trigger(el, "open"); | |
| 32 | 37 | } |
| 33 | 38 | } |
| 34 | 39 | |
| 35 | 40 | close(el) { |
| 36 | 41 | if (el && el.classList.contains(this.constructor.activeClass)) { |
| 37 | 42 | el.classList.remove(this.constructor.activeClass); |
| 38 | − $.trigger(el, 'close'); | |
| 43 | + $.trigger(el, "close"); | |
| 39 | 44 | } |
| 40 | 45 | } |
| 41 | 46 | |
| @@ -55,36 +60,55 @@ const Cls = (app.views.ListFold = class ListFold extends app.View { · 13 unmodified lines | ||
| 55 | 60 | } |
| 56 | 61 | |
| 57 | 62 | getCursor() { |
| 58 | − return this.findByClass(app.views.ListFocus.activeClass) || this.findByClass(app.views.ListSelect.activeClass); | |
| 63 | + return ( | |
| 64 | + this.findByClass(app.views.ListFocus.activeClass) || | |
| 65 | + this.findByClass(app.views.ListSelect.activeClass) | |
| 66 | + ); | |
| 59 | 67 | } |
| 60 | 68 | |
| 61 | 69 | onLeft() { |
| 62 | 70 | const cursor = this.getCursor(); |
| 63 | − if (cursor != null ? cursor.classList.contains(this.constructor.activeClass) : undefined) { | |
| 71 | + if ( | |
| 72 | + cursor != null | |
| 73 | + ? cursor.classList.contains(this.constructor.activeClass) | |
| 74 | + : undefined | |
| 75 | + ) { | |
| 64 | 76 | this.close(cursor); |
| 65 | 77 | } |
| 66 | 78 | } |
| 67 | 79 | |
| 68 | 80 | onRight() { |
| 69 | 81 | const cursor = this.getCursor(); |
| 70 | − if (cursor != null ? cursor.classList.contains(this.constructor.targetClass) : undefined) { | |
| 82 | + if ( | |
| 83 | + cursor != null | |
| 84 | + ? cursor.classList.contains(this.constructor.targetClass) | |
| 85 | + : undefined | |
| 86 | + ) { | |
| 71 | 87 | this.open(cursor); |
| 72 | 88 | } |
| 73 | 89 | } |
| 74 | 90 | |
| 75 | 91 | onClick(event) { |
| 76 | − if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } | |
| 77 | − if (!event.pageY) { return; } // ignore fabricated clicks | |
| 92 | + if (event.which !== 1 || event.metaKey || event.ctrlKey) { | |
| 93 | + return; | |
| 94 | + } | |
| 95 | + if (!event.pageY) { | |
| 96 | + return; | |
| 97 | + } // ignore fabricated clicks | |
| 78 | 98 | let el = $.eventTarget(event); |
| 79 | − if (el.parentNode.tagName.toUpperCase() === 'SVG') { el = el.parentNode; } | |
| 99 | + if (el.parentNode.tagName.toUpperCase() === "SVG") { | |
| 100 | + el = el.parentNode; | |
| 101 | + } | |
| 80 | 102 | |
| 81 | 103 | if (el.classList.contains(this.constructor.handleClass)) { |
| 82 | 104 | $.stopEvent(event); |
| 83 | 105 | this.toggle(el.parentNode); |
| 84 | 106 | } else if (el.classList.contains(this.constructor.targetClass)) { |
| 85 | − if (el.hasAttribute('href')) { | |
| 107 | + if (el.hasAttribute("href")) { | |
| 86 | 108 | if (el.classList.contains(this.constructor.activeClass)) { |
| 87 | − if (el.classList.contains(app.views.ListSelect.activeClass)) { this.close(el); } | |
| 109 | + if (el.classList.contains(app.views.ListSelect.activeClass)) { | |
| 110 | + this.close(el); | |
| 111 | + } | |
| 88 | 112 | } else { |
| 89 | 113 | this.open(el); |
| 90 | 114 | } |
| @@ -10,36 +10,43 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | const Cls = (app.views.ListSelect = class ListSelect extends app.View { |
| 12 | 12 | static initClass() { |
| 13 | − this.activeClass = 'active'; | |
| 14 | − | |
| 15 | − this.events = | |
| 16 | − {click: 'onClick'}; | |
| 13 | + this.activeClass = "active"; | |
| 14 | + | |
| 15 | + this.events = { click: "onClick" }; | |
| 17 | 16 | } |
| 18 | 17 | |
| 19 | − constructor(el) { this.onClick = this.onClick.bind(this); this.el = el; super(...arguments); } | |
| 18 | + constructor(el) { | |
| 19 | + this.onClick = this.onClick.bind(this); | |
| 20 | + this.el = el; | |
| 21 | + super(...arguments); | |
| 22 | + } | |
| 20 | 23 | |
| 21 | 24 | deactivate() { |
| 22 | − if (super.deactivate(...arguments)) { this.deselect(); } | |
| 25 | + if (super.deactivate(...arguments)) { | |
| 26 | + this.deselect(); | |
| 27 | + } | |
| 23 | 28 | } |
| 24 | 29 | |
| 25 | 30 | select(el) { |
| 26 | 31 | this.deselect(); |
| 27 | 32 | if (el) { |
| 28 | 33 | el.classList.add(this.constructor.activeClass); |
| 29 | − $.trigger(el, 'select'); | |
| 34 | + $.trigger(el, "select"); | |
| 30 | 35 | } |
| 31 | 36 | } |
| 32 | 37 | |
| 33 | 38 | deselect() { |
| 34 | 39 | let selection; |
| 35 | − if (selection = this.getSelection()) { | |
| 40 | + if ((selection = this.getSelection())) { | |
| 36 | 41 | selection.classList.remove(this.constructor.activeClass); |
| 37 | − $.trigger(selection, 'deselect'); | |
| 42 | + $.trigger(selection, "deselect"); | |
| 38 | 43 | } |
| 39 | 44 | } |
| 40 | 45 | |
| 41 | 46 | selectByHref(href) { |
| 42 | − if (__guard__(this.getSelection(), x => x.getAttribute('href')) !== href) { | |
| 47 | + if ( | |
| 48 | + __guard__(this.getSelection(), (x) => x.getAttribute("href")) !== href | |
| 49 | + ) { | |
| 43 | 50 | this.select(this.find(`a[href='${href}']`)); |
| 44 | 51 | } |
| 45 | 52 | } |
| @@ -53,9 +60,11 @@ const Cls = (app.views.ListSelect = class ListSelect extends app.View { · 7 unmodified lines | ||
| 53 | 60 | } |
| 54 | 61 | |
| 55 | 62 | onClick(event) { |
| 56 | − if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } | |
| 63 | + if (event.which !== 1 || event.metaKey || event.ctrlKey) { | |
| 64 | + return; | |
| 65 | + } | |
| 57 | 66 | const target = $.eventTarget(event); |
| 58 | − if (target.tagName === 'A') { | |
| 67 | + if (target.tagName === "A") { | |
| 59 | 68 | this.select(target); |
| 60 | 69 | } |
| 61 | 70 | } |
| @@ -63,5 +72,7 @@ const Cls = (app.views.ListSelect = class ListSelect extends app.View { · 1 unmodified line | ||
| 63 | 72 | Cls.initClass(); |
| 64 | 73 | |
| 65 | 74 | function __guard__(value, transform) { |
| 66 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 67 | −} | |
| 75 | + return typeof value !== "undefined" && value !== null | |
| 76 | + ? transform(value) | |
| 77 | + : undefined; | |
| 78 | +} | |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | * DS207: Consider shorter variations of null checks |
| 11 | 11 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 12 | 12 | */ |
| 13 | −(function() { | |
| 13 | +(function () { | |
| 14 | 14 | let PER_PAGE = undefined; |
| 15 | 15 | const Cls = (app.views.PaginatedList = class PaginatedList extends app.View { |
| 16 | 16 | static initClass() { |
| @@ -21,7 +21,12 @@ · 4 unmodified lines | ||
| 21 | 21 | let base; |
| 22 | 22 | this.onClick = this.onClick.bind(this); |
| 23 | 23 | this.data = data; |
| 24 | − if (((base = this.constructor.events || (this.constructor.events = {}))).click == null) { base.click = 'onClick'; } | |
| 24 | + if ( | |
| 25 | + (base = this.constructor.events || (this.constructor.events = {})) | |
| 26 | + .click == null | |
| 27 | + ) { | |
| 28 | + base.click = "onClick"; | |
| 29 | + } | |
| 25 | 30 | super(...arguments); |
| 26 | 31 | } |
| 27 | 32 | |
| @@ -42,11 +47,13 @@ · 14 unmodified lines | ||
| 42 | 47 | } |
| 43 | 48 | |
| 44 | 49 | renderPage(page) { |
| 45 | − return this.render(this.data.slice(((page - 1) * PER_PAGE), (page * PER_PAGE))); | |
| 50 | + return this.render( | |
| 51 | + this.data.slice((page - 1) * PER_PAGE, page * PER_PAGE), | |
| 52 | + ); | |
| 46 | 53 | } |
| 47 | 54 | |
| 48 | 55 | renderPageLink(count) { |
| 49 | − return this.tmpl('sidebarPageLink', count); | |
| 56 | + return this.tmpl("sidebarPageLink", count); | |
| 50 | 57 | } |
| 51 | 58 | |
| 52 | 59 | renderPrevLink(page) { |
| @@ -54,7 +61,7 @@ · 1 unmodified line | ||
| 54 | 61 | } |
| 55 | 62 | |
| 56 | 63 | renderNextLink(page) { |
| 57 | − return this.renderPageLink(this.data.length - (page * PER_PAGE)); | |
| 64 | + return this.renderPageLink(this.data.length - page * PER_PAGE); | |
| 58 | 65 | } |
| 59 | 66 | |
| 60 | 67 | totalPages() { |
| @@ -64,17 +71,27 @@ · 3 unmodified lines | ||
| 64 | 71 | paginate(link) { |
| 65 | 72 | $.lockScroll(link.nextSibling || link.previousSibling, () => { |
| 66 | 73 | $.batchUpdate(this.el, () => { |
| 67 | − if (link.nextSibling) { this.paginatePrev(link); } else { this.paginateNext(link); } | |
| 74 | + if (link.nextSibling) { | |
| 75 | + this.paginatePrev(link); | |
| 76 | + } else { | |
| 77 | + this.paginateNext(link); | |
| 78 | + } | |
| 68 | 79 | }); |
| 69 | 80 | }); |
| 70 | 81 | } |
| 71 | 82 | |
| 72 | 83 | paginateNext() { |
| 73 | − if (this.el.lastChild) { this.remove(this.el.lastChild); } // remove link | |
| 74 | − if (this.page >= 2) { this.hideTopPage(); } // keep previous page into view | |
| 84 | + if (this.el.lastChild) { | |
| 85 | + this.remove(this.el.lastChild); | |
| 86 | + } // remove link | |
| 87 | + if (this.page >= 2) { | |
| 88 | + this.hideTopPage(); | |
| 89 | + } // keep previous page into view | |
| 75 | 90 | this.page++; |
| 76 | 91 | this.append(this.renderPage(this.page)); |
| 77 | − if (this.page < this.totalPages()) { this.append(this.renderNextLink(this.page)); } | |
| 92 | + if (this.page < this.totalPages()) { | |
| 93 | + this.append(this.renderNextLink(this.page)); | |
| 94 | + } | |
| 78 | 95 | } |
| 79 | 96 | |
| 80 | 97 | paginatePrev() { |
| @@ -82,37 +99,55 @@ · 1 unmodified line | ||
| 82 | 99 | this.hideBottomPage(); |
| 83 | 100 | this.page--; |
| 84 | 101 | this.prepend(this.renderPage(this.page - 1)); // previous page is offset by one |
| 85 | − if (this.page >= 3) { this.prepend(this.renderPrevLink(this.page - 1)); } | |
| 102 | + if (this.page >= 3) { | |
| 103 | + this.prepend(this.renderPrevLink(this.page - 1)); | |
| 104 | + } | |
| 86 | 105 | } |
| 87 | 106 | |
| 88 | 107 | paginateTo(object) { |
| 89 | 108 | const index = this.data.indexOf(object); |
| 90 | 109 | if (index >= PER_PAGE) { |
| 91 | − for (let i = 0, end = Math.floor(index / PER_PAGE), asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.paginateNext(); } | |
| 110 | + for ( | |
| 111 | + let i = 0, end = Math.floor(index / PER_PAGE), asc = 0 <= end; | |
| 112 | + asc ? i < end : i > end; | |
| 113 | + asc ? i++ : i-- | |
| 114 | + ) { | |
| 115 | + this.paginateNext(); | |
| 116 | + } | |
| 92 | 117 | } |
| 93 | 118 | } |
| 94 | 119 | |
| 95 | 120 | hideTopPage() { |
| 96 | − const n = this.page <= 2 ? | |
| 97 | − PER_PAGE | |
| 98 | − : | |
| 99 | − PER_PAGE + 1; // remove link | |
| 100 | − for (let i = 0, end = n, asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.remove(this.el.firstChild); } | |
| 121 | + const n = this.page <= 2 ? PER_PAGE : PER_PAGE + 1; // remove link | |
| 122 | + for ( | |
| 123 | + let i = 0, end = n, asc = 0 <= end; | |
| 124 | + asc ? i < end : i > end; | |
| 125 | + asc ? i++ : i-- | |
| 126 | + ) { | |
| 127 | + this.remove(this.el.firstChild); | |
| 128 | + } | |
| 101 | 129 | this.prepend(this.renderPrevLink(this.page)); |
| 102 | 130 | } |
| 103 | 131 | |
| 104 | 132 | hideBottomPage() { |
| 105 | − const n = this.page === this.totalPages() ? | |
| 106 | − (this.data.length % PER_PAGE) || PER_PAGE | |
| 107 | − : | |
| 108 | − PER_PAGE + 1; // remove link | |
| 109 | − for (let i = 0, end = n, asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.remove(this.el.lastChild); } | |
| 133 | + const n = | |
| 134 | + this.page === this.totalPages() | |
| 135 | + ? this.data.length % PER_PAGE || PER_PAGE | |
| 136 | + : PER_PAGE + 1; // remove link | |
| 137 | + for ( | |
| 138 | + let i = 0, end = n, asc = 0 <= end; | |
| 139 | + asc ? i < end : i > end; | |
| 140 | + asc ? i++ : i-- | |
| 141 | + ) { | |
| 142 | + this.remove(this.el.lastChild); | |
| 143 | + } | |
| 110 | 144 | this.append(this.renderNextLink(this.page - 1)); |
| 111 | 145 | } |
| 112 | 146 | |
| 113 | 147 | onClick(event) { |
| 114 | 148 | const target = $.eventTarget(event); |
| 115 | − if (target.tagName === 'SPAN') { // link | |
| 149 | + if (target.tagName === "SPAN") { | |
| 150 | + // link | |
| 116 | 151 | $.stopEvent(event); |
| 117 | 152 | this.paginate(target); |
| 118 | 153 | } |
| @@ -12,15 +12,16 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | const Cls = (app.views.News = class News extends app.views.Notif { |
| 14 | 14 | static initClass() { |
| 15 | − this.className += ' _notif-news'; | |
| 16 | − | |
| 17 | − this.defautOptions = | |
| 18 | − {autoHide: 30000}; | |
| 15 | + this.className += " _notif-news"; | |
| 16 | + | |
| 17 | + this.defautOptions = { autoHide: 30000 }; | |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | 20 | init() { |
| 22 | 21 | this.unreadNews = this.getUnreadNews(); |
| 23 | − if (this.unreadNews.length) { this.show(); } | |
| 22 | + if (this.unreadNews.length) { | |
| 23 | + this.show(); | |
| 24 | + } | |
| 24 | 25 | this.markAllAsRead(); |
| 25 | 26 | } |
| 26 | 27 | |
| @@ -30,12 +31,16 @@ const Cls = (app.views.News = class News extends app.views.Notif { · 3 unmodified lines | ||
| 30 | 31 | |
| 31 | 32 | getUnreadNews() { |
| 32 | 33 | let time; |
| 33 | − if (!(time = this.getLastReadTime())) { return []; } | |
| 34 | + if (!(time = this.getLastReadTime())) { | |
| 35 | + return []; | |
| 36 | + } | |
| 34 | 37 | |
| 35 | 38 | return (() => { |
| 36 | 39 | const result = []; |
| 37 | 40 | for (var news of Array.from(app.news)) { |
| 38 | − if (new Date(news[0]).getTime() <= time) { break; } | |
| 41 | + if (new Date(news[0]).getTime() <= time) { | |
| 42 | + break; | |
| 43 | + } | |
| 39 | 44 | result.push(news); |
| 40 | 45 | } |
| 41 | 46 | return result; |
| @@ -47,11 +52,11 @@ const Cls = (app.views.News = class News extends app.views.Notif { · 5 unmodified lines | ||
| 47 | 52 | } |
| 48 | 53 | |
| 49 | 54 | getLastReadTime() { |
| 50 | − return app.settings.get('news'); | |
| 55 | + return app.settings.get("news"); | |
| 51 | 56 | } |
| 52 | 57 | |
| 53 | 58 | markAllAsRead() { |
| 54 | − app.settings.set('news', this.getLastNewsTime()); | |
| 59 | + app.settings.set("news", this.getLastNewsTime()); | |
| 55 | 60 | } |
| 56 | 61 | }); |
| 57 | 62 | Cls.initClass(); |
| @@ -9,23 +9,30 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | const Cls = (app.views.Notice = class Notice extends app.View { |
| 11 | 11 | static initClass() { |
| 12 | − this.className = '_notice'; | |
| 13 | − this.attributes = | |
| 14 | − {role: 'alert'}; | |
| 12 | + this.className = "_notice"; | |
| 13 | + this.attributes = { role: "alert" }; | |
| 15 | 14 | } |
| 16 | 15 | |
| 17 | − constructor(type, ...rest) { this.type = type; [...this.args] = Array.from(rest); super(...arguments); } | |
| 16 | + constructor(type, ...rest) { | |
| 17 | + this.type = type; | |
| 18 | + [...this.args] = Array.from(rest); | |
| 19 | + super(...arguments); | |
| 20 | + } | |
| 18 | 21 | |
| 19 | 22 | init() { |
| 20 | 23 | this.activate(); |
| 21 | 24 | } |
| 22 | 25 | |
| 23 | 26 | activate() { |
| 24 | − if (super.activate(...arguments)) { this.show(); } | |
| 27 | + if (super.activate(...arguments)) { | |
| 28 | + this.show(); | |
| 29 | + } | |
| 25 | 30 | } |
| 26 | 31 | |
| 27 | 32 | deactivate() { |
| 28 | − if (super.deactivate(...arguments)) { this.hide(); } | |
| 33 | + if (super.deactivate(...arguments)) { | |
| 34 | + this.hide(); | |
| 35 | + } | |
| 29 | 36 | } |
| 30 | 37 | |
| 31 | 38 | show() { |
| @@ -9,22 +9,21 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | const Cls = (app.views.Notif = class Notif extends app.View { |
| 11 | 11 | static initClass() { |
| 12 | − this.className = '_notif'; | |
| 13 | − this.activeClass = '_in'; | |
| 14 | − this.attributes = | |
| 15 | − {role: 'alert'}; | |
| 16 | − | |
| 17 | − this.defautOptions = | |
| 18 | − {autoHide: 15000}; | |
| 19 | − | |
| 20 | − this.events = | |
| 21 | − {click: 'onClick'}; | |
| 12 | + this.className = "_notif"; | |
| 13 | + this.activeClass = "_in"; | |
| 14 | + this.attributes = { role: "alert" }; | |
| 15 | + | |
| 16 | + this.defautOptions = { autoHide: 15000 }; | |
| 17 | + | |
| 18 | + this.events = { click: "onClick" }; | |
| 22 | 19 | } |
| 23 | 20 | |
| 24 | 21 | constructor(type, options) { |
| 25 | 22 | this.onClick = this.onClick.bind(this); |
| 26 | 23 | this.type = type; |
| 27 | − if (options == null) { options = {}; } | |
| 24 | + if (options == null) { | |
| 25 | + options = {}; | |
| 26 | + } | |
| 28 | 27 | this.options = options; |
| 29 | 28 | this.options = $.extend({}, this.constructor.defautOptions, this.options); |
| 30 | 29 | super(...arguments); |
| @@ -45,7 +44,9 @@ const Cls = (app.views.Notif = class Notif extends app.View { · 14 unmodified lines | ||
| 45 | 44 | this.appendTo(document.body); |
| 46 | 45 | this.el.offsetWidth; // force reflow |
| 47 | 46 | this.addClass(this.constructor.activeClass); |
| 48 | − if (this.options.autoHide) { this.timeout = this.delay(this.hide, this.options.autoHide); } | |
| 47 | + if (this.options.autoHide) { | |
| 48 | + this.timeout = this.delay(this.hide, this.options.autoHide); | |
| 49 | + } | |
| 49 | 50 | } |
| 50 | 51 | } |
| 51 | 52 | |
| @@ -63,15 +64,20 @@ const Cls = (app.views.Notif = class Notif extends app.View { · 11 unmodified lines | ||
| 63 | 64 | const notifications = $$(`.${app.views.Notif.className}`); |
| 64 | 65 | if (notifications.length) { |
| 65 | 66 | const lastNotif = notifications[notifications.length - 1]; |
| 66 | − this.el.style.top = lastNotif.offsetTop + lastNotif.offsetHeight + 16 + 'px'; | |
| 67 | + this.el.style.top = | |
| 68 | + lastNotif.offsetTop + lastNotif.offsetHeight + 16 + "px"; | |
| 67 | 69 | } |
| 68 | 70 | } |
| 69 | 71 | |
| 70 | 72 | onClick(event) { |
| 71 | − if (event.which !== 1) { return; } | |
| 73 | + if (event.which !== 1) { | |
| 74 | + return; | |
| 75 | + } | |
| 72 | 76 | const target = $.eventTarget(event); |
| 73 | − if (target.hasAttribute('data-behavior')) { return; } | |
| 74 | − if ((target.tagName !== 'A') || target.classList.contains('_notif-close')) { | |
| 77 | + if (target.hasAttribute("data-behavior")) { | |
| 78 | + return; | |
| 79 | + } | |
| 80 | + if (target.tagName !== "A" || target.classList.contains("_notif-close")) { | |
| 75 | 81 | $.stopEvent(event); |
| 76 | 82 | this.hide(); |
| 77 | 83 | } |
| @@ -9,10 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | const Cls = (app.views.Tip = class Tip extends app.views.Notif { |
| 11 | 11 | static initClass() { |
| 12 | − this.className = '_notif _notif-tip'; | |
| 13 | − | |
| 14 | − this.defautOptions = | |
| 15 | − {autoHide: false}; | |
| 12 | + this.className = "_notif _notif-tip"; | |
| 13 | + | |
| 14 | + this.defautOptions = { autoHide: false }; | |
| 16 | 15 | } |
| 17 | 16 | |
| 18 | 17 | render() { |
| @@ -12,34 +12,47 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | const Cls = (app.views.Updates = class Updates extends app.views.Notif { |
| 14 | 14 | static initClass() { |
| 15 | − this.className += ' _notif-news'; | |
| 16 | − | |
| 17 | − this.defautOptions = | |
| 18 | − {autoHide: 30000}; | |
| 15 | + this.className += " _notif-news"; | |
| 16 | + | |
| 17 | + this.defautOptions = { autoHide: 30000 }; | |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | 20 | init() { |
| 22 | 21 | this.lastUpdateTime = this.getLastUpdateTime(); |
| 23 | 22 | this.updatedDocs = this.getUpdatedDocs(); |
| 24 | 23 | this.updatedDisabledDocs = this.getUpdatedDisabledDocs(); |
| 25 | − if ((this.updatedDocs.length > 0) || (this.updatedDisabledDocs.length > 0)) { this.show(); } | |
| 24 | + if (this.updatedDocs.length > 0 || this.updatedDisabledDocs.length > 0) { | |
| 25 | + this.show(); | |
| 26 | + } | |
| 26 | 27 | this.markAllAsRead(); |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | 30 | render() { |
| 30 | − this.html(app.templates.notifUpdates(this.updatedDocs, this.updatedDisabledDocs)); | |
| 31 | + this.html( | |
| 32 | + app.templates.notifUpdates(this.updatedDocs, this.updatedDisabledDocs), | |
| 33 | + ); | |
| 31 | 34 | } |
| 32 | 35 | |
| 33 | 36 | getUpdatedDocs() { |
| 34 | − if (!this.lastUpdateTime) { return []; } | |
| 35 | − return Array.from(app.docs.all()).filter((doc) => doc.mtime > this.lastUpdateTime); | |
| 37 | + if (!this.lastUpdateTime) { | |
| 38 | + return []; | |
| 39 | + } | |
| 40 | + return Array.from(app.docs.all()).filter( | |
| 41 | + (doc) => doc.mtime > this.lastUpdateTime, | |
| 42 | + ); | |
| 36 | 43 | } |
| 37 | 44 | |
| 38 | 45 | getUpdatedDisabledDocs() { |
| 39 | − if (!this.lastUpdateTime) { return []; } | |
| 46 | + if (!this.lastUpdateTime) { | |
| 47 | + return []; | |
| 48 | + } | |
| 40 | 49 | return (() => { |
| 41 | 50 | const result = []; |
| 42 | − for (var doc of Array.from(app.disabledDocs.all())) { if ((doc.mtime > this.lastUpdateTime) && app.docs.findBy('slug_without_version', doc.slug_without_version)) { | |
| 51 | + for (var doc of Array.from(app.disabledDocs.all())) { | |
| 52 | + if ( | |
| 53 | + doc.mtime > this.lastUpdateTime && | |
| 54 | + app.docs.findBy("slug_without_version", doc.slug_without_version) | |
| 55 | + ) { | |
| 43 | 56 | result.push(doc); |
| 44 | 57 | } |
| 45 | 58 | } |
| @@ -48,11 +61,16 @@ const Cls = (app.views.Updates = class Updates extends app.views.Notif { · 2 unmodified lines | ||
| 48 | 61 | } |
| 49 | 62 | |
| 50 | 63 | getLastUpdateTime() { |
| 51 | − return app.settings.get('version'); | |
| 64 | + return app.settings.get("version"); | |
| 52 | 65 | } |
| 53 | 66 | |
| 54 | 67 | markAllAsRead() { |
| 55 | − app.settings.set('version', app.config.env === 'production' ? app.config.version : Math.floor(Date.now() / 1000)); | |
| 68 | + app.settings.set( | |
| 69 | + "version", | |
| 70 | + app.config.env === "production" | |
| 71 | + ? app.config.version | |
| 72 | + : Math.floor(Date.now() / 1000), | |
| 73 | + ); | |
| 56 | 74 | } |
| 57 | 75 | }); |
| 58 | 76 | Cls.initClass(); |
| @@ -9,31 +9,44 @@ · 8 unmodified lines | ||
| 9 | 9 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 10 | 10 | */ |
| 11 | 11 | app.views.BasePage = class BasePage extends app.View { |
| 12 | − constructor(el, entry) { this.paintCode = this.paintCode.bind(this); this.el = el; this.entry = entry; super(...arguments); } | |
| 12 | + constructor(el, entry) { | |
| 13 | + this.paintCode = this.paintCode.bind(this); | |
| 14 | + this.el = el; | |
| 15 | + this.entry = entry; | |
| 16 | + super(...arguments); | |
| 17 | + } | |
| 13 | 18 | |
| 14 | 19 | deactivate() { |
| 15 | 20 | if (super.deactivate(...arguments)) { |
| 16 | − return this.highlightNodes = []; | |
| 21 | + return (this.highlightNodes = []); | |
| 17 | 22 | } |
| 18 | 23 | } |
| 19 | 24 | |
| 20 | 25 | render(content, fromCache) { |
| 21 | − if (fromCache == null) { fromCache = false; } | |
| 26 | + if (fromCache == null) { | |
| 27 | + fromCache = false; | |
| 28 | + } | |
| 22 | 29 | this.highlightNodes = []; |
| 23 | 30 | this.previousTiming = null; |
| 24 | − if (!this.constructor.className) { this.addClass(`_${this.entry.doc.type}`); } | |
| 31 | + if (!this.constructor.className) { | |
| 32 | + this.addClass(`_${this.entry.doc.type}`); | |
| 33 | + } | |
| 25 | 34 | this.html(content); |
| 26 | − if (!fromCache) { this.highlightCode(); } | |
| 35 | + if (!fromCache) { | |
| 36 | + this.highlightCode(); | |
| 37 | + } | |
| 27 | 38 | this.activate(); |
| 28 | − if (this.afterRender) { this.delay(this.afterRender); } | |
| 39 | + if (this.afterRender) { | |
| 40 | + this.delay(this.afterRender); | |
| 41 | + } | |
| 29 | 42 | if (this.highlightNodes.length > 0) { |
| 30 | 43 | $.requestAnimationFrame(() => $.requestAnimationFrame(this.paintCode)); |
| 31 | 44 | } |
| 32 | 45 | } |
| 33 | 46 | |
| 34 | 47 | highlightCode() { |
| 35 | − for (var el of Array.from(this.findAll('pre[data-language]'))) { | |
| 36 | − var language = el.getAttribute('data-language'); | |
| 48 | + for (var el of Array.from(this.findAll("pre[data-language]"))) { | |
| 49 | + var language = el.getAttribute("data-language"); | |
| 37 | 50 | el.classList.add(`language-${language}`); |
| 38 | 51 | this.highlightNodes.push(el); |
| 39 | 52 | } |
| @@ -41,23 +54,34 @@ app.views.BasePage = class BasePage extends app.View { · 1 unmodified line | ||
| 41 | 54 | |
| 42 | 55 | paintCode(timing) { |
| 43 | 56 | if (this.previousTiming) { |
| 44 | − if (Math.round(1000 / (timing - this.previousTiming)) > 50) { // fps | |
| 45 | − this.nodesPerFrame = Math.round(Math.min(this.nodesPerFrame * 1.25, 50)); | |
| 57 | + if (Math.round(1000 / (timing - this.previousTiming)) > 50) { | |
| 58 | + // fps | |
| 59 | + this.nodesPerFrame = Math.round( | |
| 60 | + Math.min(this.nodesPerFrame * 1.25, 50), | |
| 61 | + ); | |
| 46 | 62 | } else { |
| 47 | − this.nodesPerFrame = Math.round(Math.max(this.nodesPerFrame * .8, 10)); | |
| 63 | + this.nodesPerFrame = Math.round(Math.max(this.nodesPerFrame * 0.8, 10)); | |
| 48 | 64 | } |
| 49 | 65 | } else { |
| 50 | 66 | this.nodesPerFrame = 10; |
| 51 | 67 | } |
| 52 | 68 | |
| 53 | − for (var el of Array.from(this.highlightNodes.splice(0, this.nodesPerFrame))) { | |
| 69 | + for (var el of Array.from( | |
| 70 | + this.highlightNodes.splice(0, this.nodesPerFrame), | |
| 71 | + )) { | |
| 54 | 72 | var clipEl; |
| 55 | − if (clipEl = el.lastElementChild) { $.remove(clipEl); } | |
| 73 | + if ((clipEl = el.lastElementChild)) { | |
| 74 | + $.remove(clipEl); | |
| 75 | + } | |
| 56 | 76 | Prism.highlightElement(el); |
| 57 | − if (clipEl) { $.append(el, clipEl); } | |
| 77 | + if (clipEl) { | |
| 78 | + $.append(el, clipEl); | |
| 79 | + } | |
| 58 | 80 | } |
| 59 | 81 | |
| 60 | − if (this.highlightNodes.length > 0) { $.requestAnimationFrame(this.paintCode); } | |
| 82 | + if (this.highlightNodes.length > 0) { | |
| 83 | + $.requestAnimationFrame(this.paintCode); | |
| 84 | + } | |
| 61 | 85 | this.previousTiming = timing; |
| 62 | 86 | } |
| 63 | 87 | }; |
| @@ -8,20 +8,24 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | const Cls = (app.views.HiddenPage = class HiddenPage extends app.View { |
| 10 | 10 | static initClass() { |
| 11 | − this.events = | |
| 12 | − {click: 'onClick'}; | |
| 11 | + this.events = { click: "onClick" }; | |
| 13 | 12 | } |
| 14 | 13 | |
| 15 | − constructor(el, entry) { this.onClick = this.onClick.bind(this); this.el = el; this.entry = entry; super(...arguments); } | |
| 14 | + constructor(el, entry) { | |
| 15 | + this.onClick = this.onClick.bind(this); | |
| 16 | + this.el = el; | |
| 17 | + this.entry = entry; | |
| 18 | + super(...arguments); | |
| 19 | + } | |
| 16 | 20 | |
| 17 | 21 | init() { |
| 18 | − this.addSubview(this.notice = new app.views.Notice('disabledDoc')); | |
| 22 | + this.addSubview((this.notice = new app.views.Notice("disabledDoc"))); | |
| 19 | 23 | this.activate(); |
| 20 | 24 | } |
| 21 | 25 | |
| 22 | 26 | onClick(event) { |
| 23 | 27 | let link; |
| 24 | − if (link = $.closestLink(event.target, this.el)) { | |
| 28 | + if ((link = $.closestLink(event.target, this.el))) { | |
| 25 | 29 | $.stopEvent(event); |
| 26 | 30 | $.popup(link); |
| 27 | 31 | } |
| @@ -10,46 +10,54 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | //= require views/pages/base |
| 12 | 12 | |
| 13 | −const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage { | |
| 13 | +const Cls = (app.views.JqueryPage = class JqueryPage extends ( | |
| 14 | + app.views.BasePage | |
| 15 | +) { | |
| 14 | 16 | constructor(...args) { |
| 15 | 17 | this.onIframeLoaded = this.onIframeLoaded.bind(this); |
| 16 | 18 | super(...args); |
| 17 | 19 | } |
| 18 | 20 | |
| 19 | 21 | static initClass() { |
| 20 | − this.demoClassName = '_jquery-demo'; | |
| 22 | + this.demoClassName = "_jquery-demo"; | |
| 21 | 23 | } |
| 22 | 24 | |
| 23 | 25 | afterRender() { |
| 24 | 26 | // Prevent jQuery Mobile's demo iframes from scrolling the page |
| 25 | − for (var iframe of Array.from(this.findAllByTag('iframe'))) { | |
| 26 | − iframe.style.display = 'none'; | |
| 27 | − $.on(iframe, 'load', this.onIframeLoaded); | |
| 27 | + for (var iframe of Array.from(this.findAllByTag("iframe"))) { | |
| 28 | + iframe.style.display = "none"; | |
| 29 | + $.on(iframe, "load", this.onIframeLoaded); | |
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 32 | return this.runExamples(); |
| 31 | 33 | } |
| 32 | 34 | |
| 33 | 35 | onIframeLoaded(event) { |
| 34 | − event.target.style.display = ''; | |
| 35 | − $.off(event.target, 'load', this.onIframeLoaded); | |
| 36 | + event.target.style.display = ""; | |
| 37 | + $.off(event.target, "load", this.onIframeLoaded); | |
| 36 | 38 | } |
| 37 | 39 | |
| 38 | 40 | runExamples() { |
| 39 | − for (var el of Array.from(this.findAllByClass('entry-example'))) { | |
| 40 | − try { this.runExample(el); } catch (error) {} | |
| 41 | + for (var el of Array.from(this.findAllByClass("entry-example"))) { | |
| 42 | + try { | |
| 43 | + this.runExample(el); | |
| 44 | + } catch (error) {} | |
| 41 | 45 | } |
| 42 | 46 | } |
| 43 | 47 | |
| 44 | 48 | runExample(el) { |
| 45 | 49 | let iframe; |
| 46 | − const source = el.getElementsByClassName('syntaxhighlighter')[0]; | |
| 47 | − if (!source || (source.innerHTML.indexOf('!doctype') === -1)) { return; } | |
| 50 | + const source = el.getElementsByClassName("syntaxhighlighter")[0]; | |
| 51 | + if (!source || source.innerHTML.indexOf("!doctype") === -1) { | |
| 52 | + return; | |
| 53 | + } | |
| 48 | 54 | |
| 49 | − if (!(iframe = el.getElementsByClassName(this.constructor.demoClassName)[0])) { | |
| 50 | − iframe = document.createElement('iframe'); | |
| 55 | + if ( | |
| 56 | + !(iframe = el.getElementsByClassName(this.constructor.demoClassName)[0]) | |
| 57 | + ) { | |
| 58 | + iframe = document.createElement("iframe"); | |
| 51 | 59 | iframe.className = this.constructor.demoClassName; |
| 52 | − iframe.width = '100%'; | |
| 60 | + iframe.width = "100%"; | |
| 53 | 61 | iframe.height = 200; |
| 54 | 62 | el.appendChild(iframe); |
| 55 | 63 | } |
| @@ -60,8 +68,13 @@ const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage · 4 unmodified lines | ||
| 60 | 68 | } |
| 61 | 69 | |
| 62 | 70 | fixIframeSource(source) { |
| 63 | − source = source.replace('"/resources/', '"https://api.jquery.com/resources/'); // attr(), keydown() | |
| 64 | − source = source.replace('</head>', `\ | |
| 71 | + source = source.replace( | |
| 72 | + '"/resources/', | |
| 73 | + '"https://api.jquery.com/resources/', | |
| 74 | + ); // attr(), keydown() | |
| 75 | + source = source.replace( | |
| 76 | + "</head>", | |
| 77 | + `\ | |
| 65 | 78 | <style> |
| 66 | 79 | html, body { border: 0; margin: 0; padding: 0; } |
| 67 | 80 | body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } |
| @@ -75,7 +88,7 @@ const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage · 7 unmodified lines | ||
| 75 | 88 | }); |
| 76 | 89 | </script> |
| 77 | 90 | </head>\ |
| 78 | −` | |
| 91 | +`, | |
| 79 | 92 | ); |
| 80 | 93 | return source.replace(/<script>/gi, '<script nonce="devdocs">'); |
| 81 | 94 | } |
| @@ -10,19 +10,23 @@ · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | const Cls = (app.views.RdocPage = class RdocPage extends app.views.BasePage { |
| 12 | 12 | static initClass() { |
| 13 | − this.events = | |
| 14 | − {click: 'onClick'}; | |
| 13 | + this.events = { click: "onClick" }; | |
| 15 | 14 | } |
| 16 | 15 | |
| 17 | 16 | onClick(event) { |
| 18 | − if (!event.target.classList.contains('method-click-advice')) { return; } | |
| 17 | + if (!event.target.classList.contains("method-click-advice")) { | |
| 18 | + return; | |
| 19 | + } | |
| 19 | 20 | $.stopEvent(event); |
| 20 | 21 | |
| 21 | − const source = $('.method-source-code', event.target.closest('.method-detail')); | |
| 22 | − const isShown = source.style.display === 'block'; | |
| 22 | + const source = $( | |
| 23 | + ".method-source-code", | |
| 24 | + event.target.closest(".method-detail"), | |
| 25 | + ); | |
| 26 | + const isShown = source.style.display === "block"; | |
| 23 | 27 | |
| 24 | − source.style.display = isShown ? 'none' : 'block'; | |
| 25 | − return event.target.textContent = isShown ? 'Show source' : 'Hide source'; | |
| 28 | + source.style.display = isShown ? "none" : "block"; | |
| 29 | + return (event.target.textContent = isShown ? "Show source" : "Hide source"); | |
| 26 | 30 | } |
| 27 | 31 | }); |
| 28 | 32 | Cls.initClass(); |
| @@ -8,28 +8,33 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | //= require views/pages/base |
| 10 | 10 | |
| 11 | −const Cls = (app.views.SqlitePage = class SqlitePage extends app.views.BasePage { | |
| 11 | +const Cls = (app.views.SqlitePage = class SqlitePage extends ( | |
| 12 | + app.views.BasePage | |
| 13 | +) { | |
| 12 | 14 | constructor(...args) { |
| 13 | 15 | this.onClick = this.onClick.bind(this); |
| 14 | 16 | super(...args); |
| 15 | 17 | } |
| 16 | 18 | |
| 17 | 19 | static initClass() { |
| 18 | − this.events = | |
| 19 | − {click: 'onClick'}; | |
| 20 | + this.events = { click: "onClick" }; | |
| 20 | 21 | } |
| 21 | 22 | |
| 22 | 23 | onClick(event) { |
| 23 | 24 | let el, id; |
| 24 | − if (!(id = event.target.getAttribute('data-toggle'))) { return; } | |
| 25 | − if (!(el = this.find(`#${id}`))) { return; } | |
| 25 | + if (!(id = event.target.getAttribute("data-toggle"))) { | |
| 26 | + return; | |
| 27 | + } | |
| 28 | + if (!(el = this.find(`#${id}`))) { | |
| 29 | + return; | |
| 30 | + } | |
| 26 | 31 | $.stopEvent(event); |
| 27 | − if (el.style.display === 'none') { | |
| 28 | − el.style.display = 'block'; | |
| 29 | − event.target.textContent = 'hide'; | |
| 32 | + if (el.style.display === "none") { | |
| 33 | + el.style.display = "block"; | |
| 34 | + event.target.textContent = "hide"; | |
| 30 | 35 | } else { |
| 31 | − el.style.display = 'none'; | |
| 32 | − event.target.textContent = 'show'; | |
| 36 | + el.style.display = "none"; | |
| 37 | + event.target.textContent = "show"; | |
| 33 | 38 | } |
| 34 | 39 | } |
| 35 | 40 | }); |
| @@ -7,19 +7,24 @@ · 6 unmodified lines | ||
| 7 | 7 | */ |
| 8 | 8 | //= require views/pages/base |
| 9 | 9 | |
| 10 | −const Cls = (app.views.SupportTablesPage = class SupportTablesPage extends app.views.BasePage { | |
| 10 | +const Cls = (app.views.SupportTablesPage = class SupportTablesPage extends ( | |
| 11 | + app.views.BasePage | |
| 12 | +) { | |
| 11 | 13 | static initClass() { |
| 12 | − this.events = | |
| 13 | − {click: 'onClick'}; | |
| 14 | + this.events = { click: "onClick" }; | |
| 14 | 15 | } |
| 15 | 16 | |
| 16 | 17 | onClick(event) { |
| 17 | − if (!event.target.classList.contains('show-all')) { return; } | |
| 18 | + if (!event.target.classList.contains("show-all")) { | |
| 19 | + return; | |
| 20 | + } | |
| 18 | 21 | $.stopEvent(event); |
| 19 | 22 | |
| 20 | 23 | let el = event.target; |
| 21 | − while (el.tagName !== 'TABLE') { el = el.parentNode; } | |
| 22 | − el.classList.add('show-all'); | |
| 24 | + while (el.tagName !== "TABLE") { | |
| 25 | + el = el.parentNode; | |
| 26 | + } | |
| 27 | + el.classList.add("show-all"); | |
| 23 | 28 | } |
| 24 | 29 | }); |
| 25 | 30 | Cls.initClass(); |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | * DS207: Consider shorter variations of null checks |
| 10 | 10 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 11 | 11 | */ |
| 12 | −(function() { | |
| 12 | +(function () { | |
| 13 | 13 | let SEARCH_PARAM = undefined; |
| 14 | 14 | let HASH_RGX = undefined; |
| 15 | 15 | const Cls = (app.views.Search = class Search extends app.View { |
| @@ -33,86 +33,106 @@ · 17 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | static initClass() { |
| 35 | 35 | SEARCH_PARAM = app.config.search_param; |
| 36 | − | |
| 37 | − this.el = '._search'; | |
| 38 | − this.activeClass = '_search-active'; | |
| 39 | − | |
| 36 | + | |
| 37 | + this.el = "._search"; | |
| 38 | + this.activeClass = "_search-active"; | |
| 39 | + | |
| 40 | 40 | this.elements = { |
| 41 | − input: '._search-input', | |
| 42 | − resetLink: '._search-clear' | |
| 41 | + input: "._search-input", | |
| 42 | + resetLink: "._search-clear", | |
| 43 | 43 | }; |
| 44 | − | |
| 44 | + | |
| 45 | 45 | this.events = { |
| 46 | − input: 'onInput', | |
| 47 | − click: 'onClick', | |
| 48 | − submit: 'onSubmit' | |
| 46 | + input: "onInput", | |
| 47 | + click: "onClick", | |
| 48 | + submit: "onSubmit", | |
| 49 | 49 | }; |
| 50 | − | |
| 50 | + | |
| 51 | 51 | this.shortcuts = { |
| 52 | − typing: 'focus', | |
| 53 | − altG: 'google', | |
| 54 | − altS: 'stackoverflow', | |
| 55 | − altD: 'duckduckgo' | |
| 52 | + typing: "focus", | |
| 53 | + altG: "google", | |
| 54 | + altS: "stackoverflow", | |
| 55 | + altD: "duckduckgo", | |
| 56 | 56 | }; |
| 57 | − | |
| 58 | − this.routes = | |
| 59 | − {after: 'afterRoute'}; | |
| 60 | − | |
| 57 | + | |
| 58 | + this.routes = { after: "afterRoute" }; | |
| 59 | + | |
| 61 | 60 | HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.*)`); |
| 62 | 61 | } |
| 63 | 62 | |
| 64 | 63 | init() { |
| 65 | − this.addSubview(this.scope = new app.views.SearchScope(this.el)); | |
| 64 | + this.addSubview((this.scope = new app.views.SearchScope(this.el))); | |
| 66 | 65 | |
| 67 | − this.searcher = new app.Searcher; | |
| 68 | − this.searcher | |
| 69 | − .on('results', this.onResults) | |
| 70 | − .on('end', this.onEnd); | |
| 66 | + this.searcher = new app.Searcher(); | |
| 67 | + this.searcher.on("results", this.onResults).on("end", this.onEnd); | |
| 71 | 68 | |
| 72 | − this.scope | |
| 73 | − .on('change', this.onScopeChange); | |
| 69 | + this.scope.on("change", this.onScopeChange); | |
| 74 | 70 | |
| 75 | − app.on('ready', this.onReady); | |
| 76 | − $.on(window, 'hashchange', this.searchUrl); | |
| 77 | − $.on(window, 'focus', this.onWindowFocus); | |
| 71 | + app.on("ready", this.onReady); | |
| 72 | + $.on(window, "hashchange", this.searchUrl); | |
| 73 | + $.on(window, "focus", this.onWindowFocus); | |
| 78 | 74 | } |
| 79 | 75 | |
| 80 | 76 | focus() { |
| 81 | − if (document.activeElement === this.input) { return; } | |
| 82 | − if (app.settings.get('noAutofocus')) { return; } | |
| 83 | − this.input.focus(); | |
| 77 | + if (document.activeElement === this.input) { | |
| 78 | + return; | |
| 79 | + } | |
| 80 | + if (app.settings.get("noAutofocus")) { | |
| 81 | + return; | |
| 82 | + } | |
| 83 | + this.input.focus(); | |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | autoFocus() { |
| 87 | − if (app.isMobile() || $.isAndroid() || $.isIOS()) { return; } | |
| 88 | − if ((document.activeElement != null ? document.activeElement.tagName : undefined) === 'INPUT') { return; } | |
| 89 | − if (app.settings.get('noAutofocus')) { return; } | |
| 87 | + if (app.isMobile() || $.isAndroid() || $.isIOS()) { | |
| 88 | + return; | |
| 89 | + } | |
| 90 | + if ( | |
| 91 | + (document.activeElement != null | |
| 92 | + ? document.activeElement.tagName | |
| 93 | + : undefined) === "INPUT" | |
| 94 | + ) { | |
| 95 | + return; | |
| 96 | + } | |
| 97 | + if (app.settings.get("noAutofocus")) { | |
| 98 | + return; | |
| 99 | + } | |
| 90 | 100 | this.input.focus(); |
| 91 | 101 | } |
| 92 | 102 | |
| 93 | 103 | onWindowFocus(event) { |
| 94 | − if (event.target === window) { return this.autoFocus(); } | |
| 104 | + if (event.target === window) { | |
| 105 | + return this.autoFocus(); | |
| 106 | + } | |
| 95 | 107 | } |
| 96 | 108 | |
| 97 | 109 | getScopeDoc() { |
| 98 | − if (this.scope.isActive()) { return this.scope.getScope(); } | |
| 110 | + if (this.scope.isActive()) { | |
| 111 | + return this.scope.getScope(); | |
| 112 | + } | |
| 99 | 113 | } |
| 100 | 114 | |
| 101 | 115 | reset(force) { |
| 102 | − if (force || !this.input.value) { this.scope.reset(); } | |
| 116 | + if (force || !this.input.value) { | |
| 117 | + this.scope.reset(); | |
| 118 | + } | |
| 103 | 119 | this.el.reset(); |
| 104 | 120 | this.onInput(); |
| 105 | 121 | this.autoFocus(); |
| 106 | 122 | } |
| 107 | 123 | |
| 108 | 124 | onReady() { |
| 109 | − this.value = ''; | |
| 125 | + this.value = ""; | |
| 110 | 126 | this.delay(this.onInput); |
| 111 | 127 | } |
| 112 | 128 | |
| 113 | 129 | onInput() { |
| 114 | − if ((this.value == null) || // ignore events pre-"ready" | |
| 115 | − (this.value === this.input.value)) { return; } | |
| 130 | + if ( | |
| 131 | + this.value == null || // ignore events pre-"ready" | |
| 132 | + this.value === this.input.value | |
| 133 | + ) { | |
| 134 | + return; | |
| 135 | + } | |
| 116 | 136 | this.value = this.input.value; |
| 117 | 137 | |
| 118 | 138 | if (this.value.length) { |
| @@ -123,25 +143,33 @@ · 4 unmodified lines | ||
| 123 | 143 | } |
| 124 | 144 | |
| 125 | 145 | search(url) { |
| 126 | − if (url == null) { url = false; } | |
| 146 | + if (url == null) { | |
| 147 | + url = false; | |
| 148 | + } | |
| 127 | 149 | this.addClass(this.constructor.activeClass); |
| 128 | − this.trigger('searching'); | |
| 150 | + this.trigger("searching"); | |
| 129 | 151 | |
| 130 | 152 | this.hasResults = null; |
| 131 | − this.flags = {urlSearch: url, initialResults: true}; | |
| 132 | − this.searcher.find(this.scope.getScope().entries.all(), 'text', this.value); | |
| 153 | + this.flags = { urlSearch: url, initialResults: true }; | |
| 154 | + this.searcher.find( | |
| 155 | + this.scope.getScope().entries.all(), | |
| 156 | + "text", | |
| 157 | + this.value, | |
| 158 | + ); | |
| 133 | 159 | } |
| 134 | 160 | |
| 135 | 161 | searchUrl() { |
| 136 | 162 | let value; |
| 137 | − if (location.pathname === '/') { | |
| 163 | + if (location.pathname === "/") { | |
| 138 | 164 | this.scope.searchUrl(); |
| 139 | 165 | } else if (!app.router.isIndex()) { |
| 140 | 166 | return; |
| 141 | 167 | } |
| 142 | 168 | |
| 143 | − if (!(value = this.extractHashValue())) { return; } | |
| 144 | − this.input.value = (this.value = value); | |
| 169 | + if (!(value = this.extractHashValue())) { | |
| 170 | + return; | |
| 171 | + } | |
| 172 | + this.input.value = this.value = value; | |
| 145 | 173 | this.input.setSelectionRange(value.length, value.length); |
| 146 | 174 | this.search(true); |
| 147 | 175 | return true; |
| @@ -149,13 +177,15 @@ · 1 unmodified line | ||
| 149 | 177 | |
| 150 | 178 | clear() { |
| 151 | 179 | this.removeClass(this.constructor.activeClass); |
| 152 | − this.trigger('clear'); | |
| 180 | + this.trigger("clear"); | |
| 153 | 181 | } |
| 154 | 182 | |
| 155 | 183 | externalSearch(url) { |
| 156 | 184 | let value; |
| 157 | − if (value = this.value) { | |
| 158 | − if (this.scope.name()) { value = `${this.scope.name()} ${value}`; } | |
| 185 | + if ((value = this.value)) { | |
| 186 | + if (this.scope.name()) { | |
| 187 | + value = `${this.scope.name()} ${value}`; | |
| 188 | + } | |
| 159 | 189 | $.popup(`${url}${encodeURIComponent(value)}`); |
| 160 | 190 | this.reset(); |
| 161 | 191 | } |
| @@ -174,13 +204,17 @@ · 12 unmodified lines | ||
| 174 | 204 | } |
| 175 | 205 | |
| 176 | 206 | onResults(results) { |
| 177 | − if (results.length) { this.hasResults = true; } | |
| 178 | − this.trigger('results', results, this.flags); | |
| 207 | + if (results.length) { | |
| 208 | + this.hasResults = true; | |
| 209 | + } | |
| 210 | + this.trigger("results", results, this.flags); | |
| 179 | 211 | this.flags.initialResults = false; |
| 180 | 212 | } |
| 181 | 213 | |
| 182 | 214 | onEnd() { |
| 183 | − if (!this.hasResults) { this.trigger('noresults'); } | |
| 215 | + if (!this.hasResults) { | |
| 216 | + this.trigger("noresults"); | |
| 217 | + } | |
| 184 | 218 | } |
| 185 | 219 | |
| 186 | 220 | onClick(event) { |
| @@ -195,14 +229,24 @@ · 8 unmodified lines | ||
| 195 | 229 | } |
| 196 | 230 | |
| 197 | 231 | onScopeChange() { |
| 198 | − this.value = ''; | |
| 232 | + this.value = ""; | |
| 199 | 233 | this.onInput(); |
| 200 | 234 | } |
| 201 | 235 | |
| 202 | 236 | afterRoute(name, context) { |
| 203 | − if ((app.shortcuts.eventInProgress != null ? app.shortcuts.eventInProgress.name : undefined) === 'escape') { return; } | |
| 204 | − if (!context.init && app.router.isIndex()) { this.reset(true); } | |
| 205 | − if (context.hash) { this.delay(this.searchUrl); } | |
| 237 | + if ( | |
| 238 | + (app.shortcuts.eventInProgress != null | |
| 239 | + ? app.shortcuts.eventInProgress.name | |
| 240 | + : undefined) === "escape" | |
| 241 | + ) { | |
| 242 | + return; | |
| 243 | + } | |
| 244 | + if (!context.init && app.router.isIndex()) { | |
| 245 | + this.reset(true); | |
| 246 | + } | |
| 247 | + if (context.hash) { | |
| 248 | + this.delay(this.searchUrl); | |
| 249 | + } | |
| 206 | 250 | $.requestAnimationFrame(this.autoFocus); |
| 207 | 251 | } |
| 208 | 252 | |
| @@ -215,7 +259,12 @@ · 6 unmodified lines | ||
| 215 | 259 | } |
| 216 | 260 | |
| 217 | 261 | getHashValue() { |
| 218 | − try { return __guard__(HASH_RGX.exec($.urlDecode(location.hash)), x => x[1]); } catch (error) {} | |
| 262 | + try { | |
| 263 | + return __guard__( | |
| 264 | + HASH_RGX.exec($.urlDecode(location.hash)), | |
| 265 | + (x) => x[1], | |
| 266 | + ); | |
| 267 | + } catch (error) {} | |
| 219 | 268 | } |
| 220 | 269 | }); |
| 221 | 270 | Cls.initClass(); |
| @@ -223,5 +272,7 @@ · 1 unmodified line | ||
| 223 | 272 | })(); |
| 224 | 273 | |
| 225 | 274 | function __guard__(value, transform) { |
| 226 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 227 | −} | |
| 275 | + return typeof value !== "undefined" && value !== null | |
| 276 | + ? transform(value) | |
| 277 | + : undefined; | |
| 278 | +} | |
| @@ -9,41 +9,49 @@ · 8 unmodified lines | ||
| 9 | 9 | * DS207: Consider shorter variations of null checks |
| 10 | 10 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md |
| 11 | 11 | */ |
| 12 | −(function() { | |
| 12 | +(function () { | |
| 13 | 13 | let SEARCH_PARAM = undefined; |
| 14 | 14 | let HASH_RGX = undefined; |
| 15 | 15 | const Cls = (app.views.SearchScope = class SearchScope extends app.View { |
| 16 | 16 | static initClass() { |
| 17 | 17 | SEARCH_PARAM = app.config.search_param; |
| 18 | − | |
| 18 | + | |
| 19 | 19 | this.elements = { |
| 20 | − input: '._search-input', | |
| 21 | − tag: '._search-tag' | |
| 20 | + input: "._search-input", | |
| 21 | + tag: "._search-tag", | |
| 22 | 22 | }; |
| 23 | − | |
| 23 | + | |
| 24 | 24 | this.events = { |
| 25 | − click: 'onClick', | |
| 26 | − keydown: 'onKeydown', | |
| 27 | − textInput: 'onTextInput' | |
| 25 | + click: "onClick", | |
| 26 | + keydown: "onKeydown", | |
| 27 | + textInput: "onTextInput", | |
| 28 | 28 | }; |
| 29 | − | |
| 30 | − this.routes = | |
| 31 | − {after: 'afterRoute'}; | |
| 32 | − | |
| 29 | + | |
| 30 | + this.routes = { after: "afterRoute" }; | |
| 31 | + | |
| 33 | 32 | HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.+?) .`); |
| 34 | 33 | } |
| 35 | 34 | |
| 36 | − constructor(el) { this.onResults = this.onResults.bind(this); this.reset = this.reset.bind(this); this.doScopeSearch = this.doScopeSearch.bind(this); this.onClick = this.onClick.bind(this); this.onKeydown = this.onKeydown.bind(this); this.onTextInput = this.onTextInput.bind(this); this.afterRoute = this.afterRoute.bind(this); this.el = el; super(...arguments); } | |
| 35 | + constructor(el) { | |
| 36 | + this.onResults = this.onResults.bind(this); | |
| 37 | + this.reset = this.reset.bind(this); | |
| 38 | + this.doScopeSearch = this.doScopeSearch.bind(this); | |
| 39 | + this.onClick = this.onClick.bind(this); | |
| 40 | + this.onKeydown = this.onKeydown.bind(this); | |
| 41 | + this.onTextInput = this.onTextInput.bind(this); | |
| 42 | + this.afterRoute = this.afterRoute.bind(this); | |
| 43 | + this.el = el; | |
| 44 | + super(...arguments); | |
| 45 | + } | |
| 37 | 46 | |
| 38 | 47 | init() { |
| 39 | − this.placeholder = this.input.getAttribute('placeholder'); | |
| 48 | + this.placeholder = this.input.getAttribute("placeholder"); | |
| 40 | 49 | |
| 41 | 50 | this.searcher = new app.SynchronousSearcher({ |
| 42 | 51 | fuzzy_min_length: 2, |
| 43 | − max_results: 1 | |
| 52 | + max_results: 1, | |
| 44 | 53 | }); |
| 45 | − this.searcher.on('results', this.onResults); | |
| 46 | − | |
| 54 | + this.searcher.on("results", this.onResults); | |
| 47 | 55 | } |
| 48 | 56 | |
| 49 | 57 | getScope() { |
| @@ -55,26 +63,34 @@ · 5 unmodified lines | ||
| 55 | 63 | } |
| 56 | 64 | |
| 57 | 65 | name() { |
| 58 | − return (this.doc != null ? this.doc.name : undefined); | |
| 66 | + return this.doc != null ? this.doc.name : undefined; | |
| 59 | 67 | } |
| 60 | 68 | |
| 61 | 69 | search(value, searchDisabled) { |
| 62 | − if (searchDisabled == null) { searchDisabled = false; } | |
| 63 | − if (this.doc) { return; } | |
| 64 | − this.searcher.find(app.docs.all(), 'text', value); | |
| 65 | − if (!this.doc && searchDisabled) { this.searcher.find(app.disabledDocs.all(), 'text', value); } | |
| 70 | + if (searchDisabled == null) { | |
| 71 | + searchDisabled = false; | |
| 72 | + } | |
| 73 | + if (this.doc) { | |
| 74 | + return; | |
| 75 | + } | |
| 76 | + this.searcher.find(app.docs.all(), "text", value); | |
| 77 | + if (!this.doc && searchDisabled) { | |
| 78 | + this.searcher.find(app.disabledDocs.all(), "text", value); | |
| 79 | + } | |
| 66 | 80 | } |
| 67 | 81 | |
| 68 | 82 | searchUrl() { |
| 69 | 83 | let value; |
| 70 | − if (value = this.extractHashValue()) { | |
| 84 | + if ((value = this.extractHashValue())) { | |
| 71 | 85 | this.search(value, true); |
| 72 | 86 | } |
| 73 | 87 | } |
| 74 | 88 | |
| 75 | 89 | onResults(results) { |
| 76 | 90 | let doc; |
| 77 | − if (!(doc = results[0])) { return; } | |
| 91 | + if (!(doc = results[0])) { | |
| 92 | + return; | |
| 93 | + } | |
| 78 | 94 | if (app.docs.contains(doc)) { |
| 79 | 95 | this.selectDoc(doc); |
| 80 | 96 | } else { |
| @@ -84,45 +100,49 @@ · 3 unmodified lines | ||
| 84 | 100 | |
| 85 | 101 | selectDoc(doc) { |
| 86 | 102 | const previousDoc = this.doc; |
| 87 | − if (doc === previousDoc) { return; } | |
| 103 | + if (doc === previousDoc) { | |
| 104 | + return; | |
| 105 | + } | |
| 88 | 106 | this.doc = doc; |
| 89 | 107 | |
| 90 | 108 | this.tag.textContent = doc.fullName; |
| 91 | − this.tag.style.display = 'block'; | |
| 109 | + this.tag.style.display = "block"; | |
| 92 | 110 | |
| 93 | − this.input.removeAttribute('placeholder'); | |
| 111 | + this.input.removeAttribute("placeholder"); | |
| 94 | 112 | this.input.value = this.input.value.slice(this.input.selectionStart); |
| 95 | − this.input.style.paddingLeft = this.tag.offsetWidth + 10 + 'px'; | |
| 113 | + this.input.style.paddingLeft = this.tag.offsetWidth + 10 + "px"; | |
| 96 | 114 | |
| 97 | − $.trigger(this.input, 'input'); | |
| 98 | − this.trigger('change', this.doc, previousDoc); | |
| 115 | + $.trigger(this.input, "input"); | |
| 116 | + this.trigger("change", this.doc, previousDoc); | |
| 99 | 117 | } |
| 100 | 118 | |
| 101 | 119 | redirectToDoc(doc) { |
| 102 | − const { | |
| 103 | − hash | |
| 104 | − } = location; | |
| 105 | − app.router.replaceHash(''); | |
| 120 | + const { hash } = location; | |
| 121 | + app.router.replaceHash(""); | |
| 106 | 122 | location.assign(doc.fullPath() + hash); |
| 107 | 123 | } |
| 108 | 124 | |
| 109 | 125 | reset() { |
| 110 | − if (!this.doc) { return; } | |
| 126 | + if (!this.doc) { | |
| 127 | + return; | |
| 128 | + } | |
| 111 | 129 | const previousDoc = this.doc; |
| 112 | 130 | this.doc = null; |
| 113 | 131 | |
| 114 | − this.tag.textContent = ''; | |
| 115 | − this.tag.style.display = 'none'; | |
| 132 | + this.tag.textContent = ""; | |
| 133 | + this.tag.style.display = "none"; | |
| 116 | 134 | |
| 117 | − this.input.setAttribute('placeholder', this.placeholder); | |
| 118 | − this.input.style.paddingLeft = ''; | |
| 135 | + this.input.setAttribute("placeholder", this.placeholder); | |
| 136 | + this.input.style.paddingLeft = ""; | |
| 119 | 137 | |
| 120 | − this.trigger('change', null, previousDoc); | |
| 138 | + this.trigger("change", null, previousDoc); | |
| 121 | 139 | } |
| 122 | 140 | |
| 123 | 141 | doScopeSearch(event) { |
| 124 | 142 | this.search(this.input.value.slice(0, this.input.selectionStart)); |
| 125 | − if (this.doc) { $.stopEvent(event); } | |
| 143 | + if (this.doc) { | |
| 144 | + $.stopEvent(event); | |
| 145 | + } | |
| 126 | 146 | } |
| 127 | 147 | |
| 128 | 148 | onClick(event) { |
| @@ -133,38 +153,54 @@ · 4 unmodified lines | ||
| 133 | 153 | } |
| 134 | 154 | |
| 135 | 155 | onKeydown(event) { |
| 136 | − if (event.which === 8) { // backspace | |
| 137 | − if (this.doc && (this.input.selectionEnd === 0)) { | |
| 156 | + if (event.which === 8) { | |
| 157 | + // backspace | |
| 158 | + if (this.doc && this.input.selectionEnd === 0) { | |
| 138 | 159 | this.reset(); |
| 139 | 160 | $.stopEvent(event); |
| 140 | 161 | } |
| 141 | 162 | } else if (!this.doc && this.input.value && !$.isChromeForAndroid()) { |
| 142 | − if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) { return; } | |
| 143 | − if ((event.which === 9) || // tab | |
| 144 | − ((event.which === 32) && app.isMobile())) { // space | |
| 163 | + if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) { | |
| 164 | + return; | |
| 165 | + } | |
| 166 | + if ( | |
| 167 | + event.which === 9 || // tab | |
| 168 | + (event.which === 32 && app.isMobile()) | |
| 169 | + ) { | |
| 170 | + // space | |
| 145 | 171 | this.doScopeSearch(event); |
| 146 | 172 | } |
| 147 | 173 | } |
| 148 | 174 | } |
| 149 | 175 | |
| 150 | 176 | onTextInput(event) { |
| 151 | − if (!$.isChromeForAndroid()) { return; } | |
| 152 | − if (!this.doc && this.input.value && (event.data === ' ')) { | |
| 177 | + if (!$.isChromeForAndroid()) { | |
| 178 | + return; | |
| 179 | + } | |
| 180 | + if (!this.doc && this.input.value && event.data === " ") { | |
| 153 | 181 | this.doScopeSearch(event); |
| 154 | 182 | } |
| 155 | 183 | } |
| 156 | 184 | |
| 157 | 185 | extractHashValue() { |
| 158 | 186 | let value; |
| 159 | − if (value = this.getHashValue()) { | |
| 160 | − const newHash = $.urlDecode(location.hash).replace(`#${SEARCH_PARAM}=${value} `, `#${SEARCH_PARAM}=`); | |
| 187 | + if ((value = this.getHashValue())) { | |
| 188 | + const newHash = $.urlDecode(location.hash).replace( | |
| 189 | + `#${SEARCH_PARAM}=${value} `, | |
| 190 | + `#${SEARCH_PARAM}=`, | |
| 191 | + ); | |
| 161 | 192 | app.router.replaceHash(newHash); |
| 162 | 193 | return value; |
| 163 | 194 | } |
| 164 | 195 | } |
| 165 | 196 | |
| 166 | 197 | getHashValue() { |
| 167 | − try { return __guard__(HASH_RGX.exec($.urlDecode(location.hash)), x => x[1]); } catch (error) {} | |
| 198 | + try { | |
| 199 | + return __guard__( | |
| 200 | + HASH_RGX.exec($.urlDecode(location.hash)), | |
| 201 | + (x) => x[1], | |
| 202 | + ); | |
| 203 | + } catch (error) {} | |
| 168 | 204 | } |
| 169 | 205 | |
| 170 | 206 | afterRoute(name, context) { |
| @@ -178,5 +214,7 @@ · 7 unmodified lines | ||
| 178 | 214 | })(); |
| 179 | 215 | |
| 180 | 216 | function __guard__(value, transform) { |
| 181 | − return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; | |
| 182 | −} | |
| 217 | + return typeof value !== "undefined" && value !== null | |
| 218 | + ? transform(value) | |
| 219 | + : undefined; | |
| 220 | +} | |
| @@ -20,65 +20,75 @@ const Cls = (app.views.DocList = class DocList extends app.View { · 19 unmodified lines | ||
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | static initClass() { |
| 23 | − this.className = '_list'; | |
| 24 | − this.attributes = | |
| 25 | − {role: 'navigation'}; | |
| 26 | − | |
| 23 | + this.className = "_list"; | |
| 24 | + this.attributes = { role: "navigation" }; | |
| 25 | + | |
| 27 | 26 | this.events = { |
| 28 | − open: 'onOpen', | |
| 29 | − close: 'onClose', | |
| 30 | − click: 'onClick' | |
| 27 | + open: "onOpen", | |
| 28 | + close: "onClose", | |
| 29 | + click: "onClick", | |
| 31 | 30 | }; |
| 32 | − | |
| 33 | − this.routes = | |
| 34 | − {after: 'afterRoute'}; | |
| 35 | − | |
| 31 | + | |
| 32 | + this.routes = { after: "afterRoute" }; | |
| 33 | + | |
| 36 | 34 | this.elements = { |
| 37 | − disabledTitle: '._list-title', | |
| 38 | − disabledList: '._disabled-list' | |
| 35 | + disabledTitle: "._list-title", | |
| 36 | + disabledList: "._disabled-list", | |
| 39 | 37 | }; |
| 40 | 38 | } |
| 41 | 39 | |
| 42 | 40 | init() { |
| 43 | 41 | this.lists = {}; |
| 44 | 42 | |
| 45 | − this.addSubview(this.listFocus = new app.views.ListFocus(this.el)); | |
| 46 | − this.addSubview(this.listFold = new app.views.ListFold(this.el)); | |
| 47 | − this.addSubview(this.listSelect = new app.views.ListSelect(this.el)); | |
| 43 | + this.addSubview((this.listFocus = new app.views.ListFocus(this.el))); | |
| 44 | + this.addSubview((this.listFold = new app.views.ListFold(this.el))); | |
| 45 | + this.addSubview((this.listSelect = new app.views.ListSelect(this.el))); | |
| 48 | 46 | |
| 49 | − app.on('ready', this.render); | |
| 47 | + app.on("ready", this.render); | |
| 50 | 48 | } |
| 51 | 49 | |
| 52 | 50 | activate() { |
| 53 | 51 | if (super.activate(...arguments)) { |
| 54 | − for (var slug in this.lists) { var list = this.lists[slug]; list.activate(); } | |
| 52 | + for (var slug in this.lists) { | |
| 53 | + var list = this.lists[slug]; | |
| 54 | + list.activate(); | |
| 55 | + } | |
| 55 | 56 | this.listSelect.selectCurrent(); |
| 56 | 57 | } |
| 57 | 58 | } |
| 58 | 59 | |
| 59 | 60 | deactivate() { |
| 60 | 61 | if (super.deactivate(...arguments)) { |
| 61 | − for (var slug in this.lists) { var list = this.lists[slug]; list.deactivate(); } | |
| 62 | + for (var slug in this.lists) { | |
| 63 | + var list = this.lists[slug]; | |
| 64 | + list.deactivate(); | |
| 65 | + } | |
| 62 | 66 | } |
| 63 | 67 | } |
| 64 | 68 | |
| 65 | 69 | render() { |
| 66 | − let html = ''; | |
| 70 | + let html = ""; | |
| 67 | 71 | for (var doc of Array.from(app.docs.all())) { |
| 68 | − html += this.tmpl('sidebarDoc', doc, {fullName: app.docs.countAllBy('name', doc.name) > 1}); | |
| 72 | + html += this.tmpl("sidebarDoc", doc, { | |
| 73 | + fullName: app.docs.countAllBy("name", doc.name) > 1, | |
| 74 | + }); | |
| 69 | 75 | } |
| 70 | 76 | this.html(html); |
| 71 | − if (!app.isSingleDoc() && (app.disabledDocs.size() !== 0)) { this.renderDisabled(); } | |
| 77 | + if (!app.isSingleDoc() && app.disabledDocs.size() !== 0) { | |
| 78 | + this.renderDisabled(); | |
| 79 | + } | |
| 72 | 80 | } |
| 73 | 81 | |
| 74 | 82 | renderDisabled() { |
| 75 | − this.append(this.tmpl('sidebarDisabled', {count: app.disabledDocs.size()})); | |
| 83 | + this.append( | |
| 84 | + this.tmpl("sidebarDisabled", { count: app.disabledDocs.size() }), | |
| 85 | + ); | |
| 76 | 86 | this.refreshElements(); |
| 77 | 87 | this.renderDisabledList(); |
| 78 | 88 | } |
| 79 | 89 | |
| 80 | 90 | renderDisabledList() { |
| 81 | − if (app.settings.get('hideDisabled')) { | |
| 91 | + if (app.settings.get("hideDisabled")) { | |
| 82 | 92 | this.removeDisabledList(); |
| 83 | 93 | } else { |
| 84 | 94 | this.appendDisabledList(); |
| @@ -87,60 +97,67 @@ const Cls = (app.views.DocList = class DocList extends app.View { · 2 unmodified lines | ||
| 87 | 97 | |
| 88 | 98 | appendDisabledList() { |
| 89 | 99 | let doc; |
| 90 | − let html = ''; | |
| 100 | + let html = ""; | |
| 91 | 101 | const docs = [].concat(...Array.from(app.disabledDocs.all() || [])); |
| 92 | 102 | |
| 93 | 103 | while ((doc = docs.shift())) { |
| 94 | 104 | if (doc.version != null) { |
| 95 | − var versions = ''; | |
| 105 | + var versions = ""; | |
| 96 | 106 | while (true) { |
| 97 | − versions += this.tmpl('sidebarDoc', doc, {disabled: true}); | |
| 98 | − if ((docs[0] != null ? docs[0].name : undefined) !== doc.name) { break; } | |
| 107 | + versions += this.tmpl("sidebarDoc", doc, { disabled: true }); | |
| 108 | + if ((docs[0] != null ? docs[0].name : undefined) !== doc.name) { | |
| 109 | + break; | |
| 110 | + } | |
| 99 | 111 | doc = docs.shift(); |
| 100 | 112 | } |
| 101 | − html += this.tmpl('sidebarDisabledVersionedDoc', doc, versions); | |
| 113 | + html += this.tmpl("sidebarDisabledVersionedDoc", doc, versions); | |
| 102 | 114 | } else { |
| 103 | − html += this.tmpl('sidebarDoc', doc, {disabled: true}); | |
| 115 | + html += this.tmpl("sidebarDoc", doc, { disabled: true }); | |
| 104 | 116 | } |
| 105 | 117 | } |
| 106 | 118 | |
| 107 | − this.append(this.tmpl('sidebarDisabledList', html)); | |
| 108 | − this.disabledTitle.classList.add('open-title'); | |
| 119 | + this.append(this.tmpl("sidebarDisabledList", html)); | |
| 120 | + this.disabledTitle.classList.add("open-title"); | |
| 109 | 121 | this.refreshElements(); |
| 110 | 122 | } |
| 111 | 123 | |
| 112 | 124 | removeDisabledList() { |
| 113 | − if (this.disabledList) { $.remove(this.disabledList); } | |
| 114 | − this.disabledTitle.classList.remove('open-title'); | |
| 125 | + if (this.disabledList) { | |
| 126 | + $.remove(this.disabledList); | |
| 127 | + } | |
| 128 | + this.disabledTitle.classList.remove("open-title"); | |
| 115 | 129 | this.refreshElements(); |
| 116 | 130 | } |
| 117 | 131 | |
| 118 | 132 | reset(options) { |
| 119 | − if (options == null) { options = {}; } | |
| 133 | + if (options == null) { | |
| 134 | + options = {}; | |
| 135 | + } | |
| 120 | 136 | this.listSelect.deselect(); |
| 121 | 137 | if (this.listFocus != null) { |
| 122 | 138 | this.listFocus.blur(); |
| 123 | 139 | } |
| 124 | 140 | this.listFold.reset(); |
| 125 | − if (options.revealCurrent || app.isSingleDoc()) { this.revealCurrent(); } | |
| 141 | + if (options.revealCurrent || app.isSingleDoc()) { | |
| 142 | + this.revealCurrent(); | |
| 143 | + } | |
| 126 | 144 | } |
125 more lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 216 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.