Prettier.io

pull/1441/head
Simon Legner 1 year ago
parent 6b335fb4fc
commit a905bdf5c1

@ -14,33 +14,41 @@ this.app = {
_$$: $$, _$$: $$,
_page: page, _page: page,
collections: {}, collections: {},
models: {}, models: {},
templates: {}, templates: {},
views: {}, views: {},
init() { init() {
try { this.initErrorTracking(); } catch (error) {} try {
if (!this.browserCheck()) { return; } this.initErrorTracking();
} catch (error) {}
if (!this.browserCheck()) {
return;
}
this.el = $('._app'); this.el = $("._app");
this.localStorage = new LocalStorageStore; this.localStorage = new LocalStorageStore();
if (app.ServiceWorker.isEnabled()) { this.serviceWorker = new app.ServiceWorker; } if (app.ServiceWorker.isEnabled()) {
this.settings = new app.Settings; this.serviceWorker = new app.ServiceWorker();
}
this.settings = new app.Settings();
this.db = new app.DB(); this.db = new app.DB();
this.settings.initLayout(); this.settings.initLayout();
this.docs = new app.collections.Docs; this.docs = new app.collections.Docs();
this.disabledDocs = new app.collections.Docs; this.disabledDocs = new app.collections.Docs();
this.entries = new app.collections.Entries; this.entries = new app.collections.Entries();
this.router = new app.Router; this.router = new app.Router();
this.shortcuts = new app.Shortcuts; this.shortcuts = new app.Shortcuts();
this.document = new app.views.Document; this.document = new app.views.Document();
if (this.isMobile()) { this.mobile = new app.views.Mobile; } if (this.isMobile()) {
this.mobile = new app.views.Mobile();
}
if (document.body.hasAttribute('data-doc')) { if (document.body.hasAttribute("data-doc")) {
this.DOC = JSON.parse(document.body.getAttribute('data-doc')); this.DOC = JSON.parse(document.body.getAttribute("data-doc"));
this.bootOne(); this.bootOne();
} else if (this.DOCS) { } else if (this.DOCS) {
this.bootAll(); this.bootAll();
@ -50,7 +58,9 @@ this.app = {
}, },
browserCheck() { browserCheck() {
if (this.isSupportedBrowser()) { return true; } if (this.isSupportedBrowser()) {
return true;
}
document.body.innerHTML = app.templates.unsupportedBrowser; document.body.innerHTML = app.templates.unsupportedBrowser;
this.hideLoadingScreen(); this.hideLoadingScreen();
return false; return false;
@ -61,7 +71,7 @@ this.app = {
// from a domain other than our own, because things are likely to break. // from a domain other than our own, because things are likely to break.
// (e.g. cross-domain requests) // (e.g. cross-domain requests)
if (this.isInvalidLocation()) { if (this.isInvalidLocation()) {
new app.views.Notif('InvalidLocation'); new app.views.Notif("InvalidLocation");
} else { } else {
if (this.config.sentry_dsn) { if (this.config.sentry_dsn) {
Raven.config(this.config.sentry_dsn, { Raven.config(this.config.sentry_dsn, {
@ -70,9 +80,12 @@ this.app = {
includePaths: [/devdocs/], includePaths: [/devdocs/],
ignoreErrors: [/NPObject/, /NS_ERROR/, /^null$/, /EvalError/], ignoreErrors: [/NPObject/, /NS_ERROR/, /^null$/, /EvalError/],
tags: { tags: {
mode: this.isSingleDoc() ? 'single' : 'full', mode: this.isSingleDoc() ? "single" : "full",
iframe: (window.top !== window).toString(), iframe: (window.top !== window).toString(),
electron: (!!__guard__(window.process != null ? window.process.versions : undefined, x => x.electron)).toString() electron: (!!__guard__(
window.process != null ? window.process.versions : undefined,
(x) => x.electron,
)).toString(),
}, },
shouldSendCallback: () => { shouldSendCallback: () => {
try { try {
@ -89,12 +102,16 @@ this.app = {
dataCallback(data) { dataCallback(data) {
try { try {
$.extend(data.user || (data.user = {}), app.settings.dump()); $.extend(data.user || (data.user = {}), app.settings.dump());
if (data.user.docs) { data.user.docs = data.user.docs.split('/'); } if (data.user.docs) {
if (app.lastIDBTransaction) { data.user.lastIDBTransaction = app.lastIDBTransaction; } data.user.docs = data.user.docs.split("/");
}
if (app.lastIDBTransaction) {
data.user.lastIDBTransaction = app.lastIDBTransaction;
}
data.tags.scriptCount = document.scripts.length; data.tags.scriptCount = document.scripts.length;
} catch (error) {} } catch (error) {}
return data; return data;
} },
}).install(); }).install();
} }
this.previousErrorHandler = onerror; this.previousErrorHandler = onerror;
@ -106,8 +123,10 @@ this.app = {
bootOne() { bootOne() {
this.doc = new app.models.Doc(this.DOC); this.doc = new app.models.Doc(this.DOC);
this.docs.reset([this.doc]); this.docs.reset([this.doc]);
this.doc.load(this.start.bind(this), this.onBootError.bind(this), {readCache: true}); this.doc.load(this.start.bind(this), this.onBootError.bind(this), {
new app.views.Notice('singleDoc', this.doc); readCache: true,
});
new app.views.Notice("singleDoc", this.doc);
delete this.DOC; delete this.DOC;
}, },
@ -117,40 +136,61 @@ this.app = {
(docs.indexOf(doc.slug) >= 0 ? this.docs : this.disabledDocs).add(doc); (docs.indexOf(doc.slug) >= 0 ? this.docs : this.disabledDocs).add(doc);
} }
this.migrateDocs(); this.migrateDocs();
this.docs.load(this.start.bind(this), this.onBootError.bind(this), {readCache: true, writeCache: true}); this.docs.load(this.start.bind(this), this.onBootError.bind(this), {
readCache: true,
writeCache: true,
});
delete this.DOCS; delete this.DOCS;
}, },
start() { start() {
let doc; let doc;
for (doc of Array.from(this.docs.all())) { this.entries.add(doc.toEntry()); } for (doc of Array.from(this.docs.all())) {
for (doc of Array.from(this.disabledDocs.all())) { this.entries.add(doc.toEntry()); } this.entries.add(doc.toEntry());
for (doc of Array.from(this.docs.all())) { this.initDoc(doc); } }
this.trigger('ready'); for (doc of Array.from(this.disabledDocs.all())) {
this.entries.add(doc.toEntry());
}
for (doc of Array.from(this.docs.all())) {
this.initDoc(doc);
}
this.trigger("ready");
this.router.start(); this.router.start();
this.hideLoadingScreen(); this.hideLoadingScreen();
setTimeout(() => { setTimeout(() => {
if (!this.doc) { this.welcomeBack(); } if (!this.doc) {
return this.removeEvent('ready bootError'); this.welcomeBack();
} }
, 50); return this.removeEvent("ready bootError");
}, 50);
}, },
initDoc(doc) { initDoc(doc) {
for (var type of Array.from(doc.types.all())) { doc.entries.add(type.toEntry()); } for (var type of Array.from(doc.types.all())) {
doc.entries.add(type.toEntry());
}
this.entries.add(doc.entries.all()); this.entries.add(doc.entries.all());
}, },
migrateDocs() { migrateDocs() {
let needsSaving; let needsSaving;
for (var slug of Array.from(this.settings.getDocs())) { for (var slug of Array.from(this.settings.getDocs())) {
if (!this.docs.findBy('slug', slug)) {var doc; if (!this.docs.findBy("slug", slug)) {
var doc;
needsSaving = true; needsSaving = true;
if (slug === 'webpack~2') { doc = this.disabledDocs.findBy('slug', 'webpack'); } if (slug === "webpack~2") {
if (slug === 'angular~4_typescript') { doc = this.disabledDocs.findBy('slug', 'angular'); } doc = this.disabledDocs.findBy("slug", "webpack");
if (slug === 'angular~2_typescript') { doc = this.disabledDocs.findBy('slug', 'angular~2'); } }
if (!doc) { doc = this.disabledDocs.findBy('slug_without_version', slug); } if (slug === "angular~4_typescript") {
doc = this.disabledDocs.findBy("slug", "angular");
}
if (slug === "angular~2_typescript") {
doc = this.disabledDocs.findBy("slug", "angular~2");
}
if (!doc) {
doc = this.disabledDocs.findBy("slug_without_version", slug);
}
if (doc) { if (doc) {
this.disabledDocs.remove(doc); this.disabledDocs.remove(doc);
this.docs.add(doc); this.docs.add(doc);
@ -158,56 +198,70 @@ this.app = {
} }
} }
if (needsSaving) { this.saveDocs(); } if (needsSaving) {
this.saveDocs();
}
}, },
enableDoc(doc, _onSuccess, onError) { enableDoc(doc, _onSuccess, onError) {
if (this.docs.contains(doc)) { return; } if (this.docs.contains(doc)) {
return;
}
const onSuccess = () => { const onSuccess = () => {
if (this.docs.contains(doc)) { return; } if (this.docs.contains(doc)) {
return;
}
this.disabledDocs.remove(doc); this.disabledDocs.remove(doc);
this.docs.add(doc); this.docs.add(doc);
this.docs.sort(); this.docs.sort();
this.initDoc(doc); this.initDoc(doc);
this.saveDocs(); this.saveDocs();
if (app.settings.get('autoInstall')) { if (app.settings.get("autoInstall")) {
doc.install(_onSuccess, onError); doc.install(_onSuccess, onError);
} else { } else {
_onSuccess(); _onSuccess();
} }
}; };
doc.load(onSuccess, onError, {writeCache: true}); doc.load(onSuccess, onError, { writeCache: true });
}, },
saveDocs() { saveDocs() {
this.settings.setDocs(Array.from(this.docs.all()).map((doc) => doc.slug)); this.settings.setDocs(Array.from(this.docs.all()).map((doc) => doc.slug));
this.db.migrate(); this.db.migrate();
return (this.serviceWorker != null ? this.serviceWorker.updateInBackground() : undefined); return this.serviceWorker != null
? this.serviceWorker.updateInBackground()
: undefined;
}, },
welcomeBack() { welcomeBack() {
let visitCount = this.settings.get('count'); let visitCount = this.settings.get("count");
this.settings.set('count', ++visitCount); this.settings.set("count", ++visitCount);
if (visitCount === 5) { new app.views.Notif('Share', {autoHide: null}); } if (visitCount === 5) {
new app.views.Notif("Share", { autoHide: null });
}
new app.views.News(); new app.views.News();
new app.views.Updates(); new app.views.Updates();
return this.updateChecker = new app.UpdateChecker(); return (this.updateChecker = new app.UpdateChecker());
}, },
reboot() { reboot() {
if ((location.pathname !== '/') && (location.pathname !== '/settings')) { if (location.pathname !== "/" && location.pathname !== "/settings") {
window.location = `/#${location.pathname}`; window.location = `/#${location.pathname}`;
} else { } else {
window.location = '/'; window.location = "/";
} }
}, },
reload() { reload() {
this.docs.clearCache(); this.docs.clearCache();
this.disabledDocs.clearCache(); this.disabledDocs.clearCache();
if (this.serviceWorker) { this.serviceWorker.reload(); } else { this.reboot(); } if (this.serviceWorker) {
this.serviceWorker.reload();
} else {
this.reboot();
}
}, },
reset() { reset() {
@ -219,11 +273,13 @@ this.app = {
if (this.serviceWorker != null) { if (this.serviceWorker != null) {
this.serviceWorker.update(); this.serviceWorker.update();
} }
window.location = '/'; window.location = "/";
}, },
showTip(tip) { showTip(tip) {
if (this.isSingleDoc()) { return; } if (this.isSingleDoc()) {
return;
}
const tips = this.settings.getTips(); const tips = this.settings.getTips();
if (tips.indexOf(tip) === -1) { if (tips.indexOf(tip) === -1) {
tips.push(tip); tips.push(tip);
@ -233,44 +289,61 @@ this.app = {
}, },
hideLoadingScreen() { hideLoadingScreen() {
if ($.overlayScrollbarsEnabled()) { document.body.classList.add('_overlay-scrollbars'); } if ($.overlayScrollbarsEnabled()) {
document.documentElement.classList.remove('_booting'); document.body.classList.add("_overlay-scrollbars");
}
document.documentElement.classList.remove("_booting");
}, },
indexHost() { indexHost() {
// Can't load the index files from the host/CDN when service worker is // Can't load the index files from the host/CDN when service worker is
// enabled because it doesn't support caching URLs that use CORS. // enabled because it doesn't support caching URLs that use CORS.
return this.config[this.serviceWorker && this.settings.hasDocs() ? 'index_path' : 'docs_origin']; return this.config[
this.serviceWorker && this.settings.hasDocs()
? "index_path"
: "docs_origin"
];
}, },
onBootError(...args) { onBootError(...args) {
this.trigger('bootError'); this.trigger("bootError");
this.hideLoadingScreen(); this.hideLoadingScreen();
}, },
onQuotaExceeded() { onQuotaExceeded() {
if (this.quotaExceeded) { return; } if (this.quotaExceeded) {
return;
}
this.quotaExceeded = true; this.quotaExceeded = true;
new app.views.Notif('QuotaExceeded', {autoHide: null}); new app.views.Notif("QuotaExceeded", { autoHide: null });
}, },
onCookieBlocked(key, value, actual) { onCookieBlocked(key, value, actual) {
if (this.cookieBlocked) { return; } if (this.cookieBlocked) {
return;
}
this.cookieBlocked = true; this.cookieBlocked = true;
new app.views.Notif('CookieBlocked', {autoHide: null}); new app.views.Notif("CookieBlocked", { autoHide: null });
Raven.captureMessage(`CookieBlocked/${key}`, {level: 'warning', extra: {value, actual}}); Raven.captureMessage(`CookieBlocked/${key}`, {
level: "warning",
extra: { value, actual },
});
}, },
onWindowError(...args) { onWindowError(...args) {
if (this.cookieBlocked) { return; } if (this.cookieBlocked) {
return;
}
if (this.isInjectionError(...Array.from(args || []))) { if (this.isInjectionError(...Array.from(args || []))) {
this.onInjectionError(); this.onInjectionError();
} else if (this.isAppError(...Array.from(args || []))) { } else if (this.isAppError(...Array.from(args || []))) {
if (typeof this.previousErrorHandler === 'function') { if (typeof this.previousErrorHandler === "function") {
this.previousErrorHandler(...Array.from(args || [])); this.previousErrorHandler(...Array.from(args || []));
} }
this.hideLoadingScreen(); this.hideLoadingScreen();
if (!this.errorNotif) { this.errorNotif = new app.views.Notif('Error'); } if (!this.errorNotif) {
this.errorNotif = new app.views.Notif("Error");
}
this.errorNotif.show(); this.errorNotif.show();
} }
}, },
@ -280,73 +353,101 @@ this.app = {
this.injectionError = true; this.injectionError = true;
alert(`\ alert(`\
JavaScript code has been injected in the page which prevents DevDocs from running correctly. JavaScript code has been injected in the page which prevents DevDocs from running correctly.
Please check your browser extensions/addons. ` Please check your browser extensions/addons. `);
); Raven.captureMessage("injection error", { level: "info" });
Raven.captureMessage('injection error', {level: 'info'});
} }
}, },
isInjectionError() { isInjectionError() {
// Some browser extensions expect the entire web to use jQuery. // Some browser extensions expect the entire web to use jQuery.
// I gave up trying to fight back. // I gave up trying to fight back.
return (window.$ !== app._$) || (window.$$ !== app._$$) || (window.page !== app._page) || (typeof $.empty !== 'function') || (typeof page.show !== 'function'); return (
window.$ !== app._$ ||
window.$$ !== app._$$ ||
window.page !== app._page ||
typeof $.empty !== "function" ||
typeof page.show !== "function"
);
}, },
isAppError(error, file) { isAppError(error, file) {
// Ignore errors from external scripts. // Ignore errors from external scripts.
return file && (file.indexOf('devdocs') !== -1) && (file.indexOf('.js') === (file.length - 3)); return (
file &&
file.indexOf("devdocs") !== -1 &&
file.indexOf(".js") === file.length - 3
);
}, },
isSupportedBrowser() { isSupportedBrowser() {
try { try {
const features = { const features = {
bind: !!Function.prototype.bind, bind: !!Function.prototype.bind,
pushState: !!history.pushState, pushState: !!history.pushState,
matchMedia: !!window.matchMedia, matchMedia: !!window.matchMedia,
insertAdjacentHTML: !!document.body.insertAdjacentHTML, insertAdjacentHTML: !!document.body.insertAdjacentHTML,
defaultPrevented: document.createEvent('CustomEvent').defaultPrevented === false, defaultPrevented:
cssVariables: !!__guardMethod__(CSS, 'supports', o => o.supports('(--t: 0)')) document.createEvent("CustomEvent").defaultPrevented === false,
cssVariables: !!__guardMethod__(CSS, "supports", (o) =>
o.supports("(--t: 0)"),
),
}; };
for (var key in features) { for (var key in features) {
var value = features[key]; var value = features[key];
if (!value) { if (!value) {
Raven.captureMessage(`unsupported/${key}`, {level: 'info'}); Raven.captureMessage(`unsupported/${key}`, { level: "info" });
return false; return false;
} }
} }
return true; return true;
} catch (error) { } catch (error) {
Raven.captureMessage('unsupported/exception', {level: 'info', extra: { error }}); Raven.captureMessage("unsupported/exception", {
level: "info",
extra: { error },
});
return false; return false;
} }
}, },
isSingleDoc() { isSingleDoc() {
return document.body.hasAttribute('data-doc'); return document.body.hasAttribute("data-doc");
}, },
isMobile() { isMobile() {
return this._isMobile != null ? this._isMobile : (this._isMobile = app.views.Mobile.detect()); return this._isMobile != null
? this._isMobile
: (this._isMobile = app.views.Mobile.detect());
}, },
isAndroidWebview() { isAndroidWebview() {
return this._isAndroidWebview != null ? this._isAndroidWebview : (this._isAndroidWebview = app.views.Mobile.detectAndroidWebview()); return this._isAndroidWebview != null
? this._isAndroidWebview
: (this._isAndroidWebview = app.views.Mobile.detectAndroidWebview());
}, },
isInvalidLocation() { isInvalidLocation() {
return (this.config.env === 'production') && (location.host.indexOf(app.config.production_host) !== 0); return (
} this.config.env === "production" &&
location.host.indexOf(app.config.production_host) !== 0
);
},
}; };
$.extend(app, Events); $.extend(app, Events);
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }
function __guardMethod__(obj, methodName, transform) { function __guardMethod__(obj, methodName, transform) {
if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { if (
typeof obj !== "undefined" &&
obj !== null &&
typeof obj[methodName] === "function"
) {
return transform(obj, methodName); return transform(obj, methodName);
} else { } else {
return undefined; return undefined;

@ -9,12 +9,12 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let NAME = undefined; let NAME = undefined;
let VERSION = undefined; let VERSION = undefined;
const Cls = (app.DB = class DB { const Cls = (app.DB = class DB {
static initClass() { static initClass() {
NAME = 'docs'; NAME = "docs";
VERSION = 15; VERSION = 15;
} }
@ -29,18 +29,27 @@
} }
db(fn) { db(fn) {
if (!this.useIndexedDB) { return fn(); } if (!this.useIndexedDB) {
if (fn) { this.callbacks.push(fn); } return fn();
if (this.open) { return; } }
if (fn) {
this.callbacks.push(fn);
}
if (this.open) {
return;
}
try { try {
this.open = true; this.open = true;
const req = indexedDB.open(NAME, (VERSION * this.versionMultipler) + this.userVersion()); const req = indexedDB.open(
NAME,
VERSION * this.versionMultipler + this.userVersion(),
);
req.onsuccess = this.onOpenSuccess; req.onsuccess = this.onOpenSuccess;
req.onerror = this.onOpenError; req.onerror = this.onOpenError;
req.onupgradeneeded = this.onUpgradeNeeded; req.onupgradeneeded = this.onUpgradeNeeded;
} catch (error) { } catch (error) {
this.fail('exception', error); this.fail("exception", error);
} }
} }
@ -49,13 +58,17 @@
const db = event.target.result; const db = event.target.result;
if (db.objectStoreNames.length === 0) { if (db.objectStoreNames.length === 0) {
try { db.close(); } catch (error1) {} try {
db.close();
} catch (error1) {}
this.open = false; this.open = false;
this.fail('empty'); this.fail("empty");
} else if (error = this.buggyIDB(db)) { } else if ((error = this.buggyIDB(db))) {
try { db.close(); } catch (error2) {} try {
db.close();
} catch (error2) {}
this.open = false; this.open = false;
this.fail('buggy', error); this.fail("buggy", error);
} else { } else {
this.runCallbacks(db); this.runCallbacks(db);
this.open = false; this.open = false;
@ -66,36 +79,43 @@
onOpenError(event) { onOpenError(event) {
event.preventDefault(); event.preventDefault();
this.open = false; this.open = false;
const { const { error } = event.target;
error
} = event.target;
switch (error.name) { switch (error.name) {
case 'QuotaExceededError': case "QuotaExceededError":
this.onQuotaExceededError(); this.onQuotaExceededError();
break; break;
case 'VersionError': case "VersionError":
this.onVersionError(); this.onVersionError();
break; break;
case 'InvalidStateError': case "InvalidStateError":
this.fail('private_mode'); this.fail("private_mode");
break; break;
default: default:
this.fail('cant_open', error); this.fail("cant_open", error);
} }
} }
fail(reason, error) { fail(reason, error) {
this.cachedDocs = null; this.cachedDocs = null;
this.useIndexedDB = false; this.useIndexedDB = false;
if (!this.reason) { this.reason = reason; } if (!this.reason) {
if (!this.error) { this.error = error; } this.reason = reason;
if (error) { if (typeof console.error === 'function') { }
console.error('IDB error', error); if (!this.error) {
} } this.error = error;
}
if (error) {
if (typeof console.error === "function") {
console.error("IDB error", error);
}
}
this.runCallbacks(); this.runCallbacks();
if (error && (reason === 'cant_open')) { if (error && reason === "cant_open") {
Raven.captureMessage(`${error.name}: ${error.message}`, {level: 'warning', fingerprint: [error.name]}); Raven.captureMessage(`${error.name}: ${error.message}`, {
level: "warning",
fingerprint: [error.name],
});
} }
} }
@ -103,34 +123,39 @@
this.reset(); this.reset();
this.db(); this.db();
app.onQuotaExceeded(); app.onQuotaExceeded();
Raven.captureMessage('QuotaExceededError', {level: 'warning'}); Raven.captureMessage("QuotaExceededError", { level: "warning" });
} }
onVersionError() { onVersionError() {
const req = indexedDB.open(NAME); const req = indexedDB.open(NAME);
req.onsuccess = event => { req.onsuccess = (event) => {
return this.handleVersionMismatch(event.target.result.version); return this.handleVersionMismatch(event.target.result.version);
}; };
req.onerror = function(event) { req.onerror = function (event) {
event.preventDefault(); event.preventDefault();
return this.fail('cant_open', error); return this.fail("cant_open", error);
}; };
} }
handleVersionMismatch(actualVersion) { handleVersionMismatch(actualVersion) {
if (Math.floor(actualVersion / this.versionMultipler) !== VERSION) { if (Math.floor(actualVersion / this.versionMultipler) !== VERSION) {
this.fail('version'); this.fail("version");
} else { } else {
this.setUserVersion(actualVersion - (VERSION * this.versionMultipler)); this.setUserVersion(actualVersion - VERSION * this.versionMultipler);
this.db(); this.db();
} }
} }
buggyIDB(db) { buggyIDB(db) {
if (this.checkedBuggyIDB) { return; } if (this.checkedBuggyIDB) {
return;
}
this.checkedBuggyIDB = true; this.checkedBuggyIDB = true;
try { try {
this.idbTransaction(db, {stores: $.makeArray(db.objectStoreNames).slice(0, 2), mode: 'readwrite'}).abort(); // https://bugs.webkit.org/show_bug.cgi?id=136937 this.idbTransaction(db, {
stores: $.makeArray(db.objectStoreNames).slice(0, 2),
mode: "readwrite",
}).abort(); // https://bugs.webkit.org/show_bug.cgi?id=136937
return; return;
} catch (error) { } catch (error) {
return error; return error;
@ -139,53 +164,72 @@
runCallbacks(db) { runCallbacks(db) {
let fn; let fn;
while ((fn = this.callbacks.shift())) { fn(db); } while ((fn = this.callbacks.shift())) {
fn(db);
}
} }
onUpgradeNeeded(event) { onUpgradeNeeded(event) {
let db; let db;
if (!(db = event.target.result)) { return; } if (!(db = event.target.result)) {
return;
}
const objectStoreNames = $.makeArray(db.objectStoreNames); const objectStoreNames = $.makeArray(db.objectStoreNames);
if (!$.arrayDelete(objectStoreNames, 'docs')) { if (!$.arrayDelete(objectStoreNames, "docs")) {
try { db.createObjectStore('docs'); } catch (error) {} try {
db.createObjectStore("docs");
} catch (error) {}
} }
for (var doc of Array.from(app.docs.all())) { for (var doc of Array.from(app.docs.all())) {
if (!$.arrayDelete(objectStoreNames, doc.slug)) { if (!$.arrayDelete(objectStoreNames, doc.slug)) {
try { db.createObjectStore(doc.slug); } catch (error1) {} try {
db.createObjectStore(doc.slug);
} catch (error1) {}
} }
} }
for (var name of Array.from(objectStoreNames)) { for (var name of Array.from(objectStoreNames)) {
try { db.deleteObjectStore(name); } catch (error2) {} try {
db.deleteObjectStore(name);
} catch (error2) {}
} }
} }
store(doc, data, onSuccess, onError, _retry) { store(doc, data, onSuccess, onError, _retry) {
if (_retry == null) { _retry = true; } if (_retry == null) {
this.db(db => { _retry = true;
}
this.db((db) => {
if (!db) { if (!db) {
onError(); onError();
return; return;
} }
const txn = this.idbTransaction(db, {stores: ['docs', doc.slug], mode: 'readwrite', ignoreError: false}); const txn = this.idbTransaction(db, {
stores: ["docs", doc.slug],
mode: "readwrite",
ignoreError: false,
});
txn.oncomplete = () => { txn.oncomplete = () => {
if (this.cachedDocs != null) { if (this.cachedDocs != null) {
this.cachedDocs[doc.slug] = doc.mtime; this.cachedDocs[doc.slug] = doc.mtime;
} }
onSuccess(); onSuccess();
}; };
txn.onerror = event => { txn.onerror = (event) => {
event.preventDefault(); event.preventDefault();
if (((txn.error != null ? txn.error.name : undefined) === 'NotFoundError') && _retry) { if (
(txn.error != null ? txn.error.name : undefined) ===
"NotFoundError" &&
_retry
) {
this.migrate(); this.migrate();
setTimeout(() => { setTimeout(() => {
return this.store(doc, data, onSuccess, onError, false); return this.store(doc, data, onSuccess, onError, false);
} }, 0);
, 0);
} else { } else {
onError(event); onError(event);
} }
@ -193,42 +237,54 @@
let store = txn.objectStore(doc.slug); let store = txn.objectStore(doc.slug);
store.clear(); store.clear();
for (var path in data) { var content = data[path]; store.add(content, path); } for (var path in data) {
var content = data[path];
store.add(content, path);
}
store = txn.objectStore('docs'); store = txn.objectStore("docs");
store.put(doc.mtime, doc.slug); store.put(doc.mtime, doc.slug);
}); });
} }
unstore(doc, onSuccess, onError, _retry) { unstore(doc, onSuccess, onError, _retry) {
if (_retry == null) { _retry = true; } if (_retry == null) {
this.db(db => { _retry = true;
}
this.db((db) => {
if (!db) { if (!db) {
onError(); onError();
return; return;
} }
const txn = this.idbTransaction(db, {stores: ['docs', doc.slug], mode: 'readwrite', ignoreError: false}); const txn = this.idbTransaction(db, {
stores: ["docs", doc.slug],
mode: "readwrite",
ignoreError: false,
});
txn.oncomplete = () => { txn.oncomplete = () => {
if (this.cachedDocs != null) { if (this.cachedDocs != null) {
delete this.cachedDocs[doc.slug]; delete this.cachedDocs[doc.slug];
} }
onSuccess(); onSuccess();
}; };
txn.onerror = function(event) { txn.onerror = function (event) {
event.preventDefault(); event.preventDefault();
if (((txn.error != null ? txn.error.name : undefined) === 'NotFoundError') && _retry) { if (
(txn.error != null ? txn.error.name : undefined) ===
"NotFoundError" &&
_retry
) {
this.migrate(); this.migrate();
setTimeout(() => { setTimeout(() => {
return this.unstore(doc, onSuccess, onError, false); return this.unstore(doc, onSuccess, onError, false);
} }, 0);
, 0);
} else { } else {
onError(event); onError(event);
} }
}; };
let store = txn.objectStore('docs'); let store = txn.objectStore("docs");
store.delete(doc.slug); store.delete(doc.slug);
store = txn.objectStore(doc.slug); store = txn.objectStore(doc.slug);
@ -243,20 +299,23 @@
return; return;
} }
this.db(db => { this.db((db) => {
if (!db) { if (!db) {
fn(false); fn(false);
return; return;
} }
const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); const txn = this.idbTransaction(db, {
const store = txn.objectStore('docs'); stores: ["docs"],
mode: "readonly",
});
const store = txn.objectStore("docs");
const req = store.get(doc.slug); const req = store.get(doc.slug);
req.onsuccess = function() { req.onsuccess = function () {
fn(req.result); fn(req.result);
}; };
req.onerror = function(event) { req.onerror = function (event) {
event.preventDefault(); event.preventDefault();
fn(false); fn(false);
}; };
@ -264,36 +323,41 @@
} }
cachedVersion(doc) { cachedVersion(doc) {
if (!this.cachedDocs) { return; } if (!this.cachedDocs) {
return;
}
return this.cachedDocs[doc.slug] || false; return this.cachedDocs[doc.slug] || false;
} }
versions(docs, fn) { versions(docs, fn) {
let versions; let versions;
if (versions = this.cachedVersions(docs)) { if ((versions = this.cachedVersions(docs))) {
fn(versions); fn(versions);
return; return;
} }
return this.db(db => { return this.db((db) => {
if (!db) { if (!db) {
fn(false); fn(false);
return; return;
} }
const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); const txn = this.idbTransaction(db, {
txn.oncomplete = function() { stores: ["docs"],
mode: "readonly",
});
txn.oncomplete = function () {
fn(result); fn(result);
}; };
const store = txn.objectStore('docs'); const store = txn.objectStore("docs");
var result = {}; var result = {};
docs.forEach(function(doc) { docs.forEach(function (doc) {
const req = store.get(doc.slug); const req = store.get(doc.slug);
req.onsuccess = function() { req.onsuccess = function () {
result[doc.slug] = req.result; result[doc.slug] = req.result;
}; };
req.onerror = function(event) { req.onerror = function (event) {
event.preventDefault(); event.preventDefault();
result[doc.slug] = false; result[doc.slug] = false;
}; };
@ -302,9 +366,13 @@
} }
cachedVersions(docs) { cachedVersions(docs) {
if (!this.cachedDocs) { return; } if (!this.cachedDocs) {
return;
}
const result = {}; const result = {};
for (var doc of Array.from(docs)) { result[doc.slug] = this.cachedVersion(doc); } for (var doc of Array.from(docs)) {
result[doc.slug] = this.cachedVersion(doc);
}
return result; return result;
} }
@ -320,14 +388,14 @@
loadWithXHR(entry, onSuccess, onError) { loadWithXHR(entry, onSuccess, onError) {
return ajax({ return ajax({
url: entry.fileUrl(), url: entry.fileUrl(),
dataType: 'html', dataType: "html",
success: onSuccess, success: onSuccess,
error: onError error: onError,
}); });
} }
loadWithIDB(entry, onSuccess, onError) { loadWithIDB(entry, onSuccess, onError) {
return this.db(db => { return this.db((db) => {
if (!db) { if (!db) {
onError(); onError();
return; return;
@ -339,14 +407,21 @@
return; return;
} }
const txn = this.idbTransaction(db, {stores: [entry.doc.slug], mode: 'readonly'}); const txn = this.idbTransaction(db, {
stores: [entry.doc.slug],
mode: "readonly",
});
const store = txn.objectStore(entry.doc.slug); const store = txn.objectStore(entry.doc.slug);
const req = store.get(entry.dbPath()); const req = store.get(entry.dbPath());
req.onsuccess = function() { req.onsuccess = function () {
if (req.result) { onSuccess(req.result); } else { onError(); } if (req.result) {
onSuccess(req.result);
} else {
onError();
}
}; };
req.onerror = function(event) { req.onerror = function (event) {
event.preventDefault(); event.preventDefault();
onError(); onError();
}; };
@ -355,31 +430,38 @@
} }
loadDocsCache(db) { loadDocsCache(db) {
if (this.cachedDocs) { return; } if (this.cachedDocs) {
return;
}
this.cachedDocs = {}; this.cachedDocs = {};
const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readonly'}); const txn = this.idbTransaction(db, {
stores: ["docs"],
mode: "readonly",
});
txn.oncomplete = () => { txn.oncomplete = () => {
setTimeout(this.checkForCorruptedDocs, 50); setTimeout(this.checkForCorruptedDocs, 50);
}; };
const req = txn.objectStore('docs').openCursor(); const req = txn.objectStore("docs").openCursor();
req.onsuccess = event => { req.onsuccess = (event) => {
let cursor; let cursor;
if (!(cursor = event.target.result)) { return; } if (!(cursor = event.target.result)) {
return;
}
this.cachedDocs[cursor.key] = cursor.value; this.cachedDocs[cursor.key] = cursor.value;
cursor.continue(); cursor.continue();
}; };
req.onerror = function(event) { req.onerror = function (event) {
event.preventDefault(); event.preventDefault();
}; };
} }
checkForCorruptedDocs() { checkForCorruptedDocs() {
this.db(db => { this.db((db) => {
let slug; let slug;
this.corruptedDocs = []; this.corruptedDocs = [];
const docs = ((() => { const docs = (() => {
const result = []; const result = [];
for (var key in this.cachedDocs) { for (var key in this.cachedDocs) {
var value = this.cachedDocs[key]; var value = this.cachedDocs[key];
@ -388,11 +470,13 @@
} }
} }
return result; return result;
})()); })();
if (docs.length === 0) { return; } if (docs.length === 0) {
return;
}
for (slug of Array.from(docs)) { for (slug of Array.from(docs)) {
if (!app.docs.findBy('slug', slug)) { if (!app.docs.findBy("slug", slug)) {
this.corruptedDocs.push(slug); this.corruptedDocs.push(slug);
} }
} }
@ -406,46 +490,64 @@
return; return;
} }
const txn = this.idbTransaction(db, {stores: docs, mode: 'readonly', ignoreError: false}); const txn = this.idbTransaction(db, {
stores: docs,
mode: "readonly",
ignoreError: false,
});
txn.oncomplete = () => { txn.oncomplete = () => {
if (this.corruptedDocs.length > 0) { setTimeout(this.deleteCorruptedDocs, 0); } if (this.corruptedDocs.length > 0) {
setTimeout(this.deleteCorruptedDocs, 0);
}
}; };
for (var doc of Array.from(docs)) { for (var doc of Array.from(docs)) {
txn.objectStore(doc).get('index').onsuccess = event => { txn.objectStore(doc).get("index").onsuccess = (event) => {
if (!event.target.result) { this.corruptedDocs.push(event.target.source.name); } if (!event.target.result) {
this.corruptedDocs.push(event.target.source.name);
}
}; };
} }
}); });
} }
deleteCorruptedDocs() { deleteCorruptedDocs() {
this.db(db => { this.db((db) => {
let doc; let doc;
const txn = this.idbTransaction(db, {stores: ['docs'], mode: 'readwrite', ignoreError: false}); const txn = this.idbTransaction(db, {
const store = txn.objectStore('docs'); stores: ["docs"],
mode: "readwrite",
ignoreError: false,
});
const store = txn.objectStore("docs");
while ((doc = this.corruptedDocs.pop())) { while ((doc = this.corruptedDocs.pop())) {
this.cachedDocs[doc] = false; this.cachedDocs[doc] = false;
store.delete(doc); store.delete(doc);
} }
}); });
Raven.captureMessage('corruptedDocs', {level: 'info', extra: { docs: this.corruptedDocs.join(',') }}); Raven.captureMessage("corruptedDocs", {
level: "info",
extra: { docs: this.corruptedDocs.join(",") },
});
} }
shouldLoadWithIDB(entry) { shouldLoadWithIDB(entry) {
return this.useIndexedDB && (!this.cachedDocs || this.cachedDocs[entry.doc.slug]); return (
this.useIndexedDB &&
(!this.cachedDocs || this.cachedDocs[entry.doc.slug])
);
} }
idbTransaction(db, options) { idbTransaction(db, options) {
app.lastIDBTransaction = [options.stores, options.mode]; app.lastIDBTransaction = [options.stores, options.mode];
const txn = db.transaction(options.stores, options.mode); const txn = db.transaction(options.stores, options.mode);
if (options.ignoreError !== false) { if (options.ignoreError !== false) {
txn.onerror = function(event) { txn.onerror = function (event) {
event.preventDefault(); event.preventDefault();
}; };
} }
if (options.ignoreAbort !== false) { if (options.ignoreAbort !== false) {
txn.onabort = function(event) { txn.onabort = function (event) {
event.preventDefault(); event.preventDefault();
}; };
} }
@ -453,9 +555,11 @@
} }
reset() { reset() {
try { if (typeof indexedDB !== 'undefined' && indexedDB !== null) { try {
indexedDB.deleteDatabase(NAME); if (typeof indexedDB !== "undefined" && indexedDB !== null) {
} } catch (error) {} indexedDB.deleteDatabase(NAME);
}
} catch (error) {}
} }
useIndexedDB() { useIndexedDB() {
@ -463,7 +567,7 @@
if (!app.isSingleDoc() && window.indexedDB) { if (!app.isSingleDoc() && window.indexedDB) {
return true; return true;
} else { } else {
this.reason = 'not_supported'; this.reason = "not_supported";
return false; return false;
} }
} catch (error) { } catch (error) {
@ -472,15 +576,15 @@
} }
migrate() { migrate() {
app.settings.set('schema', this.userVersion() + 1); app.settings.set("schema", this.userVersion() + 1);
} }
setUserVersion(version) { setUserVersion(version) {
app.settings.set('schema', version); app.settings.set("schema", version);
} }
userVersion() { userVersion() {
return app.settings.get('schema'); return app.settings.get("schema");
} }
}); });
Cls.initClass(); Cls.initClass();

@ -14,17 +14,17 @@ const Cls = (app.Router = class Router {
$.extend(this.prototype, Events); $.extend(this.prototype, Events);
this.routes = [ this.routes = [
['*', 'before' ], ["*", "before"],
['/', 'root' ], ["/", "root"],
['/settings', 'settings' ], ["/settings", "settings"],
['/offline', 'offline' ], ["/offline", "offline"],
['/about', 'about' ], ["/about", "about"],
['/news', 'news' ], ["/news", "news"],
['/help', 'help' ], ["/help", "help"],
['/:doc-:type/', 'type' ], ["/:doc-:type/", "type"],
['/:doc/', 'doc' ], ["/:doc/", "doc"],
['/:doc/:path(*)', 'entry' ], ["/:doc/:path(*)", "entry"],
['*', 'notFound' ] ["*", "notFound"],
]; ];
} }
@ -45,16 +45,16 @@ const Cls = (app.Router = class Router {
triggerRoute(name) { triggerRoute(name) {
this.trigger(name, this.context); this.trigger(name, this.context);
this.trigger('after', name, this.context); this.trigger("after", name, this.context);
} }
before(context, next) { before(context, next) {
let res; let res;
const previousContext = this.context; const previousContext = this.context;
this.context = context; this.context = context;
this.trigger('before', context); this.trigger("before", context);
if (res = next()) { if ((res = next())) {
this.context = previousContext; this.context = previousContext;
return res; return res;
} else { } else {
@ -64,10 +64,14 @@ const Cls = (app.Router = class Router {
doc(context, next) { doc(context, next) {
let doc; let doc;
if (doc = app.docs.findBySlug(context.params.doc) || app.disabledDocs.findBySlug(context.params.doc)) { if (
(doc =
app.docs.findBySlug(context.params.doc) ||
app.disabledDocs.findBySlug(context.params.doc))
) {
context.doc = doc; context.doc = doc;
context.entry = doc.toEntry(); context.entry = doc.toEntry();
this.triggerRoute('entry'); this.triggerRoute("entry");
return; return;
} else { } else {
return next(); return next();
@ -78,10 +82,13 @@ const Cls = (app.Router = class Router {
let type; let type;
const doc = app.docs.findBySlug(context.params.doc); const doc = app.docs.findBySlug(context.params.doc);
if (type = doc != null ? doc.types.findBy('slug', context.params.type) : undefined) { if (
(type =
doc != null ? doc.types.findBy("slug", context.params.type) : undefined)
) {
context.doc = doc; context.doc = doc;
context.type = type; context.type = type;
this.triggerRoute('type'); this.triggerRoute("type");
return; return;
} else { } else {
return next(); return next();
@ -91,86 +98,110 @@ const Cls = (app.Router = class Router {
entry(context, next) { entry(context, next) {
let entry; let entry;
const doc = app.docs.findBySlug(context.params.doc); const doc = app.docs.findBySlug(context.params.doc);
if (!doc) { return next(); } if (!doc) {
let { return next();
path }
} = context.params; let { path } = context.params;
const { const { hash } = context;
hash
} = context; if ((entry = doc.findEntryByPathAndHash(path, hash))) {
if (entry = doc.findEntryByPathAndHash(path, hash)) {
context.doc = doc; context.doc = doc;
context.entry = entry; context.entry = entry;
this.triggerRoute('entry'); this.triggerRoute("entry");
return; return;
} else if (path.slice(-6) === '/index') { } else if (path.slice(-6) === "/index") {
path = path.substr(0, path.length - 6); path = path.substr(0, path.length - 6);
if (entry = doc.findEntryByPathAndHash(path, hash)) { return entry.fullPath(); } if ((entry = doc.findEntryByPathAndHash(path, hash))) {
return entry.fullPath();
}
} else { } else {
path = `${path}/index`; path = `${path}/index`;
if (entry = doc.findEntryByPathAndHash(path, hash)) { return entry.fullPath(); } if ((entry = doc.findEntryByPathAndHash(path, hash))) {
return entry.fullPath();
}
} }
return next(); return next();
} }
root() { root() {
if (app.isSingleDoc()) { return '/'; } if (app.isSingleDoc()) {
this.triggerRoute('root'); return "/";
}
this.triggerRoute("root");
} }
settings(context) { settings(context) {
if (app.isSingleDoc()) { return `/#/${context.path}`; } if (app.isSingleDoc()) {
this.triggerRoute('settings'); return `/#/${context.path}`;
}
this.triggerRoute("settings");
} }
offline(context){ offline(context) {
if (app.isSingleDoc()) { return `/#/${context.path}`; } if (app.isSingleDoc()) {
this.triggerRoute('offline'); return `/#/${context.path}`;
}
this.triggerRoute("offline");
} }
about(context) { about(context) {
if (app.isSingleDoc()) { return `/#/${context.path}`; } if (app.isSingleDoc()) {
context.page = 'about'; return `/#/${context.path}`;
this.triggerRoute('page'); }
context.page = "about";
this.triggerRoute("page");
} }
news(context) { news(context) {
if (app.isSingleDoc()) { return `/#/${context.path}`; } if (app.isSingleDoc()) {
context.page = 'news'; return `/#/${context.path}`;
this.triggerRoute('page'); }
context.page = "news";
this.triggerRoute("page");
} }
help(context) { help(context) {
if (app.isSingleDoc()) { return `/#/${context.path}`; } if (app.isSingleDoc()) {
context.page = 'help'; return `/#/${context.path}`;
this.triggerRoute('page'); }
context.page = "help";
this.triggerRoute("page");
} }
notFound(context) { notFound(context) {
this.triggerRoute('notFound'); this.triggerRoute("notFound");
} }
isIndex() { isIndex() {
return ((this.context != null ? this.context.path : undefined) === '/') || (app.isSingleDoc() && __guard__(this.context != null ? this.context.entry : undefined, x => x.isIndex())); return (
(this.context != null ? this.context.path : undefined) === "/" ||
(app.isSingleDoc() &&
__guard__(this.context != null ? this.context.entry : undefined, (x) =>
x.isIndex(),
))
);
} }
isSettings() { isSettings() {
return (this.context != null ? this.context.path : undefined) === '/settings'; return (
(this.context != null ? this.context.path : undefined) === "/settings"
);
} }
setInitialPath() { setInitialPath() {
// Remove superfluous forward slashes at the beginning of the path // Remove superfluous forward slashes at the beginning of the path
let path; let path;
if ((path = location.pathname.replace(/^\/{2,}/g, '/')) !== location.pathname) { if (
(path = location.pathname.replace(/^\/{2,}/g, "/")) !== location.pathname
) {
page.replace(path + location.search + location.hash, null, true); page.replace(path + location.search + location.hash, null, true);
} }
if (location.pathname === '/') { if (location.pathname === "/") {
if (path = this.getInitialPathFromHash()) { if ((path = this.getInitialPathFromHash())) {
page.replace(path + location.search, null, true); page.replace(path + location.search, null, true);
} else if (path = this.getInitialPathFromCookie()) { } else if ((path = this.getInitialPathFromCookie())) {
page.replace(path + location.search + location.hash, null, true); page.replace(path + location.search + location.hash, null, true);
} }
} }
@ -178,24 +209,33 @@ const Cls = (app.Router = class Router {
getInitialPathFromHash() { getInitialPathFromHash() {
try { try {
return __guard__((new RegExp("#/(.+)")).exec(decodeURIComponent(location.hash)), x => x[1]); return __guard__(
new RegExp("#/(.+)").exec(decodeURIComponent(location.hash)),
(x) => x[1],
);
} catch (error) {} } catch (error) {}
} }
getInitialPathFromCookie() { getInitialPathFromCookie() {
let path; let path;
if (path = Cookies.get('initial_path')) { if ((path = Cookies.get("initial_path"))) {
Cookies.expire('initial_path'); Cookies.expire("initial_path");
return path; return path;
} }
} }
replaceHash(hash) { replaceHash(hash) {
page.replace(location.pathname + location.search + (hash || ''), null, true); page.replace(
location.pathname + location.search + (hash || ""),
null,
true,
);
} }
}); });
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -16,116 +16,150 @@
// Match functions // Match functions
// //
let fuzzyRegexp, i, index, lastIndex, match, matcher, matchIndex, matchLength, queryLength, score, separators, value, valueLength; let fuzzyRegexp,
const SEPARATOR = '.'; i,
index,
lastIndex,
match,
matcher,
matchIndex,
matchLength,
queryLength,
score,
separators,
value,
valueLength;
const SEPARATOR = ".";
let query = let query =
(queryLength = (queryLength =
(value = value =
(valueLength = valueLength =
(matcher = // current match function matcher = // current match function
(fuzzyRegexp = // query fuzzy regexp fuzzyRegexp = // query fuzzy regexp
(index = // position of the query in the string being matched index = // position of the query in the string being matched
(lastIndex = // last position of the query in the string being matched lastIndex = // last position of the query in the string being matched
(match = // regexp match data match = // regexp match data
(matchIndex = matchIndex =
(matchLength = matchLength =
(score = // score for the current match score = // score for the current match
(separators = // counter separators = // counter
(i = null))))))))))))); // cursor i =
null); // cursor
function exactMatch() { function exactMatch() {
index = value.indexOf(query); index = value.indexOf(query);
if (!(index >= 0)) { return; } if (!(index >= 0)) {
return;
}
lastIndex = value.lastIndexOf(query); lastIndex = value.lastIndexOf(query);
if (index !== lastIndex) { if (index !== lastIndex) {
return Math.max(scoreExactMatch(), ((index = lastIndex) && scoreExactMatch()) || 0); return Math.max(
} else { scoreExactMatch(),
return scoreExactMatch(); ((index = lastIndex) && scoreExactMatch()) || 0,
} );
} else {
return scoreExactMatch();
}
} }
function scoreExactMatch() { function scoreExactMatch() {
// Remove one point for each unmatched character. // Remove one point for each unmatched character.
score = 100 - (valueLength - queryLength); score = 100 - (valueLength - queryLength);
if (index > 0) { if (index > 0) {
// If the character preceding the query is a dot, assign the same score // If the character preceding the query is a dot, assign the same score
// as if the query was found at the beginning of the string, minus one. // as if the query was found at the beginning of the string, minus one.
if (value.charAt(index - 1) === SEPARATOR) { if (value.charAt(index - 1) === SEPARATOR) {
score += index - 1; score += index - 1;
// Don't match a single-character query unless it's found at the beginning // Don't match a single-character query unless it's found at the beginning
// of the string or is preceded by a dot. // of the string or is preceded by a dot.
} else if (queryLength === 1) { } else if (queryLength === 1) {
return; return;
// (1) Remove one point for each unmatched character up to the nearest // (1) Remove one point for each unmatched character up to the nearest
// preceding dot or the beginning of the string. // preceding dot or the beginning of the string.
// (2) Remove one point for each unmatched character following the query. // (2) Remove one point for each unmatched character following the query.
} else { } else {
i = index - 2;
while (i >= 0 && value.charAt(i) !== SEPARATOR) {
i--;
}
score -=
index -
i + // (1)
(valueLength - queryLength - index); // (2)
}
// Remove one point for each dot preceding the query, except for the one
// immediately before the query.
separators = 0;
i = index - 2; i = index - 2;
while ((i >= 0) && (value.charAt(i) !== SEPARATOR)) { i--; } while (i >= 0) {
score -= (index - i) + // (1) if (value.charAt(i) === SEPARATOR) {
(valueLength - queryLength - index); // (2) separators++;
}
i--;
}
score -= separators;
} }
// Remove one point for each dot preceding the query, except for the one // Remove five points for each dot following the query.
// immediately before the query.
separators = 0; separators = 0;
i = index - 2; i = valueLength - queryLength - index - 1;
while (i >= 0) { while (i >= 0) {
if (value.charAt(i) === SEPARATOR) { separators++; } if (value.charAt(index + queryLength + i) === SEPARATOR) {
separators++;
}
i--; i--;
} }
score -= separators; score -= separators * 5;
}
// Remove five points for each dot following the query. return Math.max(1, score);
separators = 0;
i = valueLength - queryLength - index - 1;
while (i >= 0) {
if (value.charAt(index + queryLength + i) === SEPARATOR) { separators++; }
i--;
}
score -= separators * 5;
return Math.max(1, score);
} }
function fuzzyMatch() { function fuzzyMatch() {
if ((valueLength <= queryLength) || (value.indexOf(query) >= 0)) { return; } if (valueLength <= queryLength || value.indexOf(query) >= 0) {
if (!(match = fuzzyRegexp.exec(value))) { return; } return;
matchIndex = match.index; }
matchLength = match[0].length; if (!(match = fuzzyRegexp.exec(value))) {
score = scoreFuzzyMatch(); return;
if (match = fuzzyRegexp.exec(value.slice(i = value.lastIndexOf(SEPARATOR) + 1))) { }
matchIndex = i + match.index; matchIndex = match.index;
matchLength = match[0].length; matchLength = match[0].length;
return Math.max(score, scoreFuzzyMatch()); score = scoreFuzzyMatch();
} else { if (
return score; (match = fuzzyRegexp.exec(
} value.slice((i = value.lastIndexOf(SEPARATOR) + 1)),
))
) {
matchIndex = i + match.index;
matchLength = match[0].length;
return Math.max(score, scoreFuzzyMatch());
} else {
return score;
}
} }
function scoreFuzzyMatch() { function scoreFuzzyMatch() {
// When the match is at the beginning of the string or preceded by a dot. // When the match is at the beginning of the string or preceded by a dot.
if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) { if (matchIndex === 0 || value.charAt(matchIndex - 1) === SEPARATOR) {
return Math.max(66, 100 - matchLength); return Math.max(66, 100 - matchLength);
// When the match is at the end of the string. // When the match is at the end of the string.
} else if ((matchIndex + matchLength) === valueLength) { } else if (matchIndex + matchLength === valueLength) {
return Math.max(33, 67 - matchLength); return Math.max(33, 67 - matchLength);
// When the match is in the middle of the string. // When the match is in the middle of the string.
} else { } else {
return Math.max(1, 34 - matchLength); return Math.max(1, 34 - matchLength);
} }
} }
// //
// Searchers // Searchers
// //
(function() { (function () {
let CHUNK_SIZE = undefined; let CHUNK_SIZE = undefined;
let DEFAULTS = undefined; let DEFAULTS = undefined;
let SEPARATORS_REGEXP = undefined; let SEPARATORS_REGEXP = undefined;
@ -146,10 +180,11 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
DEFAULTS = { DEFAULTS = {
max_results: app.config.max_results, max_results: app.config.max_results,
fuzzy_min_length: 3 fuzzy_min_length: 3,
}; };
SEPARATORS_REGEXP = /#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g; SEPARATORS_REGEXP =
/#|::|:-|->|\$(?=\w)|\-(?=\w)|\:(?=\w)|\ [\/\-&]\ |:\ |\ /g;
EOS_SEPARATORS_REGEXP = /(\w)[\-:]$/; EOS_SEPARATORS_REGEXP = /(\w)[\-:]$/;
INFO_PARANTHESES_REGEXP = /\ \(\w+?\)$/; INFO_PARANTHESES_REGEXP = /\ \(\w+?\)$/;
EMPTY_PARANTHESES_REGEXP = /\(\)/; EMPTY_PARANTHESES_REGEXP = /\(\)/;
@ -157,9 +192,9 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
DOT_REGEXP = /\.+/g; DOT_REGEXP = /\.+/g;
WHITESPACE_REGEXP = /\s/g; WHITESPACE_REGEXP = /\s/g;
EMPTY_STRING = ''; EMPTY_STRING = "";
ELLIPSIS = '...'; ELLIPSIS = "...";
STRING = 'string'; STRING = "string";
} }
static normalizeString(string) { static normalizeString(string) {
@ -176,13 +211,15 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
static normalizeQuery(string) { static normalizeQuery(string) {
string = this.normalizeString(string); string = this.normalizeString(string);
return string.replace(EOS_SEPARATORS_REGEXP, '$1.'); return string.replace(EOS_SEPARATORS_REGEXP, "$1.");
} }
constructor(options) { constructor(options) {
this.match = this.match.bind(this); this.match = this.match.bind(this);
this.matchChunks = this.matchChunks.bind(this); this.matchChunks = this.matchChunks.bind(this);
if (options == null) { options = {}; } if (options == null) {
options = {};
}
this.options = $.extend({}, DEFAULTS, options); this.options = $.extend({}, DEFAULTS, options);
} }
@ -194,11 +231,15 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
this.query = q; this.query = q;
this.setup(); this.setup();
if (this.isValid()) { this.match(); } else { this.end(); } if (this.isValid()) {
this.match();
} else {
this.end();
}
} }
setup() { setup() {
query = (this.query = this.constructor.normalizeQuery(this.query)); query = this.query = this.constructor.normalizeQuery(this.query);
queryLength = query.length; queryLength = query.length;
this.dataLength = this.data.length; this.dataLength = this.data.length;
this.matchers = [exactMatch]; this.matchers = [exactMatch];
@ -216,12 +257,14 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
} }
isValid() { isValid() {
return (queryLength > 0) && (query !== SEPARATOR); return queryLength > 0 && query !== SEPARATOR;
} }
end() { end() {
if (!this.totalResults) { this.triggerResults([]); } if (!this.totalResults) {
this.trigger('end'); this.triggerResults([]);
}
this.trigger("end");
this.free(); this.free();
} }
@ -233,8 +276,17 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
} }
free() { free() {
this.data = (this.attr = (this.dataLength = (this.matchers = (this.matcher = (this.query = this.data =
(this.totalResults = (this.scoreMap = (this.cursor = (this.timeout = null))))))))); this.attr =
this.dataLength =
this.matchers =
this.matcher =
this.query =
this.totalResults =
this.scoreMap =
this.cursor =
this.timeout =
null;
} }
match() { match() {
@ -254,7 +306,7 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
matchChunks() { matchChunks() {
this.matchChunk(); this.matchChunk();
if ((this.cursor === this.dataLength) || this.scoredEnough()) { if (this.cursor === this.dataLength || this.scoredEnough()) {
this.delay(this.match); this.delay(this.match);
this.sendResults(); this.sendResults();
} else { } else {
@ -263,28 +315,36 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
} }
matchChunk() { matchChunk() {
({ ({ matcher } = this);
matcher for (
} = this); let j = 0, end = this.chunkSize(), asc = 0 <= end;
for (let j = 0, end = this.chunkSize(), asc = 0 <= end; asc ? j < end : j > end; asc ? j++ : j--) { asc ? j < end : j > end;
asc ? j++ : j--
) {
value = this.data[this.cursor][this.attr]; value = this.data[this.cursor][this.attr];
if (value.split) { // string if (value.split) {
// string
valueLength = value.length; valueLength = value.length;
if (score = matcher()) { this.addResult(this.data[this.cursor], score); } if ((score = matcher())) {
} else { // array this.addResult(this.data[this.cursor], score);
}
} else {
// array
score = 0; score = 0;
for (value of Array.from(this.data[this.cursor][this.attr])) { for (value of Array.from(this.data[this.cursor][this.attr])) {
valueLength = value.length; valueLength = value.length;
score = Math.max(score, matcher() || 0); score = Math.max(score, matcher() || 0);
} }
if (score > 0) { this.addResult(this.data[this.cursor], score); } if (score > 0) {
this.addResult(this.data[this.cursor], score);
}
} }
this.cursor++; this.cursor++;
} }
} }
chunkSize() { chunkSize() {
if ((this.cursor + CHUNK_SIZE) > this.dataLength) { if (this.cursor + CHUNK_SIZE > this.dataLength) {
return this.dataLength % CHUNK_SIZE; return this.dataLength % CHUNK_SIZE;
} else { } else {
return CHUNK_SIZE; return CHUNK_SIZE;
@ -292,8 +352,11 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
} }
scoredEnough() { scoredEnough() {
return (this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >= this.options.max_results; return (
} (this.scoreMap[100] != null ? this.scoreMap[100].length : undefined) >=
this.options.max_results
);
}
foundEnough() { foundEnough() {
return this.totalResults >= this.options.max_results; return this.totalResults >= this.options.max_results;
@ -301,7 +364,9 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
addResult(object, score) { addResult(object, score) {
let name; let name;
(this.scoreMap[name = Math.round(score)] || (this.scoreMap[name] = [])).push(object); (
this.scoreMap[(name = Math.round(score))] || (this.scoreMap[name] = [])
).push(object);
this.totalResults++; this.totalResults++;
} }
@ -318,21 +383,26 @@ if ((matchIndex === 0) || (value.charAt(matchIndex - 1) === SEPARATOR)) {
sendResults() { sendResults() {
const results = this.getResults(); const results = this.getResults();
if (results.length) { this.triggerResults(results); } if (results.length) {
this.triggerResults(results);
}
} }
triggerResults(results) { triggerResults(results) {
this.trigger('results', results); this.trigger("results", results);
} }
delay(fn) { delay(fn) {
return this.timeout = setTimeout(fn, 1); return (this.timeout = setTimeout(fn, 1));
} }
queryToFuzzyRegexp(string) { queryToFuzzyRegexp(string) {
const chars = string.split(''); const chars = string.split("");
for (i = 0; i < chars.length; i++) { var char = chars[i]; chars[i] = $.escapeRegexp(char); } for (i = 0; i < chars.length; i++) {
return new RegExp(chars.join('.*?')); var char = chars[i];
chars[i] = $.escapeRegexp(char);
}
return new RegExp(chars.join(".*?"));
} }
}); });
Cls.initClass(); Cls.initClass();
@ -347,7 +417,9 @@ app.SynchronousSearcher = class SynchronousSearcher extends app.Searcher {
match() { match() {
if (this.matcher) { if (this.matcher) {
if (!this.allResults) { this.allResults = []; } if (!this.allResults) {
this.allResults = [];
}
this.allResults.push.apply(this.allResults, this.getResults()); this.allResults.push.apply(this.allResults, this.getResults());
} }
return super.match(...arguments); return super.match(...arguments);

@ -21,22 +21,28 @@ const Cls = (app.ServiceWorker = class ServiceWorker {
this.registration = null; this.registration = null;
this.notifyUpdate = true; this.notifyUpdate = true;
navigator.serviceWorker.register(app.config.service_worker_path, {scope: '/'}) navigator.serviceWorker
.register(app.config.service_worker_path, { scope: "/" })
.then( .then(
registration => this.updateRegistration(registration), (registration) => this.updateRegistration(registration),
error => console.error('Could not register service worker:', error)); (error) => console.error("Could not register service worker:", error),
);
} }
update() { update() {
if (!this.registration) { return; } if (!this.registration) {
return;
}
this.notifyUpdate = true; this.notifyUpdate = true;
return this.registration.update().catch(function() {}); return this.registration.update().catch(function () {});
} }
updateInBackground() { updateInBackground() {
if (!this.registration) { return; } if (!this.registration) {
return;
}
this.notifyUpdate = false; this.notifyUpdate = false;
return this.registration.update().catch(function() {}); return this.registration.update().catch(function () {});
} }
reload() { reload() {
@ -45,24 +51,32 @@ const Cls = (app.ServiceWorker = class ServiceWorker {
updateRegistration(registration) { updateRegistration(registration) {
this.registration = registration; this.registration = registration;
$.on(this.registration, 'updatefound', this.onUpdateFound); $.on(this.registration, "updatefound", this.onUpdateFound);
} }
onUpdateFound() { onUpdateFound() {
if (this.installingRegistration) { $.off(this.installingRegistration, 'statechange', this.onStateChange()); } if (this.installingRegistration) {
$.off(this.installingRegistration, "statechange", this.onStateChange());
}
this.installingRegistration = this.registration.installing; this.installingRegistration = this.registration.installing;
$.on(this.installingRegistration, 'statechange', this.onStateChange); $.on(this.installingRegistration, "statechange", this.onStateChange);
} }
onStateChange() { onStateChange() {
if (this.installingRegistration && (this.installingRegistration.state === 'installed') && navigator.serviceWorker.controller) { if (
this.installingRegistration &&
this.installingRegistration.state === "installed" &&
navigator.serviceWorker.controller
) {
this.installingRegistration = null; this.installingRegistration = null;
this.onUpdateReady(); this.onUpdateReady();
} }
} }
onUpdateReady() { onUpdateReady() {
if (this.notifyUpdate) { this.trigger('updateready'); } if (this.notifyUpdate) {
this.trigger("updateready");
}
} }
}); });
Cls.initClass(); Cls.initClass();

@ -10,42 +10,37 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let PREFERENCE_KEYS = undefined; let PREFERENCE_KEYS = undefined;
let INTERNAL_KEYS = undefined; let INTERNAL_KEYS = undefined;
const Cls = (app.Settings = class Settings { const Cls = (app.Settings = class Settings {
static initClass() { static initClass() {
PREFERENCE_KEYS = [ PREFERENCE_KEYS = [
'hideDisabled', "hideDisabled",
'hideIntro', "hideIntro",
'manualUpdate', "manualUpdate",
'fastScroll', "fastScroll",
'arrowScroll', "arrowScroll",
'analyticsConsent', "analyticsConsent",
'docs', "docs",
'dark', // legacy "dark", // legacy
'theme', "theme",
'layout', "layout",
'size', "size",
'tips', "tips",
'noAutofocus', "noAutofocus",
'autoInstall', "autoInstall",
'spaceScroll', "spaceScroll",
'spaceTimeout' "spaceTimeout",
]; ];
INTERNAL_KEYS = [ INTERNAL_KEYS = ["count", "schema", "version", "news"];
'count',
'schema',
'version',
'news'
];
this.prototype.LAYOUTS = [ this.prototype.LAYOUTS = [
'_max-width', "_max-width",
'_sidebar-hidden', "_sidebar-hidden",
'_native-scrollbars', "_native-scrollbars",
'_text-justify-hyphenate' "_text-justify-hyphenate",
]; ];
this.defaults = { this.defaults = {
@ -56,29 +51,38 @@
manualUpdate: false, manualUpdate: false,
schema: 1, schema: 1,
analyticsConsent: false, analyticsConsent: false,
theme: 'auto', theme: "auto",
spaceScroll: 1, spaceScroll: 1,
spaceTimeout: 0.5 spaceTimeout: 0.5,
}; };
} }
constructor() { constructor() {
this.store = new CookiesStore; this.store = new CookiesStore();
this.cache = {}; this.cache = {};
this.autoSupported = window.matchMedia('(prefers-color-scheme)').media !== 'not all'; this.autoSupported =
window.matchMedia("(prefers-color-scheme)").media !== "not all";
if (this.autoSupported) { if (this.autoSupported) {
this.darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); this.darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
this.darkModeQuery.addListener(() => this.setTheme(this.get('theme'))); this.darkModeQuery.addListener(() => this.setTheme(this.get("theme")));
} }
} }
get(key) { get(key) {
let left; let left;
if (this.cache.hasOwnProperty(key)) { return this.cache[key]; } if (this.cache.hasOwnProperty(key)) {
this.cache[key] = (left = this.store.get(key)) != null ? left : this.constructor.defaults[key]; return this.cache[key];
if ((key === 'theme') && (this.cache[key] === 'auto') && !this.darkModeQuery) { }
return this.cache[key] = 'default'; this.cache[key] =
(left = this.store.get(key)) != null
? left
: this.constructor.defaults[key];
if (
key === "theme" &&
this.cache[key] === "auto" &&
!this.darkModeQuery
) {
return (this.cache[key] = "default");
} else { } else {
return this.cache[key]; return this.cache[key];
} }
@ -87,7 +91,9 @@
set(key, value) { set(key, value) {
this.store.set(key, value); this.store.set(key, value);
delete this.cache[key]; delete this.cache[key];
if (key === 'theme') { this.setTheme(value); } if (key === "theme") {
this.setTheme(value);
}
} }
del(key) { del(key) {
@ -96,51 +102,58 @@
} }
hasDocs() { hasDocs() {
try { return !!this.store.get('docs'); } catch (error) {} try {
return !!this.store.get("docs");
} catch (error) {}
} }
getDocs() { getDocs() {
return __guard__(this.store.get('docs'), x => x.split('/')) || app.config.default_docs; return (
__guard__(this.store.get("docs"), (x) => x.split("/")) ||
app.config.default_docs
);
} }
setDocs(docs) { setDocs(docs) {
this.set('docs', docs.join('/')); this.set("docs", docs.join("/"));
} }
getTips() { getTips() {
return __guard__(this.store.get('tips'), x => x.split('/')) || []; return __guard__(this.store.get("tips"), (x) => x.split("/")) || [];
} }
setTips(tips) { setTips(tips) {
this.set('tips', tips.join('/')); this.set("tips", tips.join("/"));
} }
setLayout(name, enable) { setLayout(name, enable) {
this.toggleLayout(name, enable); this.toggleLayout(name, enable);
const layout = (this.store.get('layout') || '').split(' '); const layout = (this.store.get("layout") || "").split(" ");
$.arrayDelete(layout, ''); $.arrayDelete(layout, "");
if (enable) { if (enable) {
if (layout.indexOf(name) === -1) { layout.push(name); } if (layout.indexOf(name) === -1) {
layout.push(name);
}
} else { } else {
$.arrayDelete(layout, name); $.arrayDelete(layout, name);
} }
if (layout.length > 0) { if (layout.length > 0) {
this.set('layout', layout.join(' ')); this.set("layout", layout.join(" "));
} else { } else {
this.del('layout'); this.del("layout");
} }
} }
hasLayout(name) { hasLayout(name) {
const layout = (this.store.get('layout') || '').split(' '); const layout = (this.store.get("layout") || "").split(" ");
return layout.indexOf(name) !== -1; return layout.indexOf(name) !== -1;
} }
setSize(value) { setSize(value) {
this.set('size', value); this.set("size", value);
} }
dump() { dump() {
@ -149,7 +162,9 @@
export() { export() {
const data = this.dump(); const data = this.dump();
for (var key of Array.from(INTERNAL_KEYS)) { delete data[key]; } for (var key of Array.from(INTERNAL_KEYS)) {
delete data[key];
}
return data; return data;
} }
@ -158,11 +173,15 @@
const object = this.export(); const object = this.export();
for (key in object) { for (key in object) {
value = object[key]; value = object[key];
if (!data.hasOwnProperty(key)) { this.del(key); } if (!data.hasOwnProperty(key)) {
this.del(key);
}
} }
for (key in data) { for (key in data) {
value = data[key]; value = data[key];
if (PREFERENCE_KEYS.indexOf(key) !== -1) { this.set(key, value); } if (PREFERENCE_KEYS.indexOf(key) !== -1) {
this.set(key, value);
}
} }
} }
@ -172,44 +191,54 @@
} }
initLayout() { initLayout() {
if (this.get('dark') === 1) { if (this.get("dark") === 1) {
this.set('theme', 'dark'); this.set("theme", "dark");
this.del('dark'); this.del("dark");
}
this.setTheme(this.get("theme"));
for (var layout of Array.from(this.LAYOUTS)) {
this.toggleLayout(layout, this.hasLayout(layout));
} }
this.setTheme(this.get('theme'));
for (var layout of Array.from(this.LAYOUTS)) { this.toggleLayout(layout, this.hasLayout(layout)); }
this.initSidebarWidth(); this.initSidebarWidth();
} }
setTheme(theme) { setTheme(theme) {
if (theme === 'auto') { if (theme === "auto") {
theme = this.darkModeQuery.matches ? 'dark' : 'default'; theme = this.darkModeQuery.matches ? "dark" : "default";
} }
const { const { classList } = document.documentElement;
classList classList.remove("_theme-default", "_theme-dark");
} = document.documentElement; classList.add("_theme-" + theme);
classList.remove('_theme-default', '_theme-dark');
classList.add('_theme-' + theme);
this.updateColorMeta(); this.updateColorMeta();
} }
updateColorMeta() { updateColorMeta() {
const color = getComputedStyle(document.documentElement).getPropertyValue('--headerBackground').trim(); const color = getComputedStyle(document.documentElement)
$('meta[name=theme-color]').setAttribute('content', color); .getPropertyValue("--headerBackground")
.trim();
$("meta[name=theme-color]").setAttribute("content", color);
} }
toggleLayout(layout, enable) { toggleLayout(layout, enable) {
const { const { classList } = document.body;
classList
} = document.body;
// sidebar is always shown for settings; its state is updated in app.views.Settings // sidebar is always shown for settings; its state is updated in app.views.Settings
if ((layout !== '_sidebar-hidden') || !(app.router != null ? app.router.isSettings : undefined)) { classList.toggle(layout, enable); } if (
classList.toggle('_overlay-scrollbars', $.overlayScrollbarsEnabled()); layout !== "_sidebar-hidden" ||
!(app.router != null ? app.router.isSettings : undefined)
) {
classList.toggle(layout, enable);
}
classList.toggle("_overlay-scrollbars", $.overlayScrollbarsEnabled());
} }
initSidebarWidth() { initSidebarWidth() {
const size = this.get('size'); const size = this.get("size");
if (size) { document.documentElement.style.setProperty('--sidebarWidth', size + 'px'); } if (size) {
document.documentElement.style.setProperty(
"--sidebarWidth",
size + "px",
);
}
} }
}); });
Cls.initClass(); Cls.initClass();
@ -217,5 +246,7 @@
})(); })();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -21,111 +21,151 @@ const Cls = (app.Shortcuts = class Shortcuts {
} }
start() { start() {
$.on(document, 'keydown', this.onKeydown); $.on(document, "keydown", this.onKeydown);
$.on(document, 'keypress', this.onKeypress); $.on(document, "keypress", this.onKeypress);
} }
stop() { stop() {
$.off(document, 'keydown', this.onKeydown); $.off(document, "keydown", this.onKeydown);
$.off(document, 'keypress', this.onKeypress); $.off(document, "keypress", this.onKeypress);
} }
swapArrowKeysBehavior() { swapArrowKeysBehavior() {
return app.settings.get('arrowScroll'); return app.settings.get("arrowScroll");
} }
spaceScroll() { spaceScroll() {
return app.settings.get('spaceScroll'); return app.settings.get("spaceScroll");
} }
showTip() { showTip() {
app.showTip('KeyNav'); app.showTip("KeyNav");
return this.showTip = null; return (this.showTip = null);
} }
spaceTimeout() { spaceTimeout() {
return app.settings.get('spaceTimeout'); return app.settings.get("spaceTimeout");
} }
onKeydown(event) { onKeydown(event) {
if (this.buggyEvent(event)) { return; } if (this.buggyEvent(event)) {
return;
}
const result = (() => { const result = (() => {
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
if (!event.altKey && !event.shiftKey) { return this.handleKeydownSuperEvent(event); } if (!event.altKey && !event.shiftKey) {
} else if (event.shiftKey) { return this.handleKeydownSuperEvent(event);
if (!event.altKey) { return this.handleKeydownShiftEvent(event); } }
} else if (event.altKey) { } else if (event.shiftKey) {
return this.handleKeydownAltEvent(event); if (!event.altKey) {
} else { return this.handleKeydownShiftEvent(event);
return this.handleKeydownEvent(event); }
} } else if (event.altKey) {
return this.handleKeydownAltEvent(event);
} else {
return this.handleKeydownEvent(event);
}
})(); })();
if (result === false) { event.preventDefault(); } if (result === false) {
event.preventDefault();
}
} }
onKeypress(event) { onKeypress(event) {
if (this.buggyEvent(event) || ((event.charCode === 63) && (document.activeElement.tagName === 'INPUT'))) { return; } if (
this.buggyEvent(event) ||
(event.charCode === 63 && document.activeElement.tagName === "INPUT")
) {
return;
}
if (!event.ctrlKey && !event.metaKey) { if (!event.ctrlKey && !event.metaKey) {
const result = this.handleKeypressEvent(event); const result = this.handleKeypressEvent(event);
if (result === false) { event.preventDefault(); } if (result === false) {
event.preventDefault();
}
} }
} }
handleKeydownEvent(event, _force) { handleKeydownEvent(event, _force) {
if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownAltEvent(event, true); } if (
!_force &&
[37, 38, 39, 40].includes(event.which) &&
this.swapArrowKeysBehavior()
) {
return this.handleKeydownAltEvent(event, true);
}
if (!event.target.form && ((48 <= event.which && event.which <= 57) || (65 <= event.which && event.which <= 90))) { if (
this.trigger('typing'); !event.target.form &&
((48 <= event.which && event.which <= 57) ||
(65 <= event.which && event.which <= 90))
) {
this.trigger("typing");
return; return;
} }
switch (event.which) { switch (event.which) {
case 8: case 8:
if (!event.target.form) { return this.trigger('typing'); } if (!event.target.form) {
return this.trigger("typing");
}
break; break;
case 13: case 13:
return this.trigger('enter'); return this.trigger("enter");
case 27: case 27:
this.trigger('escape'); this.trigger("escape");
return false; return false;
case 32: case 32:
if ((event.target.type === 'search') && this.spaceScroll() && (!this.lastKeypress || (this.lastKeypress < (Date.now() - (this.spaceTimeout() * 1000))))) { if (
this.trigger('pageDown'); event.target.type === "search" &&
this.spaceScroll() &&
(!this.lastKeypress ||
this.lastKeypress < Date.now() - this.spaceTimeout() * 1000)
) {
this.trigger("pageDown");
return false; return false;
} }
break; break;
case 33: case 33:
return this.trigger('pageUp'); return this.trigger("pageUp");
case 34: case 34:
return this.trigger('pageDown'); return this.trigger("pageDown");
case 35: case 35:
if (!event.target.form) { return this.trigger('pageBottom'); } if (!event.target.form) {
return this.trigger("pageBottom");
}
break; break;
case 36: case 36:
if (!event.target.form) { return this.trigger('pageTop'); } if (!event.target.form) {
return this.trigger("pageTop");
}
break; break;
case 37: case 37:
if (!event.target.value) { return this.trigger('left'); } if (!event.target.value) {
return this.trigger("left");
}
break; break;
case 38: case 38:
this.trigger('up'); this.trigger("up");
if (typeof this.showTip === 'function') { if (typeof this.showTip === "function") {
this.showTip(); this.showTip();
} }
return false; return false;
case 39: case 39:
if (!event.target.value) { return this.trigger('right'); } if (!event.target.value) {
return this.trigger("right");
}
break; break;
case 40: case 40:
this.trigger('down'); this.trigger("down");
if (typeof this.showTip === 'function') { if (typeof this.showTip === "function") {
this.showTip(); this.showTip();
} }
return false; return false;
case 191: case 191:
if (!event.target.form) { if (!event.target.form) {
this.trigger('typing'); this.trigger("typing");
return false; return false;
} }
break; break;
@ -135,52 +175,58 @@ const Cls = (app.Shortcuts = class Shortcuts {
handleKeydownSuperEvent(event) { handleKeydownSuperEvent(event) {
switch (event.which) { switch (event.which) {
case 13: case 13:
return this.trigger('superEnter'); return this.trigger("superEnter");
case 37: case 37:
if (this.isMac) { if (this.isMac) {
this.trigger('superLeft'); this.trigger("superLeft");
return false; return false;
} }
break; break;
case 38: case 38:
this.trigger('pageTop'); this.trigger("pageTop");
return false; return false;
case 39: case 39:
if (this.isMac) { if (this.isMac) {
this.trigger('superRight'); this.trigger("superRight");
return false; return false;
} }
break; break;
case 40: case 40:
this.trigger('pageBottom'); this.trigger("pageBottom");
return false; return false;
case 188: case 188:
this.trigger('preferences'); this.trigger("preferences");
return false; return false;
} }
} }
handleKeydownShiftEvent(event, _force) { handleKeydownShiftEvent(event, _force) {
if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownEvent(event, true); } if (
!_force &&
[37, 38, 39, 40].includes(event.which) &&
this.swapArrowKeysBehavior()
) {
return this.handleKeydownEvent(event, true);
}
if (!event.target.form && (65 <= event.which && event.which <= 90)) { if (!event.target.form && 65 <= event.which && event.which <= 90) {
this.trigger('typing'); this.trigger("typing");
return; return;
} }
switch (event.which) { switch (event.which) {
case 32: case 32:
this.trigger('pageUp'); this.trigger("pageUp");
return false; return false;
case 38: case 38:
if (!__guard__(getSelection(), x => x.toString())) { if (!__guard__(getSelection(), (x) => x.toString())) {
this.trigger('altUp'); this.trigger("altUp");
return false; return false;
} }
break; break;
case 40: case 40:
if (!__guard__(getSelection(), x1 => x1.toString())) { if (!__guard__(getSelection(), (x1) => x1.toString())) {
this.trigger('altDown'); this.trigger("altDown");
return false; return false;
} }
break; break;
@ -188,58 +234,64 @@ const Cls = (app.Shortcuts = class Shortcuts {
} }
handleKeydownAltEvent(event, _force) { handleKeydownAltEvent(event, _force) {
if (!_force && [37, 38, 39, 40].includes(event.which) && this.swapArrowKeysBehavior()) { return this.handleKeydownEvent(event, true); } if (
!_force &&
[37, 38, 39, 40].includes(event.which) &&
this.swapArrowKeysBehavior()
) {
return this.handleKeydownEvent(event, true);
}
switch (event.which) { switch (event.which) {
case 9: case 9:
return this.trigger('altRight', event); return this.trigger("altRight", event);
case 37: case 37:
if (!this.isMac) { if (!this.isMac) {
this.trigger('superLeft'); this.trigger("superLeft");
return false; return false;
} }
break; break;
case 38: case 38:
this.trigger('altUp'); this.trigger("altUp");
return false; return false;
case 39: case 39:
if (!this.isMac) { if (!this.isMac) {
this.trigger('superRight'); this.trigger("superRight");
return false; return false;
} }
break; break;
case 40: case 40:
this.trigger('altDown'); this.trigger("altDown");
return false; return false;
case 67: case 67:
this.trigger('altC'); this.trigger("altC");
return false; return false;
case 68: case 68:
this.trigger('altD'); this.trigger("altD");
return false; return false;
case 70: case 70:
return this.trigger('altF', event); return this.trigger("altF", event);
case 71: case 71:
this.trigger('altG'); this.trigger("altG");
return false; return false;
case 79: case 79:
this.trigger('altO'); this.trigger("altO");
return false; return false;
case 82: case 82:
this.trigger('altR'); this.trigger("altR");
return false; return false;
case 83: case 83:
this.trigger('altS'); this.trigger("altS");
return false; return false;
} }
} }
handleKeypressEvent(event) { handleKeypressEvent(event) {
if ((event.which === 63) && !event.target.value) { if (event.which === 63 && !event.target.value) {
this.trigger('help'); this.trigger("help");
return false; return false;
} else { } else {
return this.lastKeypress = Date.now(); return (this.lastKeypress = Date.now());
} }
} }
@ -257,5 +309,7 @@ const Cls = (app.Shortcuts = class Shortcuts {
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -11,9 +11,9 @@ app.UpdateChecker = class UpdateChecker {
this.onFocus = this.onFocus.bind(this); this.onFocus = this.onFocus.bind(this);
this.lastCheck = Date.now(); this.lastCheck = Date.now();
$.on(window, 'focus', this.onFocus); $.on(window, "focus", this.onFocus);
if (app.serviceWorker != null) { if (app.serviceWorker != null) {
app.serviceWorker.on('updateready', this.onUpdateReady); app.serviceWorker.on("updateready", this.onUpdateReady);
} }
setTimeout(this.checkDocs, 0); setTimeout(this.checkDocs, 0);
@ -24,31 +24,39 @@ app.UpdateChecker = class UpdateChecker {
app.serviceWorker.update(); app.serviceWorker.update();
} else { } else {
ajax({ ajax({
url: $('script[src*="application"]').getAttribute('src'), url: $('script[src*="application"]').getAttribute("src"),
dataType: 'application/javascript', dataType: "application/javascript",
error: (_, xhr) => { if (xhr.status === 404) { return this.onUpdateReady(); } } error: (_, xhr) => {
if (xhr.status === 404) {
return this.onUpdateReady();
}
},
}); });
} }
} }
onUpdateReady() { onUpdateReady() {
new app.views.Notif('UpdateReady', {autoHide: null}); new app.views.Notif("UpdateReady", { autoHide: null });
} }
checkDocs() { checkDocs() {
if (!app.settings.get('manualUpdate')) { if (!app.settings.get("manualUpdate")) {
app.docs.updateInBackground(); app.docs.updateInBackground();
} else { } else {
app.docs.checkForUpdates(i => { if (i > 0) { return this.onDocsUpdateReady(); } }); app.docs.checkForUpdates((i) => {
if (i > 0) {
return this.onDocsUpdateReady();
}
});
} }
} }
onDocsUpdateReady() { onDocsUpdateReady() {
new app.views.Notif('UpdateDocs', {autoHide: null}); new app.views.Notif("UpdateDocs", { autoHide: null });
} }
onFocus() { onFocus() {
if ((Date.now() - this.lastCheck) > 21600e3) { if (Date.now() - this.lastCheck > 21600e3) {
this.lastCheck = Date.now(); this.lastCheck = Date.now();
this.check(); this.check();
} }

@ -27,8 +27,8 @@
//= require tracking //= require tracking
var init = function() { var init = function () {
document.removeEventListener('DOMContentLoaded', init, false); document.removeEventListener("DOMContentLoaded", init, false);
if (document.body) { if (document.body) {
return app.init(); return app.init();
@ -37,4 +37,4 @@ var init = function() {
} }
}; };
document.addEventListener('DOMContentLoaded', init, false); document.addEventListener("DOMContentLoaded", init, false);

@ -9,7 +9,9 @@
*/ */
app.Collection = class Collection { app.Collection = class Collection {
constructor(objects) { constructor(objects) {
if (objects == null) { objects = []; } if (objects == null) {
objects = [];
}
this.reset(objects); this.reset(objects);
} }
@ -18,16 +20,22 @@ app.Collection = class Collection {
} }
reset(objects) { reset(objects) {
if (objects == null) { objects = []; } if (objects == null) {
objects = [];
}
this.models = []; this.models = [];
for (var object of Array.from(objects)) { this.add(object); } for (var object of Array.from(objects)) {
this.add(object);
}
} }
add(object) { add(object) {
if (object instanceof app.Model) { if (object instanceof app.Model) {
this.models.push(object); this.models.push(object);
} else if (object instanceof Array) { } else if (object instanceof Array) {
for (var obj of Array.from(object)) { this.add(obj); } for (var obj of Array.from(object)) {
this.add(obj);
}
} else if (object instanceof app.Collection) { } else if (object instanceof app.Collection) {
this.models.push(...Array.from(object.all() || [])); this.models.push(...Array.from(object.all() || []));
} else { } else {
@ -48,7 +56,9 @@ app.Collection = class Collection {
} }
each(fn) { each(fn) {
for (var model of Array.from(this.models)) { fn(model); } for (var model of Array.from(this.models)) {
fn(model);
}
} }
all() { all() {
@ -61,7 +71,9 @@ app.Collection = class Collection {
findBy(attr, value) { findBy(attr, value) {
for (var model of Array.from(this.models)) { for (var model of Array.from(this.models)) {
if (model[attr] === value) { return model; } if (model[attr] === value) {
return model;
}
} }
} }
@ -71,7 +83,11 @@ app.Collection = class Collection {
countAllBy(attr, value) { countAllBy(attr, value) {
let i = 0; let i = 0;
for (var model of Array.from(this.models)) { if (model[attr] === value) { i += 1; } } for (var model of Array.from(this.models)) {
if (model[attr] === value) {
i += 1;
}
}
return i; return i;
} }
}; };

@ -8,16 +8,16 @@
* DS206: Consider reworking classes to avoid initClass * DS206: Consider reworking classes to avoid initClass
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let NORMALIZE_VERSION_RGX = undefined; let NORMALIZE_VERSION_RGX = undefined;
let NORMALIZE_VERSION_SUB = undefined; let NORMALIZE_VERSION_SUB = undefined;
let CONCURRENCY = undefined; let CONCURRENCY = undefined;
const Cls = (app.collections.Docs = class Docs extends app.Collection { const Cls = (app.collections.Docs = class Docs extends app.Collection {
static initClass() { static initClass() {
this.model = 'Doc'; this.model = "Doc";
NORMALIZE_VERSION_RGX = /\.(\d)$/; NORMALIZE_VERSION_RGX = /\.(\d)$/;
NORMALIZE_VERSION_SUB = '.0$1'; NORMALIZE_VERSION_SUB = ".0$1";
// Load models concurrently. // Load models concurrently.
// It's not pretty but I didn't want to import a promise library only for this. // It's not pretty but I didn't want to import a promise library only for this.
@ -25,12 +25,18 @@
} }
findBySlug(slug) { findBySlug(slug) {
return this.findBy('slug', slug) || this.findBy('slug_without_version', slug); return (
this.findBy("slug", slug) || this.findBy("slug_without_version", slug)
);
} }
sort() { sort() {
return this.models.sort(function(a, b) { return this.models.sort(function (a, b) {
if (a.name === b.name) { if (a.name === b.name) {
if (!a.version || (a.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB) > b.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB))) { if (
!a.version ||
a.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB) >
b.version.replace(NORMALIZE_VERSION_RGX, NORMALIZE_VERSION_SUB)
) {
return -1; return -1;
} else { } else {
return 1; return 1;
@ -48,13 +54,13 @@
var next = () => { var next = () => {
if (i < this.models.length) { if (i < this.models.length) {
this.models[i].load(next, fail, options); this.models[i].load(next, fail, options);
} else if (i === ((this.models.length + CONCURRENCY) - 1)) { } else if (i === this.models.length + CONCURRENCY - 1) {
onComplete(); onComplete();
} }
i++; i++;
}; };
var fail = function(...args) { var fail = function (...args) {
if (onError) { if (onError) {
onError(...Array.from(args || [])); onError(...Array.from(args || []));
onError = null; onError = null;
@ -62,11 +68,19 @@
next(); next();
}; };
for (let j = 0, end = CONCURRENCY, asc = 0 <= end; asc ? j < end : j > end; asc ? j++ : j--) { next(); } for (
let j = 0, end = CONCURRENCY, asc = 0 <= end;
asc ? j < end : j > end;
asc ? j++ : j--
) {
next();
}
} }
clearCache() { clearCache() {
for (var doc of Array.from(this.models)) { doc.clearCache(); } for (var doc of Array.from(this.models)) {
doc.clearCache();
}
} }
uninstall(callback) { uninstall(callback) {
@ -82,11 +96,11 @@
} }
getInstallStatuses(callback) { getInstallStatuses(callback) {
app.db.versions(this.models, function(statuses) { app.db.versions(this.models, function (statuses) {
if (statuses) { if (statuses) {
for (var key in statuses) { for (var key in statuses) {
var value = statuses[key]; var value = statuses[key];
statuses[key] = {installed: !!value, mtime: value}; statuses[key] = { installed: !!value, mtime: value };
} }
} }
callback(statuses); callback(statuses);
@ -94,22 +108,31 @@
} }
checkForUpdates(callback) { checkForUpdates(callback) {
this.getInstallStatuses(statuses => { this.getInstallStatuses((statuses) => {
let i = 0; let i = 0;
if (statuses) { if (statuses) {
for (var slug in statuses) { var status = statuses[slug]; if (this.findBy('slug', slug).isOutdated(status)) { i += 1; } } for (var slug in statuses) {
var status = statuses[slug];
if (this.findBy("slug", slug).isOutdated(status)) {
i += 1;
}
}
} }
callback(i); callback(i);
}); });
} }
updateInBackground() { updateInBackground() {
this.getInstallStatuses(statuses => { this.getInstallStatuses((statuses) => {
if (!statuses) { return; } if (!statuses) {
return;
}
for (var slug in statuses) { for (var slug in statuses) {
var status = statuses[slug]; var status = statuses[slug];
var doc = this.findBy('slug', slug); var doc = this.findBy("slug", slug);
if (doc.isOutdated(status)) { doc.install($.noop, $.noop); } if (doc.isOutdated(status)) {
doc.install($.noop, $.noop);
}
} }
}); });
} }

@ -7,7 +7,7 @@
*/ */
const Cls = (app.collections.Entries = class Entries extends app.Collection { const Cls = (app.collections.Entries = class Entries extends app.Collection {
static initClass() { static initClass() {
this.model = 'Entry'; this.model = "Entry";
} }
}); });
Cls.initClass(); Cls.initClass();

@ -8,14 +8,15 @@
* DS206: Consider reworking classes to avoid initClass * DS206: Consider reworking classes to avoid initClass
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let GUIDES_RGX = undefined; let GUIDES_RGX = undefined;
let APPENDIX_RGX = undefined; let APPENDIX_RGX = undefined;
const Cls = (app.collections.Types = class Types extends app.Collection { const Cls = (app.collections.Types = class Types extends app.Collection {
static initClass() { static initClass() {
this.model = 'Type'; this.model = "Type";
GUIDES_RGX = /(^|\()(guides?|tutorials?|reference|book|getting\ started|manual|examples)($|[\):])/i; GUIDES_RGX =
/(^|\()(guides?|tutorials?|reference|book|getting\ started|manual|examples)($|[\):])/i;
APPENDIX_RGX = /appendix/i; APPENDIX_RGX = /appendix/i;
} }
@ -23,9 +24,11 @@
const result = []; const result = [];
for (var type of Array.from(this.models)) { for (var type of Array.from(this.models)) {
var name; var name;
(result[name = this._groupFor(type)] || (result[name] = [])).push(type); (result[(name = this._groupFor(type))] || (result[name] = [])).push(
type,
);
} }
return result.filter(e => e.length > 0); return result.filter((e) => e.length > 0);
} }
_groupFor(type) { _groupFor(type) {

@ -9,26 +9,33 @@
* DS209: Avoid top-level return * DS209: Avoid top-level return
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
if (!(typeof console !== 'undefined' && console !== null ? console.time : undefined) || !console.groupCollapsed) { return; } if (
!(typeof console !== "undefined" && console !== null
? console.time
: undefined) ||
!console.groupCollapsed
) {
return;
}
// //
// App // App
// //
const _init = app.init; const _init = app.init;
app.init = function() { app.init = function () {
console.time('Init'); console.time("Init");
_init.call(app); _init.call(app);
console.timeEnd('Init'); console.timeEnd("Init");
return console.time('Load'); return console.time("Load");
}; };
const _start = app.start; const _start = app.start;
app.start = function() { app.start = function () {
console.timeEnd('Load'); console.timeEnd("Load");
console.time('Start'); console.time("Start");
_start.call(app, ...arguments); _start.call(app, ...arguments);
return console.timeEnd('Start'); return console.timeEnd("Start");
}; };
// //
@ -38,47 +45,50 @@ app.start = function() {
const _super = app.Searcher; const _super = app.Searcher;
const _proto = app.Searcher.prototype; const _proto = app.Searcher.prototype;
app.Searcher = function() { app.Searcher = function () {
_super.apply(this, arguments); _super.apply(this, arguments);
const _setup = this.setup.bind(this); const _setup = this.setup.bind(this);
this.setup = function() { this.setup = function () {
console.groupCollapsed(`Search: ${this.query}`); console.groupCollapsed(`Search: ${this.query}`);
console.time('Total'); console.time("Total");
return _setup(); return _setup();
}; };
const _match = this.match.bind(this); const _match = this.match.bind(this);
this.match = () => { this.match = () => {
if (this.matcher) { console.timeEnd(this.matcher.name); } if (this.matcher) {
console.timeEnd(this.matcher.name);
}
return _match(); return _match();
}; };
const _setupMatcher = this.setupMatcher.bind(this); const _setupMatcher = this.setupMatcher.bind(this);
this.setupMatcher = function() { this.setupMatcher = function () {
console.time(this.matcher.name); console.time(this.matcher.name);
return _setupMatcher(); return _setupMatcher();
}; };
const _end = this.end.bind(this); const _end = this.end.bind(this);
this.end = function() { this.end = function () {
console.log(`Results: ${this.totalResults}`); console.log(`Results: ${this.totalResults}`);
console.timeEnd('Total'); console.timeEnd("Total");
console.groupEnd(); console.groupEnd();
return _end(); return _end();
}; };
const _kill = this.kill.bind(this); const _kill = this.kill.bind(this);
this.kill = function() { this.kill = function () {
if (this.timeout) { if (this.timeout) {
if (this.matcher) { console.timeEnd(this.matcher.name); } if (this.matcher) {
console.timeEnd(this.matcher.name);
}
console.groupEnd(); console.groupEnd();
console.timeEnd('Total'); console.timeEnd("Total");
console.warn('Killed'); console.warn("Killed");
} }
return _kill(); return _kill();
}; };
}; };
$.extend(app.Searcher, _super); $.extend(app.Searcher, _super);
@ -89,23 +99,40 @@ app.Searcher.prototype = _proto;
// View tree // View tree
// //
this.viewTree = function(view, level, visited) { this.viewTree = function (view, level, visited) {
if (view == null) { view = app.document; } if (view == null) {
if (level == null) { level = 0; } view = app.document;
if (visited == null) { visited = []; } }
if (visited.indexOf(view) >= 0) { return; } if (level == null) {
level = 0;
}
if (visited == null) {
visited = [];
}
if (visited.indexOf(view) >= 0) {
return;
}
visited.push(view); visited.push(view);
console.log(`%c ${Array(level + 1).join(' ')}${view.constructor.name}: ${!!view.activated}`, console.log(
'color:' + ((view.activated && 'green') || 'red')); `%c ${Array(level + 1).join(" ")}${
view.constructor.name
}: ${!!view.activated}`,
"color:" + ((view.activated && "green") || "red"),
);
for (var key of Object.keys(view || {})) { for (var key of Object.keys(view || {})) {
var value = view[key]; var value = view[key];
if ((key !== 'view') && value) { if (key !== "view" && value) {
if ((typeof value === 'object') && value.setupElement) { if (typeof value === "object" && value.setupElement) {
this.viewTree(value, level + 1, visited); this.viewTree(value, level + 1, visited);
} else if (value.constructor.toString().match(/Object\(\)/)) { } else if (value.constructor.toString().match(/Object\(\)/)) {
for (var k of Object.keys(value || {})) { var v = value[k]; if (v && (typeof v === 'object') && v.setupElement) { this.viewTree(v, level + 1, visited); } } for (var k of Object.keys(value || {})) {
var v = value[k];
if (v && typeof v === "object" && v.setupElement) {
this.viewTree(v, level + 1, visited);
}
}
} }
} }
} }

@ -9,11 +9,11 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const MIME_TYPES = { const MIME_TYPES = {
json: 'application/json', json: "application/json",
html: 'text/html' html: "text/html",
}; };
this.ajax = function(options) { this.ajax = function (options) {
applyDefaults(options); applyDefaults(options);
serializeData(options); serializeData(options);
@ -26,7 +26,7 @@ this.ajax = function(options) {
xhr.send(options.data); xhr.send(options.data);
if (options.async) { if (options.async) {
return {abort: abort.bind(undefined, xhr)}; return { abort: abort.bind(undefined, xhr) };
} else { } else {
return parseResponse(xhr, options); return parseResponse(xhr, options);
} }
@ -34,51 +34,63 @@ this.ajax = function(options) {
ajax.defaults = { ajax.defaults = {
async: true, async: true,
dataType: 'json', dataType: "json",
timeout: 30, timeout: 30,
type: 'GET' type: "GET",
}; };
// contentType // contentType
// context // context
// data // data
// error // error
// headers // headers
// progress // progress
// success // success
// url // url
var applyDefaults = function(options) { var applyDefaults = function (options) {
for (var key in ajax.defaults) { for (var key in ajax.defaults) {
if (options[key] == null) { options[key] = ajax.defaults[key]; } if (options[key] == null) {
options[key] = ajax.defaults[key];
}
} }
}; };
var serializeData = function(options) { var serializeData = function (options) {
if (!options.data) { return; } if (!options.data) {
return;
}
if (options.type === 'GET') { if (options.type === "GET") {
options.url += '?' + serializeParams(options.data); options.url += "?" + serializeParams(options.data);
options.data = null; options.data = null;
} else { } else {
options.data = serializeParams(options.data); options.data = serializeParams(options.data);
} }
}; };
var serializeParams = params => ((() => { var serializeParams = (params) =>
const result = []; (() => {
for (var key in params) { const result = [];
var value = params[key]; for (var key in params) {
result.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); var value = params[key];
} result.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
return result; }
})()).join('&'); return result;
})().join("&");
var applyCallbacks = function(xhr, options) { var applyCallbacks = function (xhr, options) {
if (!options.async) { return; } if (!options.async) {
return;
}
xhr.timer = setTimeout(onTimeout.bind(undefined, xhr, options), options.timeout * 1000); xhr.timer = setTimeout(
if (options.progress) { xhr.onprogress = options.progress; } onTimeout.bind(undefined, xhr, options),
xhr.onreadystatechange = function() { options.timeout * 1000,
);
if (options.progress) {
xhr.onprogress = options.progress;
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
clearTimeout(xhr.timer); clearTimeout(xhr.timer);
onComplete(xhr, options); onComplete(xhr, options);
@ -86,19 +98,26 @@ var applyCallbacks = function(xhr, options) {
}; };
}; };
var applyHeaders = function(xhr, options) { var applyHeaders = function (xhr, options) {
if (!options.headers) { options.headers = {}; } if (!options.headers) {
options.headers = {};
}
if (options.contentType) { if (options.contentType) {
options.headers['Content-Type'] = options.contentType; options.headers["Content-Type"] = options.contentType;
} }
if (!options.headers['Content-Type'] && options.data && (options.type !== 'GET')) { if (
options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; !options.headers["Content-Type"] &&
options.data &&
options.type !== "GET"
) {
options.headers["Content-Type"] = "application/x-www-form-urlencoded";
} }
if (options.dataType) { if (options.dataType) {
options.headers['Accept'] = MIME_TYPES[options.dataType] || options.dataType; options.headers["Accept"] =
MIME_TYPES[options.dataType] || options.dataType;
} }
for (var key in options.headers) { for (var key in options.headers) {
@ -107,50 +126,52 @@ var applyHeaders = function(xhr, options) {
} }
}; };
var onComplete = function(xhr, options) { var onComplete = function (xhr, options) {
if (200 <= xhr.status && xhr.status < 300) { if (200 <= xhr.status && xhr.status < 300) {
let response; let response;
if ((response = parseResponse(xhr, options)) != null) { if ((response = parseResponse(xhr, options)) != null) {
onSuccess(response, xhr, options); onSuccess(response, xhr, options);
} else { } else {
onError('invalid', xhr, options); onError("invalid", xhr, options);
} }
} else { } else {
onError('error', xhr, options); onError("error", xhr, options);
} }
}; };
var onSuccess = function(response, xhr, options) { var onSuccess = function (response, xhr, options) {
if (options.success != null) { if (options.success != null) {
options.success.call(options.context, response, xhr, options); options.success.call(options.context, response, xhr, options);
} }
}; };
var onError = function(type, xhr, options) { var onError = function (type, xhr, options) {
if (options.error != null) { if (options.error != null) {
options.error.call(options.context, type, xhr, options); options.error.call(options.context, type, xhr, options);
} }
}; };
var onTimeout = function(xhr, options) { var onTimeout = function (xhr, options) {
xhr.abort(); xhr.abort();
onError('timeout', xhr, options); onError("timeout", xhr, options);
}; };
var abort = function(xhr) { var abort = function (xhr) {
clearTimeout(xhr.timer); clearTimeout(xhr.timer);
xhr.onreadystatechange = null; xhr.onreadystatechange = null;
xhr.abort(); xhr.abort();
}; };
var parseResponse = function(xhr, options) { var parseResponse = function (xhr, options) {
if (options.dataType === 'json') { if (options.dataType === "json") {
return parseJSON(xhr.responseText); return parseJSON(xhr.responseText);
} else { } else {
return xhr.responseText; return xhr.responseText;
} }
}; };
var parseJSON = function(json) { var parseJSON = function (json) {
try { return JSON.parse(json); } catch (error) {} try {
return JSON.parse(json);
} catch (error) {}
}; };

@ -8,7 +8,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let INT = undefined; let INT = undefined;
const Cls = (this.CookiesStore = class CookiesStore { const Cls = (this.CookiesStore = class CookiesStore {
static initClass() { static initClass() {
@ -23,7 +23,9 @@
get(key) { get(key) {
let value = Cookies.get(key); let value = Cookies.get(key);
if ((value != null) && INT.test(value)) { value = parseInt(value, 10); } if (value != null && INT.test(value)) {
value = parseInt(value, 10);
}
return value; return value;
} }
@ -33,10 +35,19 @@
return; return;
} }
if (value === true) { value = 1; } if (value === true) {
if (value && (typeof INT.test === 'function' ? INT.test(value) : undefined)) { value = parseInt(value, 10); } value = 1;
Cookies.set(key, '' + value, {path: '/', expires: 1e8}); }
if (this.get(key) !== value) { this.constructor.onBlocked(key, value, this.get(key)); } if (
value &&
(typeof INT.test === "function" ? INT.test(value) : undefined)
) {
value = parseInt(value, 10);
}
Cookies.set(key, "" + value, { path: "/", expires: 1e8 });
if (this.get(key) !== value) {
this.constructor.onBlocked(key, value, this.get(key));
}
} }
del(key) { del(key) {
@ -46,7 +57,7 @@
reset() { reset() {
try { try {
for (var cookie of Array.from(document.cookie.split(/;\s?/))) { for (var cookie of Array.from(document.cookie.split(/;\s?/))) {
Cookies.expire(cookie.split('=')[0]); Cookies.expire(cookie.split("=")[0]);
} }
return; return;
} catch (error) {} } catch (error) {}
@ -55,8 +66,8 @@
dump() { dump() {
const result = {}; const result = {};
for (var cookie of Array.from(document.cookie.split(/;\s?/))) { for (var cookie of Array.from(document.cookie.split(/;\s?/))) {
if (cookie[0] !== '_') { if (cookie[0] !== "_") {
cookie = cookie.split('='); cookie = cookie.split("=");
result[cookie[0]] = cookie[1]; result[cookie[0]] = cookie[1];
} }
} }

@ -11,22 +11,38 @@
*/ */
this.Events = { this.Events = {
on(event, callback) { on(event, callback) {
if (event.indexOf(' ') >= 0) { if (event.indexOf(" ") >= 0) {
for (var name of Array.from(event.split(' '))) { this.on(name, callback); } for (var name of Array.from(event.split(" "))) {
this.on(name, callback);
}
} else { } else {
let base; let base;
(((base = this._callbacks != null ? this._callbacks : (this._callbacks = {})))[event] != null ? base[event] : (base[event] = [])).push(callback); ((base =
this._callbacks != null ? this._callbacks : (this._callbacks = {}))[
event
] != null
? base[event]
: (base[event] = [])
).push(callback);
} }
return this; return this;
}, },
off(event, callback) { off(event, callback) {
let callbacks, index; let callbacks, index;
if (event.indexOf(' ') >= 0) { if (event.indexOf(" ") >= 0) {
for (var name of Array.from(event.split(' '))) { this.off(name, callback); } for (var name of Array.from(event.split(" "))) {
} else if ((callbacks = this._callbacks != null ? this._callbacks[event] : undefined) && ((index = callbacks.indexOf(callback)) >= 0)) { this.off(name, callback);
}
} else if (
(callbacks =
this._callbacks != null ? this._callbacks[event] : undefined) &&
(index = callbacks.indexOf(callback)) >= 0
) {
callbacks.splice(index, 1); callbacks.splice(index, 1);
if (!callbacks.length) { delete this._callbacks[event]; } if (!callbacks.length) {
delete this._callbacks[event];
}
} }
return this; return this;
}, },
@ -34,20 +50,28 @@ this.Events = {
trigger(event, ...args) { trigger(event, ...args) {
let callbacks; let callbacks;
this.eventInProgress = { name: event, args }; this.eventInProgress = { name: event, args };
if (callbacks = this._callbacks != null ? this._callbacks[event] : undefined) { if (
for (var callback of Array.from(callbacks.slice(0))) { if (typeof callback === 'function') { (callbacks = this._callbacks != null ? this._callbacks[event] : undefined)
callback(...Array.from(args || [])); ) {
} } for (var callback of Array.from(callbacks.slice(0))) {
if (typeof callback === "function") {
callback(...Array.from(args || []));
}
}
} }
this.eventInProgress = null; this.eventInProgress = null;
if (event !== 'all') { this.trigger('all', event, ...Array.from(args)); } if (event !== "all") {
this.trigger("all", event, ...Array.from(args));
}
return this; return this;
}, },
removeEvent(event) { removeEvent(event) {
if (this._callbacks != null) { if (this._callbacks != null) {
for (var name of Array.from(event.split(' '))) { delete this._callbacks[name]; } for (var name of Array.from(event.split(" "))) {
delete this._callbacks[name];
}
} }
return this; return this;
} },
}; };

@ -12,22 +12,24 @@ let currentSlug = null;
const imageCache = {}; const imageCache = {};
const urlCache = {}; const urlCache = {};
const withImage = function(url, action) { const withImage = function (url, action) {
if (imageCache[url]) { if (imageCache[url]) {
return action(imageCache[url]); return action(imageCache[url]);
} else { } else {
const img = new Image(); const img = new Image();
img.crossOrigin = 'anonymous'; img.crossOrigin = "anonymous";
img.src = url; img.src = url;
return img.onload = () => { return (img.onload = () => {
imageCache[url] = img; imageCache[url] = img;
return action(img); return action(img);
}; });
} }
}; };
this.setFaviconForDoc = function(doc) { this.setFaviconForDoc = function (doc) {
if (currentSlug === doc.slug) { return; } if (currentSlug === doc.slug) {
return;
}
const favicon = $('link[rel="icon"]'); const favicon = $('link[rel="icon"]');
@ -41,51 +43,67 @@ this.setFaviconForDoc = function(doc) {
return; return;
} }
const iconEl = $(`._icon-${doc.slug.split('~')[0]}`); const iconEl = $(`._icon-${doc.slug.split("~")[0]}`);
if (iconEl === null) { return; } if (iconEl === null) {
return;
}
const styles = window.getComputedStyle(iconEl, ':before'); const styles = window.getComputedStyle(iconEl, ":before");
const backgroundPositionX = styles['background-position-x']; const backgroundPositionX = styles["background-position-x"];
const backgroundPositionY = styles['background-position-y']; const backgroundPositionY = styles["background-position-y"];
if ((backgroundPositionX === undefined) || (backgroundPositionY === undefined)) { return; } if (backgroundPositionX === undefined || backgroundPositionY === undefined) {
return;
}
const bgUrl = app.config.favicon_spritesheet; const bgUrl = app.config.favicon_spritesheet;
const sourceSize = 16; const sourceSize = 16;
const sourceX = Math.abs(parseInt(backgroundPositionX.slice(0, -2))); const sourceX = Math.abs(parseInt(backgroundPositionX.slice(0, -2)));
const sourceY = Math.abs(parseInt(backgroundPositionY.slice(0, -2))); const sourceY = Math.abs(parseInt(backgroundPositionY.slice(0, -2)));
return withImage(bgUrl, docImg => withImage(defaultUrl, function(defaultImg) { return withImage(bgUrl, (docImg) =>
const size = defaultImg.width; withImage(defaultUrl, function (defaultImg) {
const size = defaultImg.width;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d'); const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size; canvas.width = size;
ctx.drawImage(defaultImg, 0, 0); canvas.height = size;
ctx.drawImage(defaultImg, 0, 0);
const docIconPercentage = 65;
const destinationCoords = (size / 100) * (100 - docIconPercentage); const docIconPercentage = 65;
const destinationSize = (size / 100) * docIconPercentage; const destinationCoords = (size / 100) * (100 - docIconPercentage);
const destinationSize = (size / 100) * docIconPercentage;
ctx.drawImage(docImg, sourceX, sourceY, sourceSize, sourceSize, destinationCoords, destinationCoords, destinationSize, destinationSize);
ctx.drawImage(
try { docImg,
urlCache[doc.slug] = canvas.toDataURL(); sourceX,
favicon.href = urlCache[doc.slug]; sourceY,
sourceSize,
return currentSlug = doc.slug; sourceSize,
} catch (error) { destinationCoords,
Raven.captureException(error, { level: 'info' }); destinationCoords,
return this.resetFavicon(); destinationSize,
} destinationSize,
})); );
try {
urlCache[doc.slug] = canvas.toDataURL();
favicon.href = urlCache[doc.slug];
return (currentSlug = doc.slug);
} catch (error) {
Raven.captureException(error, { level: "info" });
return this.resetFavicon();
}
}),
);
}; };
this.resetFavicon = function() { this.resetFavicon = function () {
if ((defaultUrl !== null) && (currentSlug !== null)) { if (defaultUrl !== null && currentSlug !== null) {
$('link[rel="icon"]').href = defaultUrl; $('link[rel="icon"]').href = defaultUrl;
return currentSlug = null; return (currentSlug = null);
} }
}; };

@ -6,4 +6,4 @@
* This source code is licensed under the terms of the Mozilla * This source code is licensed under the terms of the Mozilla
* Public License, v. 2.0, a copy of which may be obtained at: * Public License, v. 2.0, a copy of which may be obtained at:
* http://mozilla.org/MPL/2.0/ * http://mozilla.org/MPL/2.0/
*/ */

@ -13,50 +13,54 @@
* Based on github.com/visionmedia/page.js * Based on github.com/visionmedia/page.js
* Licensed under the MIT license * Licensed under the MIT license
* Copyright 2012 TJ Holowaychuk <tj@vision-media.ca> * Copyright 2012 TJ Holowaychuk <tj@vision-media.ca>
*/ */
let running = false; let running = false;
let currentState = null; let currentState = null;
const callbacks = []; const callbacks = [];
this.page = function(value, fn) { this.page = function (value, fn) {
if (typeof value === 'function') { if (typeof value === "function") {
page('*', value); page("*", value);
} else if (typeof fn === 'function') { } else if (typeof fn === "function") {
const route = new Route(value); const route = new Route(value);
callbacks.push(route.middleware(fn)); callbacks.push(route.middleware(fn));
} else if (typeof value === 'string') { } else if (typeof value === "string") {
page.show(value, fn); page.show(value, fn);
} else { } else {
page.start(value); page.start(value);
} }
}; };
page.start = function(options) { page.start = function (options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
if (!running) { if (!running) {
running = true; running = true;
addEventListener('popstate', onpopstate); addEventListener("popstate", onpopstate);
addEventListener('click', onclick); addEventListener("click", onclick);
page.replace(currentPath(), null, null, true); page.replace(currentPath(), null, null, true);
} }
}; };
page.stop = function() { page.stop = function () {
if (running) { if (running) {
running = false; running = false;
removeEventListener('click', onclick); removeEventListener("click", onclick);
removeEventListener('popstate', onpopstate); removeEventListener("popstate", onpopstate);
} }
}; };
page.show = function(path, state) { page.show = function (path, state) {
let res; let res;
if (path === (currentState != null ? currentState.path : undefined)) { return; } if (path === (currentState != null ? currentState.path : undefined)) {
return;
}
const context = new Context(path, state); const context = new Context(path, state);
const previousState = currentState; const previousState = currentState;
currentState = context.state; currentState = context.state;
if (res = page.dispatch(context)) { if ((res = page.dispatch(context))) {
currentState = previousState; currentState = previousState;
location.assign(res); location.assign(res);
} else { } else {
@ -67,12 +71,14 @@ page.show = function(path, state) {
return context; return context;
}; };
page.replace = function(path, state, skipDispatch, init) { page.replace = function (path, state, skipDispatch, init) {
let result; let result;
let context = new Context(path, state || currentState); let context = new Context(path, state || currentState);
context.init = init; context.init = init;
currentState = context.state; currentState = context.state;
if (!skipDispatch) { result = page.dispatch(context); } if (!skipDispatch) {
result = page.dispatch(context);
}
if (result) { if (result) {
context = new Context(result); context = new Context(result);
context.init = init; context.init = init;
@ -81,15 +87,19 @@ page.replace = function(path, state, skipDispatch, init) {
} }
context.replaceState(); context.replaceState();
updateCanonicalLink(); updateCanonicalLink();
if (!skipDispatch) { track(); } if (!skipDispatch) {
track();
}
return context; return context;
}; };
page.dispatch = function(context) { page.dispatch = function (context) {
let i = 0; let i = 0;
var next = function() { var next = function () {
let fn, res; let fn, res;
if (fn = callbacks[i++]) { res = fn(context, next); } if ((fn = callbacks[i++])) {
res = fn(context, next);
}
return res; return res;
}; };
return next(); return next();
@ -113,11 +123,11 @@ class Context {
} }
static isLastState(state) { static isLastState(state) {
return state.id === (this.stateId - 1); return state.id === this.stateId - 1;
} }
static isInitialPopState(state) { static isInitialPopState(state) {
return (state.path === this.initialPath) && (this.stateId === 1); return state.path === this.initialPath && this.stateId === 1;
} }
static isSameSession(state) { static isSameSession(state) {
@ -125,27 +135,40 @@ class Context {
} }
constructor(path, state) { constructor(path, state) {
if (path == null) { path = '/'; } if (path == null) {
path = "/";
}
this.path = path; this.path = path;
if (state == null) { state = {}; } if (state == null) {
state = {};
}
this.state = state; this.state = state;
this.pathname = this.path.replace(/(?:\?([^#]*))?(?:#(.*))?$/, (_, query, hash) => { this.pathname = this.path.replace(
this.query = query; /(?:\?([^#]*))?(?:#(.*))?$/,
this.hash = hash; (_, query, hash) => {
return ''; this.query = query;
}); this.hash = hash;
return "";
if (this.state.id == null) { this.state.id = this.constructor.stateId++; } },
if (this.state.sessionId == null) { this.state.sessionId = this.constructor.sessionId; } );
if (this.state.id == null) {
this.state.id = this.constructor.stateId++;
}
if (this.state.sessionId == null) {
this.state.sessionId = this.constructor.sessionId;
}
this.state.path = this.path; this.state.path = this.path;
} }
pushState() { pushState() {
history.pushState(this.state, '', this.path); history.pushState(this.state, "", this.path);
} }
replaceState() { replaceState() {
try { history.replaceState(this.state, '', this.path); } catch (error) {} // NS_ERROR_FAILURE in Firefox try {
history.replaceState(this.state, "", this.path);
} catch (error) {} // NS_ERROR_FAILURE in Firefox
} }
} }
Context.initClass(); Context.initClass();
@ -153,7 +176,9 @@ Context.initClass();
class Route { class Route {
constructor(path, options) { constructor(path, options) {
this.path = path; this.path = path;
if (options == null) { options = {}; } if (options == null) {
options = {};
}
this.keys = []; this.keys = [];
this.regexp = pathtoRegexp(this.path, this.keys); this.regexp = pathtoRegexp(this.path, this.keys);
} }
@ -172,13 +197,17 @@ class Route {
match(path, params) { match(path, params) {
let matchData; let matchData;
if (!(matchData = this.regexp.exec(path))) { return; } if (!(matchData = this.regexp.exec(path))) {
return;
}
const iterable = matchData.slice(1); const iterable = matchData.slice(1);
for (let i = 0; i < iterable.length; i++) { for (let i = 0; i < iterable.length; i++) {
var key; var key;
var value = iterable[i]; var value = iterable[i];
if (typeof value === 'string') { value = decodeURIComponent(value); } if (typeof value === "string") {
value = decodeURIComponent(value);
}
if ((key = this.keys[i])) { if ((key = this.keys[i])) {
params[key.name] = value; params[key.name] = value;
} else { } else {
@ -189,32 +218,50 @@ class Route {
} }
} }
var pathtoRegexp = function(path, keys) { var pathtoRegexp = function (path, keys) {
if (path instanceof RegExp) { return path; } if (path instanceof RegExp) {
return path;
}
if (path instanceof Array) { path = `(${path.join('|')})`; } if (path instanceof Array) {
path = `(${path.join("|")})`;
}
path = path path = path
.replace(/\/\(/g, '(?:/') .replace(/\/\(/g, "(?:/")
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional) { .replace(
if (slash == null) { slash = ''; } /(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,
if (format == null) { format = ''; } function (_, slash, format, key, capture, optional) {
keys.push({name: key, optional: !!optional}); if (slash == null) {
let str = optional ? '' : slash; slash = "";
str += '(?:'; }
if (optional) { str += slash; } if (format == null) {
str += format; format = "";
str += capture || (format ? '([^/.]+?)' : '([^/]+?)'); }
str += ')'; keys.push({ name: key, optional: !!optional });
if (optional) { str += optional; } let str = optional ? "" : slash;
return str; str += "(?:";
}).replace(/([\/.])/g, '\\$1') if (optional) {
.replace(/\*/g, '(.*)'); str += slash;
}
str += format;
str += capture || (format ? "([^/.]+?)" : "([^/]+?)");
str += ")";
if (optional) {
str += optional;
}
return str;
},
)
.replace(/([\/.])/g, "\\$1")
.replace(/\*/g, "(.*)");
return new RegExp(`^${path}$`); return new RegExp(`^${path}$`);
}; };
var onpopstate = function(event) { var onpopstate = function (event) {
if (!event.state || Context.isInitialPopState(event.state)) { return; } if (!event.state || Context.isInitialPopState(event.state)) {
return;
}
if (Context.isSameSession(event.state)) { if (Context.isSameSession(event.state)) {
page.replace(event.state.path, event.state); page.replace(event.state.path, event.state);
@ -223,59 +270,83 @@ var onpopstate = function(event) {
} }
}; };
var onclick = function(event) { var onclick = function (event) {
try { try {
if ((event.which !== 1) || event.metaKey || event.ctrlKey || event.shiftKey || event.defaultPrevented) { return; } if (
event.which !== 1 ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.defaultPrevented
) {
return;
}
} catch (error) { } catch (error) {
return; return;
} }
let link = $.eventTarget(event); let link = $.eventTarget(event);
while (link && (link.tagName !== 'A')) { link = link.parentNode; } while (link && link.tagName !== "A") {
link = link.parentNode;
}
if (link && !link.target && isSameOrigin(link.href)) { if (link && !link.target && isSameOrigin(link.href)) {
event.preventDefault(); event.preventDefault();
let path = link.pathname + link.search + link.hash; let path = link.pathname + link.search + link.hash;
path = path.replace(/^\/\/+/, '/'); // IE11 bug path = path.replace(/^\/\/+/, "/"); // IE11 bug
page.show(path); page.show(path);
} }
}; };
var isSameOrigin = url => url.indexOf(`${location.protocol}//${location.hostname}`) === 0; var isSameOrigin = (url) =>
url.indexOf(`${location.protocol}//${location.hostname}`) === 0;
var updateCanonicalLink = function() { var updateCanonicalLink = function () {
if (!this.canonicalLink) { this.canonicalLink = document.head.querySelector('link[rel="canonical"]'); } if (!this.canonicalLink) {
return this.canonicalLink.setAttribute('href', `https://${location.host}${location.pathname}`); this.canonicalLink = document.head.querySelector('link[rel="canonical"]');
}
return this.canonicalLink.setAttribute(
"href",
`https://${location.host}${location.pathname}`,
);
}; };
const trackers = []; const trackers = [];
page.track = function(fn) { page.track = function (fn) {
trackers.push(fn); trackers.push(fn);
}; };
var track = function() { var track = function () {
if (app.config.env !== 'production') { return; } if (app.config.env !== "production") {
if (navigator.doNotTrack === '1') { return; } return;
if (navigator.globalPrivacyControl) { return; } }
if (navigator.doNotTrack === "1") {
return;
}
if (navigator.globalPrivacyControl) {
return;
}
const consentGiven = Cookies.get('analyticsConsent'); const consentGiven = Cookies.get("analyticsConsent");
const consentAsked = Cookies.get('analyticsConsentAsked'); const consentAsked = Cookies.get("analyticsConsentAsked");
if (consentGiven === '1') { if (consentGiven === "1") {
for (var tracker of Array.from(trackers)) { tracker.call(); } for (var tracker of Array.from(trackers)) {
} else if ((consentGiven === undefined) && (consentAsked === undefined)) { tracker.call();
}
} else if (consentGiven === undefined && consentAsked === undefined) {
// Only ask for consent once per browser session // Only ask for consent once per browser session
Cookies.set('analyticsConsentAsked', '1'); Cookies.set("analyticsConsentAsked", "1");
new app.views.Notif('AnalyticsConsent', {autoHide: null}); new app.views.Notif("AnalyticsConsent", { autoHide: null });
} }
}; };
this.resetAnalytics = function() { this.resetAnalytics = function () {
for (var cookie of Array.from(document.cookie.split(/;\s?/))) { for (var cookie of Array.from(document.cookie.split(/;\s?/))) {
var name = cookie.split('=')[0]; var name = cookie.split("=")[0];
if ((name[0] === '_') && (name[1] !== '_')) { if (name[0] === "_" && name[1] !== "_") {
Cookies.expire(name); Cookies.expire(name);
} }
} }

@ -16,32 +16,52 @@
// //
let smoothDistance, smoothDuration, smoothEnd, smoothStart; let smoothDistance, smoothDuration, smoothEnd, smoothStart;
this.$ = function(selector, el) { this.$ = function (selector, el) {
if (el == null) { el = document; } if (el == null) {
try { return el.querySelector(selector); } catch (error) {} el = document;
}
try {
return el.querySelector(selector);
} catch (error) {}
}; };
this.$$ = function(selector, el) { this.$$ = function (selector, el) {
if (el == null) { el = document; } if (el == null) {
try { return el.querySelectorAll(selector); } catch (error) {} el = document;
}
try {
return el.querySelectorAll(selector);
} catch (error) {}
}; };
$.id = id => document.getElementById(id); $.id = (id) => document.getElementById(id);
$.hasChild = function(parent, el) { $.hasChild = function (parent, el) {
if (!parent) { return; } if (!parent) {
return;
}
while (el) { while (el) {
if (el === parent) { return true; } if (el === parent) {
if (el === document.body) { return; } return true;
}
if (el === document.body) {
return;
}
el = el.parentNode; el = el.parentNode;
} }
}; };
$.closestLink = function(el, parent) { $.closestLink = function (el, parent) {
if (parent == null) { parent = document.body; } if (parent == null) {
parent = document.body;
}
while (el) { while (el) {
if (el.tagName === 'A') { return el; } if (el.tagName === "A") {
if (el === parent) { return; } return el;
}
if (el === parent) {
return;
}
el = el.parentNode; el = el.parentNode;
} }
}; };
@ -50,55 +70,85 @@ $.closestLink = function(el, parent) {
// Events // Events
// //
$.on = function(el, event, callback, useCapture) { $.on = function (el, event, callback, useCapture) {
if (useCapture == null) { useCapture = false; } if (useCapture == null) {
if (event.indexOf(' ') >= 0) { useCapture = false;
for (var name of Array.from(event.split(' '))) { $.on(el, name, callback); } }
if (event.indexOf(" ") >= 0) {
for (var name of Array.from(event.split(" "))) {
$.on(el, name, callback);
}
} else { } else {
el.addEventListener(event, callback, useCapture); el.addEventListener(event, callback, useCapture);
} }
}; };
$.off = function(el, event, callback, useCapture) { $.off = function (el, event, callback, useCapture) {
if (useCapture == null) { useCapture = false; } if (useCapture == null) {
if (event.indexOf(' ') >= 0) { useCapture = false;
for (var name of Array.from(event.split(' '))) { $.off(el, name, callback); } }
if (event.indexOf(" ") >= 0) {
for (var name of Array.from(event.split(" "))) {
$.off(el, name, callback);
}
} else { } else {
el.removeEventListener(event, callback, useCapture); el.removeEventListener(event, callback, useCapture);
} }
}; };
$.trigger = function(el, type, canBubble, cancelable) { $.trigger = function (el, type, canBubble, cancelable) {
if (canBubble == null) { canBubble = true; } if (canBubble == null) {
if (cancelable == null) { cancelable = true; } canBubble = true;
const event = document.createEvent('Event'); }
if (cancelable == null) {
cancelable = true;
}
const event = document.createEvent("Event");
event.initEvent(type, canBubble, cancelable); event.initEvent(type, canBubble, cancelable);
el.dispatchEvent(event); el.dispatchEvent(event);
}; };
$.click = function(el) { $.click = function (el) {
const event = document.createEvent('MouseEvent'); const event = document.createEvent("MouseEvent");
event.initMouseEvent('click', true, true, window, null, 0, 0, 0, 0, false, false, false, false, 0, null); event.initMouseEvent(
"click",
true,
true,
window,
null,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null,
);
el.dispatchEvent(event); el.dispatchEvent(event);
}; };
$.stopEvent = function(event) { $.stopEvent = function (event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
}; };
$.eventTarget = event => event.target.correspondingUseElement || event.target; $.eventTarget = (event) => event.target.correspondingUseElement || event.target;
// //
// Manipulation // Manipulation
// //
const buildFragment = function(value) { const buildFragment = function (value) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
if ($.isCollection(value)) { if ($.isCollection(value)) {
for (var child of Array.from($.makeArray(value))) { fragment.appendChild(child); } for (var child of Array.from($.makeArray(value))) {
fragment.appendChild(child);
}
} else { } else {
fragment.innerHTML = value; fragment.innerHTML = value;
} }
@ -106,36 +156,40 @@ const buildFragment = function(value) {
return fragment; return fragment;
}; };
$.append = function(el, value) { $.append = function (el, value) {
if (typeof value === 'string') { if (typeof value === "string") {
el.insertAdjacentHTML('beforeend', value); el.insertAdjacentHTML("beforeend", value);
} else { } else {
if ($.isCollection(value)) { value = buildFragment(value); } if ($.isCollection(value)) {
value = buildFragment(value);
}
el.appendChild(value); el.appendChild(value);
} }
}; };
$.prepend = function(el, value) { $.prepend = function (el, value) {
if (!el.firstChild) { if (!el.firstChild) {
$.append(value); $.append(value);
} else if (typeof value === 'string') { } else if (typeof value === "string") {
el.insertAdjacentHTML('afterbegin', value); el.insertAdjacentHTML("afterbegin", value);
} else { } else {
if ($.isCollection(value)) { value = buildFragment(value); } if ($.isCollection(value)) {
value = buildFragment(value);
}
el.insertBefore(value, el.firstChild); el.insertBefore(value, el.firstChild);
} }
}; };
$.before = function(el, value) { $.before = function (el, value) {
if ((typeof value === 'string') || $.isCollection(value)) { if (typeof value === "string" || $.isCollection(value)) {
value = buildFragment(value); value = buildFragment(value);
} }
el.parentNode.insertBefore(value, el); el.parentNode.insertBefore(value, el);
}; };
$.after = function(el, value) { $.after = function (el, value) {
if ((typeof value === 'string') || $.isCollection(value)) { if (typeof value === "string" || $.isCollection(value)) {
value = buildFragment(value); value = buildFragment(value);
} }
@ -146,11 +200,13 @@ $.after = function(el, value) {
} }
}; };
$.remove = function(value) { $.remove = function (value) {
if ($.isCollection(value)) { if ($.isCollection(value)) {
for (var el of Array.from($.makeArray(value))) { if (el.parentNode != null) { for (var el of Array.from($.makeArray(value))) {
el.parentNode.removeChild(el); if (el.parentNode != null) {
} } el.parentNode.removeChild(el);
}
}
} else { } else {
if (value.parentNode != null) { if (value.parentNode != null) {
value.parentNode.removeChild(value); value.parentNode.removeChild(value);
@ -158,13 +214,15 @@ $.remove = function(value) {
} }
}; };
$.empty = function(el) { $.empty = function (el) {
while (el.firstChild) { el.removeChild(el.firstChild); } while (el.firstChild) {
el.removeChild(el.firstChild);
}
}; };
// Calls the function while the element is off the DOM to avoid triggering // Calls the function while the element is off the DOM to avoid triggering
// unnecessary reflows and repaints. // unnecessary reflows and repaints.
$.batchUpdate = function(el, fn) { $.batchUpdate = function (el, fn) {
const parent = el.parentNode; const parent = el.parentNode;
const sibling = el.nextSibling; const sibling = el.nextSibling;
parent.removeChild(el); parent.removeChild(el);
@ -182,14 +240,16 @@ $.batchUpdate = function(el, fn) {
// Offset // Offset
// //
$.rect = el => el.getBoundingClientRect(); $.rect = (el) => el.getBoundingClientRect();
$.offset = function(el, container) { $.offset = function (el, container) {
if (container == null) { container = document.body; } if (container == null) {
container = document.body;
}
let top = 0; let top = 0;
let left = 0; let left = 0;
while (el && (el !== container)) { while (el && el !== container) {
top += el.offsetTop; top += el.offsetTop;
left += el.offsetLeft; left += el.offsetLeft;
el = el.offsetParent; el = el.offsetParent;
@ -197,102 +257,131 @@ $.offset = function(el, container) {
return { return {
top, top,
left left,
}; };
}; };
$.scrollParent = function(el) { $.scrollParent = function (el) {
while ((el = el.parentNode) && (el.nodeType === 1)) { while ((el = el.parentNode) && el.nodeType === 1) {
var needle; var needle;
if (el.scrollTop > 0) { break; } if (el.scrollTop > 0) {
if ((needle = __guard__(getComputedStyle(el), x => x.overflowY), ['auto', 'scroll'].includes(needle))) { break; } break;
}
if (
((needle = __guard__(getComputedStyle(el), (x) => x.overflowY)),
["auto", "scroll"].includes(needle))
) {
break;
}
} }
return el; return el;
}; };
$.scrollTo = function(el, parent, position, options) { $.scrollTo = function (el, parent, position, options) {
if (position == null) { position = 'center'; } if (position == null) {
if (options == null) { options = {}; } position = "center";
if (!el) { return; } }
if (options == null) {
options = {};
}
if (!el) {
return;
}
if (parent == null) { parent = $.scrollParent(el); } if (parent == null) {
if (!parent) { return; } parent = $.scrollParent(el);
}
if (!parent) {
return;
}
const parentHeight = parent.clientHeight; const parentHeight = parent.clientHeight;
const parentScrollHeight = parent.scrollHeight; const parentScrollHeight = parent.scrollHeight;
if (!(parentScrollHeight > parentHeight)) { return; } if (!(parentScrollHeight > parentHeight)) {
return;
}
const { const { top } = $.offset(el, parent);
top const { offsetTop } = parent.firstElementChild;
} = $.offset(el, parent);
const {
offsetTop
} = parent.firstElementChild;
switch (position) { switch (position) {
case 'top': case "top":
parent.scrollTop = top - offsetTop - ((options.margin != null) ? options.margin : 0); parent.scrollTop =
top - offsetTop - (options.margin != null ? options.margin : 0);
break; break;
case 'center': case "center":
parent.scrollTop = top - Math.round((parentHeight / 2) - (el.offsetHeight / 2)); parent.scrollTop =
top - Math.round(parentHeight / 2 - el.offsetHeight / 2);
break; break;
case 'continuous': case "continuous":
var { var { scrollTop } = parent;
scrollTop
} = parent;
var height = el.offsetHeight; var height = el.offsetHeight;
var lastElementOffset = parent.lastElementChild.offsetTop + parent.lastElementChild.offsetHeight; var lastElementOffset =
var offsetBottom = lastElementOffset > 0 ? parentScrollHeight - lastElementOffset : 0; parent.lastElementChild.offsetTop +
parent.lastElementChild.offsetHeight;
var offsetBottom =
lastElementOffset > 0 ? parentScrollHeight - lastElementOffset : 0;
// If the target element is above the visible portion of its scrollable // If the target element is above the visible portion of its scrollable
// ancestor, move it near the top with a gap = options.topGap * target's height. // ancestor, move it near the top with a gap = options.topGap * target's height.
if ((top - offsetTop) <= (scrollTop + (height * (options.topGap || 1)))) { if (top - offsetTop <= scrollTop + height * (options.topGap || 1)) {
parent.scrollTop = top - offsetTop - (height * (options.topGap || 1)); parent.scrollTop = top - offsetTop - height * (options.topGap || 1);
// If the target element is below the visible portion of its scrollable // If the target element is below the visible portion of its scrollable
// ancestor, move it near the bottom with a gap = options.bottomGap * target's height. // ancestor, move it near the bottom with a gap = options.bottomGap * target's height.
} else if ((top + offsetBottom) >= ((scrollTop + parentHeight) - (height * ((options.bottomGap || 1) + 1)))) { } else if (
parent.scrollTop = ((top + offsetBottom) - parentHeight) + (height * ((options.bottomGap || 1) + 1)); top + offsetBottom >=
scrollTop + parentHeight - height * ((options.bottomGap || 1) + 1)
) {
parent.scrollTop =
top +
offsetBottom -
parentHeight +
height * ((options.bottomGap || 1) + 1);
} }
break; break;
} }
}; };
$.scrollToWithImageLock = function(el, parent, ...args) { $.scrollToWithImageLock = function (el, parent, ...args) {
if (parent == null) { parent = $.scrollParent(el); } if (parent == null) {
if (!parent) { return; } parent = $.scrollParent(el);
}
if (!parent) {
return;
}
$.scrollTo(el, parent, ...Array.from(args)); $.scrollTo(el, parent, ...Array.from(args));
// Lock the scroll position on the target element for up to 3 seconds while // Lock the scroll position on the target element for up to 3 seconds while
// nearby images are loaded and rendered. // nearby images are loaded and rendered.
for (var image of Array.from(parent.getElementsByTagName('img'))) { for (var image of Array.from(parent.getElementsByTagName("img"))) {
if (!image.complete) { if (!image.complete) {
(function() { (function () {
let timeout; let timeout;
const onLoad = function(event) { const onLoad = function (event) {
clearTimeout(timeout); clearTimeout(timeout);
unbind(event.target); unbind(event.target);
return $.scrollTo(el, parent, ...Array.from(args)); return $.scrollTo(el, parent, ...Array.from(args));
}; };
var unbind = target => $.off(target, 'load', onLoad); var unbind = (target) => $.off(target, "load", onLoad);
$.on(image, 'load', onLoad); $.on(image, "load", onLoad);
return timeout = setTimeout(unbind.bind(null, image), 3000); return (timeout = setTimeout(unbind.bind(null, image), 3000));
})(); })();
} }
} }
}; };
// Calls the function while locking the element's position relative to the window. // Calls the function while locking the element's position relative to the window.
$.lockScroll = function(el, fn) { $.lockScroll = function (el, fn) {
let parent; let parent;
if (parent = $.scrollParent(el)) { if ((parent = $.scrollParent(el))) {
let { let { top } = $.rect(el);
top if (![document.body, document.documentElement].includes(parent)) {
} = $.rect(el); top -= $.rect(parent).top;
if (![document.body, document.documentElement].includes(parent)) { top -= $.rect(parent).top; } }
fn(); fn();
parent.scrollTop = $.offset(el, parent).top - top; parent.scrollTop = $.offset(el, parent).top - top;
} else { } else {
@ -300,9 +389,14 @@ $.lockScroll = function(el, fn) {
} }
}; };
let smoothScroll = (smoothStart = (smoothEnd = (smoothDistance = (smoothDuration = null)))); let smoothScroll =
(smoothStart =
smoothEnd =
smoothDistance =
smoothDuration =
null);
$.smoothScroll = function(el, end) { $.smoothScroll = function (el, end) {
if (!window.requestAnimationFrame) { if (!window.requestAnimationFrame) {
el.scrollTop = end; el.scrollTop = end;
return; return;
@ -322,12 +416,18 @@ $.smoothScroll = function(el, end) {
smoothDuration = Math.min(300, Math.abs(smoothDistance)); smoothDuration = Math.min(300, Math.abs(smoothDistance));
const startTime = Date.now(); const startTime = Date.now();
smoothScroll = function() { smoothScroll = function () {
const p = Math.min(1, (Date.now() - startTime) / smoothDuration); const p = Math.min(1, (Date.now() - startTime) / smoothDuration);
const y = Math.max(0, Math.floor(smoothStart + (smoothDistance * (p < 0.5 ? 2 * p * p : (p * (4 - (p * 2))) - 1)))); const y = Math.max(
0,
Math.floor(
smoothStart +
smoothDistance * (p < 0.5 ? 2 * p * p : p * (4 - p * 2) - 1),
),
);
el.scrollTop = y; el.scrollTop = y;
if (p === 1) { if (p === 1) {
return smoothScroll = null; return (smoothScroll = null);
} else { } else {
return requestAnimationFrame(smoothScroll); return requestAnimationFrame(smoothScroll);
} }
@ -339,7 +439,7 @@ $.smoothScroll = function(el, end) {
// Utilities // Utilities
// //
$.extend = function(target, ...objects) { $.extend = function (target, ...objects) {
for (var object of Array.from(objects)) { for (var object of Array.from(objects)) {
if (object) { if (object) {
for (var key in object) { for (var key in object) {
@ -351,7 +451,7 @@ $.extend = function(target, ...objects) {
return target; return target;
}; };
$.makeArray = function(object) { $.makeArray = function (object) {
if (Array.isArray(object)) { if (Array.isArray(object)) {
return object; return object;
} else { } else {
@ -359,7 +459,7 @@ $.makeArray = function(object) {
} }
}; };
$.arrayDelete = function(array, object) { $.arrayDelete = function (array, object) {
const index = array.indexOf(object); const index = array.indexOf(object);
if (index >= 0) { if (index >= 0) {
array.splice(index, 1); array.splice(index, 1);
@ -370,45 +470,49 @@ $.arrayDelete = function(array, object) {
}; };
// Returns true if the object is an array or a collection of DOM elements. // Returns true if the object is an array or a collection of DOM elements.
$.isCollection = object => Array.isArray(object) || (typeof (object != null ? object.item : undefined) === 'function'); $.isCollection = (object) =>
Array.isArray(object) ||
typeof (object != null ? object.item : undefined) === "function";
const ESCAPE_HTML_MAP = { const ESCAPE_HTML_MAP = {
'&': '&amp;', "&": "&amp;",
'<': '&lt;', "<": "&lt;",
'>': '&gt;', ">": "&gt;",
'"': '&quot;', '"': "&quot;",
"'": '&#x27;', "'": "&#x27;",
'/': '&#x2F;' "/": "&#x2F;",
}; };
const ESCAPE_HTML_REGEXP = /[&<>"'\/]/g; const ESCAPE_HTML_REGEXP = /[&<>"'\/]/g;
$.escape = string => string.replace(ESCAPE_HTML_REGEXP, match => ESCAPE_HTML_MAP[match]); $.escape = (string) =>
string.replace(ESCAPE_HTML_REGEXP, (match) => ESCAPE_HTML_MAP[match]);
const ESCAPE_REGEXP = /([.*+?^=!:${}()|\[\]\/\\])/g; const ESCAPE_REGEXP = /([.*+?^=!:${}()|\[\]\/\\])/g;
$.escapeRegexp = string => string.replace(ESCAPE_REGEXP, "\\$1"); $.escapeRegexp = (string) => string.replace(ESCAPE_REGEXP, "\\$1");
$.urlDecode = string => decodeURIComponent(string.replace(/\+/g, '%20')); $.urlDecode = (string) => decodeURIComponent(string.replace(/\+/g, "%20"));
$.classify = function(string) { $.classify = function (string) {
string = string.split('_'); string = string.split("_");
for (let i = 0; i < string.length; i++) { for (let i = 0; i < string.length; i++) {
var substr = string[i]; var substr = string[i];
string[i] = substr[0].toUpperCase() + substr.slice(1); string[i] = substr[0].toUpperCase() + substr.slice(1);
} }
return string.join(''); return string.join("");
}; };
$.framify = function(fn, obj) { $.framify = function (fn, obj) {
if (window.requestAnimationFrame) { if (window.requestAnimationFrame) {
return (...args) => requestAnimationFrame(fn.bind(obj, ...Array.from(args))); return (...args) =>
requestAnimationFrame(fn.bind(obj, ...Array.from(args)));
} else { } else {
return fn; return fn;
} }
}; };
$.requestAnimationFrame = function(fn) { $.requestAnimationFrame = function (fn) {
if (window.requestAnimationFrame) { if (window.requestAnimationFrame) {
requestAnimationFrame(fn); requestAnimationFrame(fn);
} else { } else {
@ -420,37 +524,81 @@ $.requestAnimationFrame = function(fn) {
// Miscellaneous // Miscellaneous
// //
$.noop = function() {}; $.noop = function () {};
$.popup = function(value) { $.popup = function (value) {
try { try {
const win = window.open(); const win = window.open();
if (win.opener) { win.opener = null; } if (win.opener) {
win.opener = null;
}
win.location = value.href || value; win.location = value.href || value;
} catch (error) { } catch (error) {
window.open(value.href || value, '_blank'); window.open(value.href || value, "_blank");
} }
}; };
let isMac = null; let isMac = null;
$.isMac = () => isMac != null ? isMac : (isMac = (navigator.userAgent != null ? navigator.userAgent.indexOf('Mac') : undefined) >= 0); $.isMac = () =>
isMac != null
? isMac
: (isMac =
(navigator.userAgent != null
? navigator.userAgent.indexOf("Mac")
: undefined) >= 0);
let isIE = null; let isIE = null;
$.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)); $.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);
let isChromeForAndroid = null; let isChromeForAndroid = null;
$.isChromeForAndroid = () => isChromeForAndroid != null ? isChromeForAndroid : (isChromeForAndroid = ((navigator.userAgent != null ? navigator.userAgent.indexOf('Android') : undefined) >= 0) && /Chrome\/([.0-9])+ Mobile/.test(navigator.userAgent)); $.isChromeForAndroid = () =>
isChromeForAndroid != null
? isChromeForAndroid
: (isChromeForAndroid =
(navigator.userAgent != null
? navigator.userAgent.indexOf("Android")
: undefined) >= 0 &&
/Chrome\/([.0-9])+ Mobile/.test(navigator.userAgent));
let isAndroid = null; let isAndroid = null;
$.isAndroid = () => isAndroid != null ? isAndroid : (isAndroid = (navigator.userAgent != null ? navigator.userAgent.indexOf('Android') : undefined) >= 0); $.isAndroid = () =>
isAndroid != null
? isAndroid
: (isAndroid =
(navigator.userAgent != null
? navigator.userAgent.indexOf("Android")
: undefined) >= 0);
let isIOS = null; let isIOS = null;
$.isIOS = () => isIOS != null ? isIOS : (isIOS = ((navigator.userAgent != null ? navigator.userAgent.indexOf('iPhone') : undefined) >= 0) || ((navigator.userAgent != null ? navigator.userAgent.indexOf('iPad') : undefined) >= 0)); $.isIOS = () =>
isIOS != null
$.overlayScrollbarsEnabled = function() { ? isIOS
if (!$.isMac()) { return false; } : (isIOS =
const div = document.createElement('div'); (navigator.userAgent != null
div.setAttribute('style', 'width: 100px; height: 100px; overflow: scroll; position: absolute'); ? navigator.userAgent.indexOf("iPhone")
: undefined) >= 0 ||
(navigator.userAgent != null
? navigator.userAgent.indexOf("iPad")
: undefined) >= 0);
$.overlayScrollbarsEnabled = function () {
if (!$.isMac()) {
return false;
}
const div = document.createElement("div");
div.setAttribute(
"style",
"width: 100px; height: 100px; overflow: scroll; position: absolute",
);
document.body.appendChild(div); document.body.appendChild(div);
const result = div.offsetWidth === div.clientWidth; const result = div.offsetWidth === div.clientWidth;
document.body.removeChild(div); document.body.removeChild(div);
@ -458,36 +606,39 @@ $.overlayScrollbarsEnabled = function() {
}; };
const HIGHLIGHT_DEFAULTS = { const HIGHLIGHT_DEFAULTS = {
className: 'highlight', className: "highlight",
delay: 1000 delay: 1000,
}; };
$.highlight = function(el, options) { $.highlight = function (el, options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
options = $.extend({}, HIGHLIGHT_DEFAULTS, options); options = $.extend({}, HIGHLIGHT_DEFAULTS, options);
el.classList.add(options.className); el.classList.add(options.className);
setTimeout((() => el.classList.remove(options.className)), options.delay); setTimeout(() => el.classList.remove(options.className), options.delay);
}; };
$.copyToClipboard = function(string) { $.copyToClipboard = function (string) {
let result; let result;
const textarea = document.createElement('textarea'); const textarea = document.createElement("textarea");
textarea.style.position = 'fixed'; textarea.style.position = "fixed";
textarea.style.opacity = 0; textarea.style.opacity = 0;
textarea.value = string; textarea.value = string;
document.body.appendChild(textarea); document.body.appendChild(textarea);
try { try {
textarea.select(); textarea.select();
result = !!document.execCommand('copy'); result = !!document.execCommand("copy");
} catch (error) { } catch (error) {
result = false; result = false;
} } finally {
finally {
document.body.removeChild(textarea); document.body.removeChild(textarea);
} }
return result; return result;
}; };
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -12,10 +12,12 @@ app.models.Doc = class Doc extends app.Model {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.reset(this); this.reset(this);
this.slug_without_version = this.slug.split('~')[0]; this.slug_without_version = this.slug.split("~")[0];
this.fullName = `${this.name}` + (this.version ? ` ${this.version}` : ''); this.fullName = `${this.name}` + (this.version ? ` ${this.version}` : "");
this.icon = this.slug_without_version; this.icon = this.slug_without_version;
if (this.version) { this.short_version = this.version.split(' ')[0]; } if (this.version) {
this.short_version = this.version.split(" ")[0];
}
this.text = this.toEntry().text; this.text = this.toEntry().text;
} }
@ -26,17 +28,25 @@ app.models.Doc = class Doc extends app.Model {
resetEntries(entries) { resetEntries(entries) {
this.entries = new app.collections.Entries(entries); this.entries = new app.collections.Entries(entries);
this.entries.each(entry => { return entry.doc = this; }); this.entries.each((entry) => {
return (entry.doc = this);
});
} }
resetTypes(types) { resetTypes(types) {
this.types = new app.collections.Types(types); this.types = new app.collections.Types(types);
this.types.each(type => { return type.doc = this; }); this.types.each((type) => {
return (type.doc = this);
});
} }
fullPath(path) { fullPath(path) {
if (path == null) { path = ''; } if (path == null) {
if (path[0] !== '/') { path = `/${path}`; } path = "";
}
if (path[0] !== "/") {
path = `/${path}`;
}
return `/${this.slug}${path}`; return `/${this.slug}${path}`;
} }
@ -49,45 +59,57 @@ app.models.Doc = class Doc extends app.Model {
} }
indexUrl() { indexUrl() {
return `${app.indexHost()}/${this.slug}/${app.config.index_filename}?${this.mtime}`; return `${app.indexHost()}/${this.slug}/${app.config.index_filename}?${
this.mtime
}`;
} }
toEntry() { toEntry() {
if (this.entry) { return this.entry; } if (this.entry) {
return this.entry;
}
this.entry = new app.models.Entry({ this.entry = new app.models.Entry({
doc: this, doc: this,
name: this.fullName, name: this.fullName,
path: 'index' path: "index",
}); });
if (this.version) { this.entry.addAlias(this.name); } if (this.version) {
this.entry.addAlias(this.name);
}
return this.entry; return this.entry;
} }
findEntryByPathAndHash(path, hash) { findEntryByPathAndHash(path, hash) {
let entry; let entry;
if (hash && (entry = this.entries.findBy('path', `${path}#${hash}`))) { if (hash && (entry = this.entries.findBy("path", `${path}#${hash}`))) {
return entry; return entry;
} else if (path === 'index') { } else if (path === "index") {
return this.toEntry(); return this.toEntry();
} else { } else {
return this.entries.findBy('path', path); return this.entries.findBy("path", path);
} }
} }
load(onSuccess, onError, options) { load(onSuccess, onError, options) {
if (options == null) { options = {}; } if (options == null) {
if (options.readCache && this._loadFromCache(onSuccess)) { return; } options = {};
}
if (options.readCache && this._loadFromCache(onSuccess)) {
return;
}
const callback = data => { const callback = (data) => {
this.reset(data); this.reset(data);
onSuccess(); onSuccess();
if (options.writeCache) { this._setCache(data); } if (options.writeCache) {
this._setCache(data);
}
}; };
return ajax({ return ajax({
url: this.indexUrl(), url: this.indexUrl(),
success: callback, success: callback,
error: onError error: onError,
}); });
} }
@ -97,7 +119,9 @@ app.models.Doc = class Doc extends app.Model {
_loadFromCache(onSuccess) { _loadFromCache(onSuccess) {
let data; let data;
if (!(data = this._getCache())) { return; } if (!(data = this._getCache())) {
return;
}
const callback = () => { const callback = () => {
this.reset(data); this.reset(data);
@ -110,7 +134,9 @@ app.models.Doc = class Doc extends app.Model {
_getCache() { _getCache() {
let data; let data;
if (!(data = app.localStorage.get(this.slug))) { return; } if (!(data = app.localStorage.get(this.slug))) {
return;
}
if (data[0] === this.mtime) { if (data[0] === this.mtime) {
return data[1]; return data[1];
@ -125,7 +151,9 @@ app.models.Doc = class Doc extends app.Model {
} }
install(onSuccess, onError, onProgress) { install(onSuccess, onError, onProgress) {
if (this.installing) { return; } if (this.installing) {
return;
}
this.installing = true; this.installing = true;
const error = () => { const error = () => {
@ -133,7 +161,7 @@ app.models.Doc = class Doc extends app.Model {
onError(); onError();
}; };
const success = data => { const success = (data) => {
this.installing = null; this.installing = null;
app.db.store(this, data, onSuccess, error); app.db.store(this, data, onSuccess, error);
}; };
@ -143,12 +171,14 @@ app.models.Doc = class Doc extends app.Model {
success, success,
error, error,
progress: onProgress, progress: onProgress,
timeout: 3600 timeout: 3600,
}); });
} }
uninstall(onSuccess, onError) { uninstall(onSuccess, onError) {
if (this.installing) { return; } if (this.installing) {
return;
}
this.installing = true; this.installing = true;
const success = () => { const success = () => {
@ -165,12 +195,16 @@ app.models.Doc = class Doc extends app.Model {
} }
getInstallStatus(callback) { getInstallStatus(callback) {
app.db.version(this, value => callback({installed: !!value, mtime: value})); app.db.version(this, (value) =>
callback({ installed: !!value, mtime: value }),
);
} }
isOutdated(status) { isOutdated(status) {
if (!status) { return false; } if (!status) {
const isInstalled = status.installed || app.settings.get('autoInstall'); return false;
return isInstalled && (this.mtime !== status.mtime); }
const isInstalled = status.installed || app.settings.get("autoInstall");
return isInstalled && this.mtime !== status.mtime;
} }
}; };

@ -8,63 +8,62 @@
*/ */
//= require app/searcher //= require app/searcher
(function() { (function () {
let applyAliases = undefined; let applyAliases = undefined;
const Cls = (app.models.Entry = class Entry extends app.Model { const Cls = (app.models.Entry = class Entry extends app.Model {
static initClass() { static initClass() {
let ALIASES; let ALIASES;
applyAliases = function(string) { applyAliases = function (string) {
if (ALIASES.hasOwnProperty(string)) { if (ALIASES.hasOwnProperty(string)) {
return [string, ALIASES[string]]; return [string, ALIASES[string]];
} else { } else {
const words = string.split('.'); const words = string.split(".");
for (let i = 0; i < words.length; i++) { for (let i = 0; i < words.length; i++) {
var word = words[i]; var word = words[i];
if (ALIASES.hasOwnProperty(word)) { if (ALIASES.hasOwnProperty(word)) {
words[i] = ALIASES[word]; words[i] = ALIASES[word];
return [string, words.join('.')]; return [string, words.join(".")];
} }
} }
} }
return string; return string;
}; };
this.ALIASES = (ALIASES = { this.ALIASES = ALIASES = {
'angular': 'ng', angular: "ng",
'angular.js': 'ng', "angular.js": "ng",
'backbone.js': 'bb', "backbone.js": "bb",
'c++': 'cpp', "c++": "cpp",
'coffeescript': 'cs', coffeescript: "cs",
'crystal': 'cr', crystal: "cr",
'elixir': 'ex', elixir: "ex",
'javascript': 'js', javascript: "js",
'julia': 'jl', julia: "jl",
'jquery': '$', jquery: "$",
'knockout.js': 'ko', "knockout.js": "ko",
'kubernetes': 'k8s', kubernetes: "k8s",
'less': 'ls', less: "ls",
'lodash': '_', lodash: "_",
'löve': 'love', löve: "love",
'marionette': 'mn', marionette: "mn",
'markdown': 'md', markdown: "md",
'matplotlib': 'mpl', matplotlib: "mpl",
'modernizr': 'mdr', modernizr: "mdr",
'moment.js': 'mt', "moment.js": "mt",
'openjdk': 'java', openjdk: "java",
'nginx': 'ngx', nginx: "ngx",
'numpy': 'np', numpy: "np",
'pandas': 'pd', pandas: "pd",
'postgresql': 'pg', postgresql: "pg",
'python': 'py', python: "py",
'ruby.on.rails': 'ror', "ruby.on.rails": "ror",
'ruby': 'rb', ruby: "rb",
'rust': 'rs', rust: "rs",
'sass': 'scss', sass: "scss",
'tensorflow': 'tf', tensorflow: "tf",
'typescript': 'ts', typescript: "ts",
'underscore.js': '_' "underscore.js": "_",
}); };
} }
// Attributes: name, type, path // Attributes: name, type, path
@ -75,16 +74,18 @@
addAlias(name) { addAlias(name) {
const text = applyAliases(app.Searcher.normalizeString(name)); const text = applyAliases(app.Searcher.normalizeString(name));
if (!Array.isArray(this.text)) { this.text = [this.text]; } if (!Array.isArray(this.text)) {
this.text = [this.text];
}
this.text.push(Array.isArray(text) ? text[1] : text); this.text.push(Array.isArray(text) ? text[1] : text);
} }
fullPath() { fullPath() {
return this.doc.fullPath(this.isIndex() ? '' : this.path); return this.doc.fullPath(this.isIndex() ? "" : this.path);
} }
dbPath() { dbPath() {
return this.path.replace(/#.*/, ''); return this.path.replace(/#.*/, "");
} }
filePath() { filePath() {
@ -96,17 +97,19 @@
} }
_filePath() { _filePath() {
let result = this.path.replace(/#.*/, ''); let result = this.path.replace(/#.*/, "");
if (result.slice(-5) !== '.html') { result += '.html'; } if (result.slice(-5) !== ".html") {
result += ".html";
}
return result; return result;
} }
isIndex() { isIndex() {
return this.path === 'index'; return this.path === "index";
} }
getType() { getType() {
return this.doc.types.findBy('name', this.type); return this.doc.types.findBy("name", this.type);
} }
loadFile(onSuccess, onError) { loadFile(onSuccess, onError) {

@ -2,6 +2,9 @@
// Sanity-check the conversion and remove this comment. // Sanity-check the conversion and remove this comment.
app.Model = class Model { app.Model = class Model {
constructor(attributes) { constructor(attributes) {
for (var key in attributes) { var value = attributes[key]; this[key] = value; } for (var key in attributes) {
var value = attributes[key];
this[key] = value;
}
} }
}; };

@ -13,14 +13,14 @@ app.models.Type = class Type extends app.Model {
} }
entries() { entries() {
return this.doc.entries.findAllBy('type', this.name); return this.doc.entries.findAllBy("type", this.name);
} }
toEntry() { toEntry() {
return new app.models.Entry({ return new app.models.Entry({
doc: this.doc, doc: this.doc,
name: `${this.doc.name} / ${this.name}`, name: `${this.doc.name} / ${this.name}`,
path: '..' + this.fullPath() path: ".." + this.fullPath(),
}); });
} }
}; };

@ -6,14 +6,16 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.templates.render = function(name, value, ...args) { app.templates.render = function (name, value, ...args) {
const template = app.templates[name]; const template = app.templates[name];
if (Array.isArray(value)) { if (Array.isArray(value)) {
let result = ''; let result = "";
for (var val of Array.from(value)) { result += template(val, ...Array.from(args)); } for (var val of Array.from(value)) {
result += template(val, ...Array.from(args));
}
return result; return result;
} else if (typeof template === 'function') { } else if (typeof template === "function") {
return template(value, ...Array.from(args)); return template(value, ...Array.from(args));
} else { } else {
return template; return template;

@ -7,62 +7,79 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const error = function(title, text, links) { const error = function (title, text, links) {
if (text == null) { text = ''; } if (text == null) {
if (links == null) { links = ''; } text = "";
if (text) { text = `<p class="_error-text">${text}</p>`; } }
if (links) { links = `<p class="_error-links">${links}</p>`; } if (links == null) {
links = "";
}
if (text) {
text = `<p class="_error-text">${text}</p>`;
}
if (links) {
links = `<p class="_error-links">${links}</p>`;
}
return `<div class="_error"><h1 class="_error-title">${title}</h1>${text}${links}</div>`; return `<div class="_error"><h1 class="_error-title">${title}</h1>${text}${links}</div>`;
}; };
const back = '<a href="#" data-behavior="back" class="_error-link">Go back</a>'; const back = '<a href="#" data-behavior="back" class="_error-link">Go back</a>';
app.templates.notFoundPage = () => error(" Page not found. ", app.templates.notFoundPage = () =>
" It may be missing from the source documentation or this could be a bug. ", error(
back); " Page not found. ",
" It may be missing from the source documentation or this could be a bug. ",
back,
);
app.templates.pageLoadError = () => error(" The page failed to load. ", app.templates.pageLoadError = () =>
` 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> error(
" The page failed to load. ",
` 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>
If you're online and you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. `, If you're online and you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. `,
` ${back} &middot; <a href="/#${location.pathname}" target="_top" class="_error-link">Reload</a> ` ${back} &middot; <a href="/#${location.pathname}" target="_top" class="_error-link">Reload</a>
&middot; <a href="#" class="_error-link" data-retry>Retry</a> ` &middot; <a href="#" class="_error-link" data-retry>Retry</a> `,
); );
app.templates.bootError = () => error(" The app failed to load. ", app.templates.bootError = () =>
` Check your Internet connection and try <a href="#" data-behavior="reload">reloading</a>.<br> error(
If you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. ` " The app failed to load. ",
); ` Check your Internet connection and try <a href="#" data-behavior="reload">reloading</a>.<br>
If you keep seeing this, you're likely behind a proxy or firewall that blocks cross-domain requests. `,
);
app.templates.offlineError = function(reason, exception) { app.templates.offlineError = function (reason, exception) {
if (reason === 'cookie_blocked') { if (reason === "cookie_blocked") {
return error(" Cookies must be enabled to use offline mode. "); return error(" Cookies must be enabled to use offline mode. ");
} }
reason = (() => { switch (reason) { reason = (() => {
case 'not_supported': switch (reason) {
return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> case "not_supported":
return ` DevDocs requires IndexedDB to cache documentations for offline access.<br>
Unfortunately your browser either doesn't support IndexedDB or doesn't make it available. `; Unfortunately your browser either doesn't support IndexedDB or doesn't make it available. `;
case 'buggy': case "buggy":
return ` DevDocs requires IndexedDB to cache documentations for offline access.<br> return ` DevDocs requires IndexedDB to cache documentations for offline access.<br>
Unfortunately your browser's implementation of IndexedDB contains bugs that prevent DevDocs from using it. `; Unfortunately your browser's implementation of IndexedDB contains bugs that prevent DevDocs from using it. `;
case 'private_mode': case "private_mode":
return ` Your browser appears to be running in private mode.<br> return ` Your browser appears to be running in private mode.<br>
This prevents DevDocs from caching documentations for offline access.`; This prevents DevDocs from caching documentations for offline access.`;
case 'exception': case "exception":
return ` An error occurred when trying to open the IndexedDB database:<br> return ` An error occurred when trying to open the IndexedDB database:<br>
<code class="_label">${exception.name}: ${exception.message}</code> `; <code class="_label">${exception.name}: ${exception.message}</code> `;
case 'cant_open': case "cant_open":
return ` An error occurred when trying to open the IndexedDB database:<br> return ` An error occurred when trying to open the IndexedDB database:<br>
<code class="_label">${exception.name}: ${exception.message}</code><br> <code class="_label">${exception.name}: ${exception.message}</code><br>
This could be because you're browsing in private mode or have disallowed offline storage on the domain. `; This could be because you're browsing in private mode or have disallowed offline storage on the domain. `;
case 'version': case "version":
return ` The IndexedDB database was modified with a newer version of the app.<br> return ` The IndexedDB database was modified with a newer version of the app.<br>
<a href="#" data-behavior="reload">Reload the page</a> to use offline mode. `; <a href="#" data-behavior="reload">Reload the page</a> to use offline mode. `;
case 'empty': case "empty":
return " The IndexedDB database appears to be corrupted. Try <a href=\"#\" data-behavior=\"reset\">resetting the app</a>. "; return ' The IndexedDB database appears to be corrupted. Try <a href="#" data-behavior="reset">resetting the app</a>. ';
} })(); }
})();
return error('Offline mode is unavailable.', reason); return error("Offline mode is unavailable.", reason);
}; };
app.templates.unsupportedBrowser = `\ app.templates.unsupportedBrowser = `\

@ -5,12 +5,12 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const notice = text => `<p class="_notice-text">${text}</p>`; const notice = (text) => `<p class="_notice-text">${text}</p>`;
app.templates.singleDocNotice = doc => notice(` You're browsing the ${doc.fullName} documentation. To browse all docs, go to app.templates.singleDocNotice = (doc) =>
<a href="//${app.config.production_host}" target="_top">${app.config.production_host}</a> (or press <code>esc</code>). ` notice(` You're browsing the ${doc.fullName} documentation. To browse all docs, go to
); <a href="//${app.config.production_host}" target="_top">${app.config.production_host}</a> (or press <code>esc</code>). `);
app.templates.disabledDocNotice = () => notice(` <strong>This documentation is disabled.</strong> app.templates.disabledDocNotice = () =>
To enable it, go to <a href="/settings" class="_notice-link">Preferences</a>. ` notice(` <strong>This documentation is disabled.</strong>
); To enable it, go to <a href="/settings" class="_notice-link">Preferences</a>. `);

@ -6,7 +6,7 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const notif = function(title, html) { const notif = function (title, html) {
html = html.replace(/<a /g, '<a class="_notif-link" '); html = html.replace(/<a /g, '<a class="_notif-link" ');
return ` <h5 class="_notif-title">${title}</h5> return ` <h5 class="_notif-title">${title}</h5>
${html} ${html}
@ -14,32 +14,56 @@ ${html}
`; `;
}; };
const textNotif = (title, message) => notif(title, `<p class="_notif-text">${message}`); const textNotif = (title, message) =>
notif(title, `<p class="_notif-text">${message}`);
app.templates.notifUpdateReady = () => textNotif("<span data-behavior=\"reboot\">DevDocs has been updated.</span>", app.templates.notifUpdateReady = () =>
"<span data-behavior=\"reboot\"><a href=\"#\" data-behavior=\"reboot\">Reload the page</a> to use the new version.</span>"); textNotif(
'<span data-behavior="reboot">DevDocs has been updated.</span>',
'<span data-behavior="reboot"><a href="#" data-behavior="reboot">Reload the page</a> to use the new version.</span>',
);
app.templates.notifError = () => textNotif(" Oops, an error occurred. ", app.templates.notifError = () =>
` Try <a href="#" data-behavior="hard-reload">reloading</a>, and if the problem persists, textNotif(
" Oops, an error occurred. ",
` Try <a href="#" data-behavior="hard-reload">reloading</a>, and if the problem persists,
<a href="#" data-behavior="reset">resetting the app</a>.<br> <a href="#" data-behavior="reset">resetting the app</a>.<br>
You can also report this issue on <a href="https://github.com/freeCodeCamp/devdocs/issues/new" target="_blank" rel="noopener">GitHub</a>. ` You can also report this issue on <a href="https://github.com/freeCodeCamp/devdocs/issues/new" target="_blank" rel="noopener">GitHub</a>. `,
); );
app.templates.notifQuotaExceeded = () => textNotif(" The offline database has exceeded its size limitation. ", app.templates.notifQuotaExceeded = () =>
" 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. "); textNotif(
" The offline database has exceeded its size limitation. ",
" 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. ",
);
app.templates.notifCookieBlocked = () => textNotif(" Please enable cookies. ", app.templates.notifCookieBlocked = () =>
" DevDocs will not work properly if cookies are disabled. "); textNotif(
" Please enable cookies. ",
" DevDocs will not work properly if cookies are disabled. ",
);
app.templates.notifInvalidLocation = () => textNotif(` DevDocs must be loaded from ${app.config.production_host} `, app.templates.notifInvalidLocation = () =>
" Otherwise things are likely to break. "); textNotif(
` DevDocs must be loaded from ${app.config.production_host} `,
" Otherwise things are likely to break. ",
);
app.templates.notifImportInvalid = () => textNotif(" Oops, an error occurred. ", app.templates.notifImportInvalid = () =>
" The file you selected is invalid. "); textNotif(
" Oops, an error occurred. ",
" The file you selected is invalid. ",
);
app.templates.notifNews = news => notif('Changelog', `<div class="_notif-content _notif-news">${app.templates.newsList(news, {years: false})}</div>`); app.templates.notifNews = (news) =>
notif(
"Changelog",
`<div class="_notif-content _notif-news">${app.templates.newsList(news, {
years: false,
})}</div>`,
);
app.templates.notifUpdates = function(docs, disabledDocs) { app.templates.notifUpdates = function (docs, disabledDocs) {
let doc; let doc;
let html = '<div class="_notif-content _notif-news">'; let html = '<div class="_notif-content _notif-news">';
@ -48,9 +72,11 @@ app.templates.notifUpdates = function(docs, disabledDocs) {
html += '<ul class="_notif-list">'; html += '<ul class="_notif-list">';
for (doc of Array.from(docs)) { for (doc of Array.from(docs)) {
html += `<li>${doc.name}`; html += `<li>${doc.name}`;
if (doc.release) { html += ` <code>&rarr;</code> ${doc.release}`; } if (doc.release) {
html += ` <code>&rarr;</code> ${doc.release}`;
}
} }
html += '</ul></div>'; html += "</ul></div>";
} }
if (disabledDocs.length > 0) { if (disabledDocs.length > 0) {
@ -58,26 +84,35 @@ app.templates.notifUpdates = function(docs, disabledDocs) {
html += '<ul class="_notif-list">'; html += '<ul class="_notif-list">';
for (doc of Array.from(disabledDocs)) { for (doc of Array.from(disabledDocs)) {
html += `<li>${doc.name}`; html += `<li>${doc.name}`;
if (doc.release) { html += ` <code>&rarr;</code> ${doc.release}`; } if (doc.release) {
html += "<span class=\"_notif-info\"><a href=\"/settings\">Enable</a></span>"; html += ` <code>&rarr;</code> ${doc.release}`;
}
html += '<span class="_notif-info"><a href="/settings">Enable</a></span>';
} }
html += '</ul></div>'; html += "</ul></div>";
} }
return notif('Updates', `${html}</div>`); return notif("Updates", `${html}</div>`);
}; };
app.templates.notifShare = () => textNotif(" Hi there! ", app.templates.notifShare = () =>
` Like DevDocs? Help us reach more developers by sharing the link with your friends on textNotif(
" Hi there! ",
` Like DevDocs? Help us reach more developers by sharing the link with your friends on
<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>, <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>,
<a href="https://out.devdocs.io/s/re" target="_blank" rel="noopener">Reddit</a>, etc.<br>Thanks :) ` <a href="https://out.devdocs.io/s/re" target="_blank" rel="noopener">Reddit</a>, etc.<br>Thanks :) `,
); );
app.templates.notifUpdateDocs = () => textNotif(" Documentation updates available. ", app.templates.notifUpdateDocs = () =>
" <a href=\"/offline\">Install them</a> as soon as possible to avoid broken pages. "); textNotif(
" Documentation updates available. ",
' <a href="/offline">Install them</a> as soon as possible to avoid broken pages. ',
);
app.templates.notifAnalyticsConsent = () => textNotif(" Tracking cookies ", app.templates.notifAnalyticsConsent = () =>
` We would like to gather usage data about how DevDocs is used through Google Analytics and Gauges. We only collect anonymous traffic information. textNotif(
" Tracking cookies ",
` We would like to gather usage data about how DevDocs is used through Google Analytics and Gauges. We only collect anonymous traffic information.
Please confirm if you accept our tracking cookies. You can always change your decision in the settings. Please confirm if you accept our tracking cookies. You can always change your decision in the settings.
<br><span class="_notif-right"><a href="#" data-behavior="accept-analytics">Accept</a> or <a href="#" data-behavior="decline-analytics">Decline</a></span> ` <br><span class="_notif-right"><a href="#" data-behavior="accept-analytics">Accept</a> or <a href="#" data-behavior="decline-analytics">Decline</a></span> `,
); );

@ -8,12 +8,18 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.templates.aboutPage = function() { app.templates.aboutPage = function () {
let doc; let doc;
const all_docs = app.docs.all().concat(...Array.from(app.disabledDocs.all() || [])); const all_docs = app.docs
.all()
.concat(...Array.from(app.disabledDocs.all() || []));
// de-duplicate docs by doc.name // de-duplicate docs by doc.name
const docs = []; const docs = [];
for (doc of Array.from(all_docs)) { if (!(docs.find(d => d.name === doc.name))) { docs.push(doc); } } for (doc of Array.from(all_docs)) {
if (!docs.find((d) => d.name === doc.name)) {
docs.push(doc);
}
}
return `\ return `\
<nav class="_toc" role="directory"> <nav class="_toc" role="directory">
<h3 class="_toc-title">Table of Contents</h3> <h3 class="_toc-title">Table of Contents</h3>
@ -79,18 +85,23 @@ app.templates.aboutPage = function() {
<th>Documentation <th>Documentation
<th>Copyright/License <th>Copyright/License
<th>Source code <th>Source code
${((() => { ${(() => {
const result = []; const result = [];
for (doc of Array.from(docs)) { result.push(`<tr> \ for (doc of Array.from(docs)) {
<td><a href=\"${(doc.links != null ? doc.links.home : undefined)}\">${doc.name}</a></td> \ result.push(`<tr> \
<td><a href=\"${doc.links != null ? doc.links.home : undefined}\">${
doc.name
}</a></td> \
<td>${doc.attribution}</td> \ <td>${doc.attribution}</td> \
<td><a href=\"${(doc.links != null ? doc.links.code : undefined)}\">Source code</a></td> \ <td><a href=\"${
doc.links != null ? doc.links.code : undefined
}\">Source code</a></td> \
</tr>`); </tr>`);
} }
return result; return result;
})()).join('')} })().join("")}
</table> </table>
</div> </div>

@ -6,11 +6,11 @@
* DS205: Consider reworking code to avoid use of IIFEs * DS205: Consider reworking code to avoid use of IIFEs
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.templates.helpPage = function() { app.templates.helpPage = function () {
let key, value; let key, value;
const ctrlKey = $.isMac() ? 'cmd' : 'ctrl'; const ctrlKey = $.isMac() ? "cmd" : "ctrl";
const navKey = $.isMac() ? 'cmd' : 'alt'; const navKey = $.isMac() ? "cmd" : "alt";
const arrowScroll = app.settings.get('arrowScroll'); const arrowScroll = app.settings.get("arrowScroll");
const aliases_one = {}; const aliases_one = {};
const aliases_two = {}; const aliases_two = {};
@ -18,7 +18,8 @@ app.templates.helpPage = function() {
const middle = Math.ceil(keys.length / 2) - 1; const middle = Math.ceil(keys.length / 2) - 1;
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
key = keys[i]; key = keys[i];
(i > middle ? aliases_two : aliases_one)[key] = app.models.Entry.ALIASES[key]; (i > middle ? aliases_two : aliases_one)[key] =
app.models.Entry.ALIASES[key];
} }
return `\ return `\
@ -79,12 +80,12 @@ app.templates.helpPage = function() {
<h3 class="_shortcuts-title">Sidebar</h3> <h3 class="_shortcuts-title">Sidebar</h3>
<dl class="_shortcuts-dl"> <dl class="_shortcuts-dl">
<dt class="_shortcuts-dt"> <dt class="_shortcuts-dt">
${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ''} ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ""}
<code class="_shortcut-code">&darr;</code> <code class="_shortcut-code">&darr;</code>
<code class="_shortcut-code">&uarr;</code> <code class="_shortcut-code">&uarr;</code>
<dd class="_shortcuts-dd">Move selection <dd class="_shortcuts-dd">Move selection
<dt class="_shortcuts-dt"> <dt class="_shortcuts-dt">
${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ''} ${arrowScroll ? '<code class="_shortcut-code">shift</code> + ' : ""}
<code class="_shortcut-code">&rarr;</code> <code class="_shortcut-code">&rarr;</code>
<code class="_shortcut-code">&larr;</code> <code class="_shortcut-code">&larr;</code>
<dd class="_shortcuts-dd">Show/hide sub-list <dd class="_shortcuts-dd">Show/hide sub-list
@ -105,15 +106,16 @@ app.templates.helpPage = function() {
<code class="_shortcut-code">${navKey} + &rarr;</code> <code class="_shortcut-code">${navKey} + &rarr;</code>
<dd class="_shortcuts-dd">Go back/forward <dd class="_shortcuts-dd">Go back/forward
<dt class="_shortcuts-dt"> <dt class="_shortcuts-dt">
${arrowScroll ? ${
'<code class="_shortcut-code">&darr;</code> ' + arrowScroll
? '<code class="_shortcut-code">&darr;</code> ' +
'<code class="_shortcut-code">&uarr;</code>' '<code class="_shortcut-code">&uarr;</code>'
: : '<code class="_shortcut-code">alt + &darr;</code> ' +
'<code class="_shortcut-code">alt + &darr;</code> ' +
'<code class="_shortcut-code">alt + &uarr;</code>' + '<code class="_shortcut-code">alt + &uarr;</code>' +
'<br>' + "<br>" +
'<code class="_shortcut-code">shift + &darr;</code> ' + '<code class="_shortcut-code">shift + &darr;</code> ' +
'<code class="_shortcut-code">shift + &uarr;</code>'} '<code class="_shortcut-code">shift + &uarr;</code>'
}
<dd class="_shortcuts-dd">Scroll step by step<br><br> <dd class="_shortcuts-dd">Scroll step by step<br><br>
<dt class="_shortcuts-dt"> <dt class="_shortcuts-dt">
<code class="_shortcut-code">space</code> <code class="_shortcut-code">space</code>
@ -167,27 +169,31 @@ app.templates.helpPage = function() {
<tr> <tr>
<th>Word <th>Word
<th>Alias <th>Alias
${((() => { ${(() => {
const result = []; const result = [];
for (key in aliases_one) { for (key in aliases_one) {
value = aliases_one[key]; value = aliases_one[key];
result.push(`<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`); result.push(
} `<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`,
return result; );
})()).join('')} }
return result;
})().join("")}
</table> </table>
<table> <table>
<tr> <tr>
<th>Word <th>Word
<th>Alias <th>Alias
${((() => { ${(() => {
const result1 = []; const result1 = [];
for (key in aliases_two) { for (key in aliases_two) {
value = aliases_two[key]; value = aliases_two[key];
result1.push(`<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`); result1.push(
} `<tr><td class=\"_code\">${key}<td class=\"_code\">${value}`,
return result1; );
})()).join('')} }
return result1;
})().join("")}
</table> </table>
</div> </div>
<p>Feel free to suggest new aliases on <a href="https://github.com/freeCodeCamp/devdocs/issues/new">GitHub</a>.\ <p>Feel free to suggest new aliases on <a href="https://github.com/freeCodeCamp/devdocs/issues/new">GitHub</a>.\

@ -5,12 +5,14 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.templates.offlinePage = docs => `\ app.templates.offlinePage = (docs) => `\
<h1 class="_lined-heading">Offline Documentation</h1> <h1 class="_lined-heading">Offline Documentation</h1>
<div class="_docs-tools"> <div class="_docs-tools">
<label> <label>
<input type="checkbox" name="autoUpdate" value="1" ${app.settings.get('manualUpdate') ? '' : 'checked'}>Install updates automatically <input type="checkbox" name="autoUpdate" value="1" ${
app.settings.get("manualUpdate") ? "" : "checked"
}>Install updates automatically
</label> </label>
<div class="_docs-links"> <div class="_docs-links">
<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> <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 => `\
</dl>\ </dl>\
`; `;
var canICloseTheTab = function() { var canICloseTheTab = function () {
if (app.ServiceWorker.isEnabled()) { if (app.ServiceWorker.isEnabled()) {
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). "; 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). ';
} else { } else {
let reason = "aren't available in your browser (or are disabled)"; let reason = "aren't available in your browser (or are disabled)";
if (app.config.env !== 'production') { if (app.config.env !== "production") {
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>)"; 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>)";
} }
return ` No. Service Workers ${reason}, so loading <a href="//devdocs.io">devdocs.io</a> offline won't work.<br> 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
} }
}; };
app.templates.offlineDoc = function(doc, status) { app.templates.offlineDoc = function (doc, status) {
const outdated = doc.isOutdated(status); const outdated = doc.isOutdated(status);
let html = `\ let html = `\
<tr data-slug="${doc.slug}"${outdated ? ' class="_highlight"' : ''}> <tr data-slug="${doc.slug}"${outdated ? ' class="_highlight"' : ""}>
<td class="_docs-name _icon-${doc.icon}">${doc.fullName}</td> <td class="_docs-name _icon-${doc.icon}">${doc.fullName}</td>
<td class="_docs-size">${Math.ceil(doc.db_size / 100000) / 10}&nbsp;<small>MB</small></td>\ <td class="_docs-size">${
Math.ceil(doc.db_size / 100000) / 10
}&nbsp;<small>MB</small></td>\
`; `;
html += !(status && status.installed) ? html += !(status && status.installed)
`\ ? `\
<td>-</td> <td>-</td>
<td><button type="button" class="_btn-link" data-action="install">Install</button></td>\ <td><button type="button" class="_btn-link" data-action="install">Install</button></td>\
` `
: outdated ? : outdated
`\ ? `\
<td><strong>Outdated</strong></td> <td><strong>Outdated</strong></td>
<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>\ <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>\
` `
: : `\
`\
<td>Up&#8209;to&#8209;date</td> <td>Up&#8209;to&#8209;date</td>
<td><button type="button" class="_btn-link" data-action="uninstall">Uninstall</button></td>\ <td><button type="button" class="_btn-link" data-action="uninstall">Uninstall</button></td>\
`; `;
return html + '</tr>'; return html + "</tr>";
}; };

@ -7,23 +7,32 @@
*/ */
const themeOption = ({ label, value }, settings) => `\ const themeOption = ({ label, value }, settings) => `\
<label class="_settings-label _theme-label"> <label class="_settings-label _theme-label">
<input type="radio" name="theme" value="${value}"${settings.theme === value ? ' checked' : ''}> <input type="radio" name="theme" value="${value}"${
settings.theme === value ? " checked" : ""
}>
${label} ${label}
</label>\ </label>\
`; `;
app.templates.settingsPage = settings => `\ app.templates.settingsPage = (settings) => `\
<h1 class="_lined-heading">Preferences</h1> <h1 class="_lined-heading">Preferences</h1>
<div class="_settings-fieldset"> <div class="_settings-fieldset">
<h2 class="_settings-legend">Theme:</h2> <h2 class="_settings-legend">Theme:</h2>
<div class="_settings-inputs"> <div class="_settings-inputs">
${settings.autoSupported ? ${
themeOption({label: "Automatic <small>Matches system setting</small>", value: "auto"}, settings) settings.autoSupported
: ? themeOption(
""} {
${themeOption({label: "Light", value: "default"}, settings)} label: "Automatic <small>Matches system setting</small>",
${themeOption({label: "Dark", value: "dark"}, settings)} value: "auto",
},
settings,
)
: ""
}
${themeOption({ label: "Light", value: "default" }, settings)}
${themeOption({ label: "Dark", value: "dark" }, settings)}
</div> </div>
</div> </div>
@ -32,24 +41,36 @@ app.templates.settingsPage = settings => `\
<div class="_settings-inputs"> <div class="_settings-inputs">
<label class="_settings-label _setting-max-width"> <label class="_settings-label _setting-max-width">
<input type="checkbox" form="settings" name="layout" value="_max-width"${settings['_max-width'] ? ' checked' : ''}>Enable fixed-width layout <input type="checkbox" form="settings" name="layout" value="_max-width"${
settings["_max-width"] ? " checked" : ""
}>Enable fixed-width layout
</label> </label>
<label class="_settings-label _setting-text-justify-hyphenate"> <label class="_settings-label _setting-text-justify-hyphenate">
<input type="checkbox" form="settings" name="layout" value="_text-justify-hyphenate"${settings['_text-justify-hyphenate'] ? ' checked' : ''}>Enable justified layout and automatic hyphenation <input type="checkbox" form="settings" name="layout" value="_text-justify-hyphenate"${
settings["_text-justify-hyphenate"] ? " checked" : ""
}>Enable justified layout and automatic hyphenation
</label> </label>
<label class="_settings-label _hide-on-mobile"> <label class="_settings-label _hide-on-mobile">
<input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"${settings['_sidebar-hidden'] ? ' checked' : ''}>Automatically hide and show the sidebar <input type="checkbox" form="settings" name="layout" value="_sidebar-hidden"${
settings["_sidebar-hidden"] ? " checked" : ""
}>Automatically hide and show the sidebar
<small>Tip: drag the edge of the sidebar to resize it.</small> <small>Tip: drag the edge of the sidebar to resize it.</small>
</label> </label>
<label class="_settings-label _hide-on-mobile"> <label class="_settings-label _hide-on-mobile">
<input type="checkbox" form="settings" name="noAutofocus" value="_no-autofocus"${settings.noAutofocus ? ' checked' : ''}>Disable autofocus of search input <input type="checkbox" form="settings" name="noAutofocus" value="_no-autofocus"${
settings.noAutofocus ? " checked" : ""
}>Disable autofocus of search input
</label> </label>
<label class="_settings-label"> <label class="_settings-label">
<input type="checkbox" form="settings" name="autoInstall" value="_auto-install"${settings.autoInstall ? ' checked' : ''}>Automatically download documentation for offline use <input type="checkbox" form="settings" name="autoInstall" value="_auto-install"${
settings.autoInstall ? " checked" : ""
}>Automatically download documentation for offline use
<small>Only enable this when bandwidth isn't a concern to you.</small> <small>Only enable this when bandwidth isn't a concern to you.</small>
</label> </label>
<label class="_settings-label _hide-in-development"> <label class="_settings-label _hide-in-development">
<input type="checkbox" form="settings" name="analyticsConsent"${settings.analyticsConsent ? ' checked' : ''}>Enable tracking cookies <input type="checkbox" form="settings" name="analyticsConsent"${
settings.analyticsConsent ? " checked" : ""
}>Enable tracking cookies
<small>With this checked, we enable Google Analytics and Gauges to collect anonymous traffic information.</small> <small>With this checked, we enable Google Analytics and Gauges to collect anonymous traffic information.</small>
</label> </label>
</div> </div>
@ -60,20 +81,30 @@ app.templates.settingsPage = settings => `\
<div class="_settings-inputs"> <div class="_settings-inputs">
<label class="_settings-label"> <label class="_settings-label">
<input type="checkbox" form="settings" name="smoothScroll" value="1"${settings.smoothScroll ? ' checked' : ''}>Use smooth scrolling <input type="checkbox" form="settings" name="smoothScroll" value="1"${
settings.smoothScroll ? " checked" : ""
}>Use smooth scrolling
</label> </label>
<label class="_settings-label _setting-native-scrollbar"> <label class="_settings-label _setting-native-scrollbar">
<input type="checkbox" form="settings" name="layout" value="_native-scrollbars"${settings['_native-scrollbars'] ? ' checked' : ''}>Use native scrollbars <input type="checkbox" form="settings" name="layout" value="_native-scrollbars"${
settings["_native-scrollbars"] ? " checked" : ""
}>Use native scrollbars
</label> </label>
<label class="_settings-label"> <label class="_settings-label">
<input type="checkbox" form="settings" name="arrowScroll" value="1"${settings.arrowScroll ? ' checked' : ''}>Use arrow keys to scroll the main content area <input type="checkbox" form="settings" name="arrowScroll" value="1"${
settings.arrowScroll ? " checked" : ""
}>Use arrow keys to scroll the main content area
<small>With this checked, use <code class="_label">shift</code> + <code class="_label">&uarr;</code><code class="_label">&darr;</code><code class="_label">&larr;</code><code class="_label">&rarr;</code> to navigate the sidebar.</small> <small>With this checked, use <code class="_label">shift</code> + <code class="_label">&uarr;</code><code class="_label">&darr;</code><code class="_label">&larr;</code><code class="_label">&rarr;</code> to navigate the sidebar.</small>
</label> </label>
<label class="_settings-label"> <label class="_settings-label">
<input type="checkbox" form="settings" name="spaceScroll" value="1"${settings.spaceScroll ? ' checked' : ''}>Use spacebar to scroll during search <input type="checkbox" form="settings" name="spaceScroll" value="1"${
settings.spaceScroll ? " checked" : ""
}>Use spacebar to scroll during search
</label> </label>
<label class="_settings-label"> <label class="_settings-label">
<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 <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
<small>Time in seconds</small> <small>Time in seconds</small>
</label> </label>
</div> </div>

@ -5,7 +5,13 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.templates.typePage = type => ` <h1>${type.doc.fullName} / ${type.name}</h1> app.templates.typePage = (type) => ` <h1>${type.doc.fullName} / ${
<ul class="_entry-list">${app.templates.render('typePageEntry', type.entries())}</ul> `; type.name
}</h1>
<ul class="_entry-list">${app.templates.render(
"typePageEntry",
type.entries(),
)}</ul> `;
app.templates.typePageEntry = entry => `<li><a href="${entry.fullPath()}">${$.escape(entry.name)}</a></li>`; app.templates.typePageEntry = (entry) =>
`<li><a href="${entry.fullPath()}">${$.escape(entry.name)}</a></li>`;

@ -5,11 +5,19 @@
* DS102: Remove unnecessary code created because of implicit returns * DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const arrow = "<svg class=\"_path-arrow\"><use xlink:href=\"#icon-dir\"/></svg>"; const arrow = '<svg class="_path-arrow"><use xlink:href="#icon-dir"/></svg>';
app.templates.path = function(doc, type, entry) { app.templates.path = function (doc, type, entry) {
let html = `<a href="${doc.fullPath()}" class="_path-item _icon-${doc.icon}">${doc.fullName}</a>`; let html = `<a href="${doc.fullPath()}" class="_path-item _icon-${
if (type) { html += `${arrow}<a href="${type.fullPath()}" class="_path-item">${type.name}</a>`; } doc.icon
if (entry) { html += `${arrow}<span class="_path-item">${$.escape(entry.name)}</span>`; } }">${doc.fullName}</a>`;
if (type) {
html += `${arrow}<a href="${type.fullPath()}" class="_path-item">${
type.name
}</a>`;
}
if (entry) {
html += `${arrow}<span class="_path-item">${$.escape(entry.name)}</span>`;
}
return html; return html;
}; };

@ -6,74 +6,112 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
const { const { templates } = app;
templates
} = app;
const arrow = "<svg class=\"_list-arrow\"><use xlink:href=\"#icon-dir\"/></svg>"; const arrow = '<svg class="_list-arrow"><use xlink:href="#icon-dir"/></svg>';
templates.sidebarDoc = function(doc, options) { templates.sidebarDoc = function (doc, options) {
if (options == null) { options = {}; } if (options == null) {
let link = `<a href="${doc.fullPath()}" class="_list-item _icon-${doc.icon} `; options = {};
link += options.disabled ? '_list-disabled' : '_list-dir'; }
let link = `<a href="${doc.fullPath()}" class="_list-item _icon-${doc.icon} `;
link += options.disabled ? "_list-disabled" : "_list-dir";
link += `" data-slug="${doc.slug}" title="${doc.fullName}" tabindex="-1">`; link += `" data-slug="${doc.slug}" title="${doc.fullName}" tabindex="-1">`;
if (options.disabled) { if (options.disabled) {
link += `<span class="_list-enable" data-enable="${doc.slug}">Enable</span>`; link += `<span class="_list-enable" data-enable="${doc.slug}">Enable</span>`;
} else { } else {
link += arrow; link += arrow;
} }
if (doc.release) { link += `<span class="_list-count">${doc.release}</span>`; } if (doc.release) {
link += `<span class="_list-count">${doc.release}</span>`;
}
link += `<span class="_list-text">${doc.name}`; link += `<span class="_list-text">${doc.name}`;
if (options.fullName || (options.disabled && doc.version)) { link += ` ${doc.version}`; } if (options.fullName || (options.disabled && doc.version)) {
link += ` ${doc.version}`;
}
return link + "</span></a>"; return link + "</span></a>";
}; };
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>`; 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>`;
templates.sidebarEntry = entry => `<a href="${entry.fullPath()}" class="_list-item _list-hover" tabindex="-1">${$.escape(entry.name)}</a>`; templates.sidebarEntry = (entry) =>
`<a href="${entry.fullPath()}" class="_list-item _list-hover" tabindex="-1">${$.escape(
entry.name,
)}</a>`;
templates.sidebarResult = function(entry) { templates.sidebarResult = function (entry) {
let addons = entry.isIndex() && app.disabledDocs.contains(entry.doc) ? let addons =
`<span class="_list-enable" data-enable="${entry.doc.slug}">Enable</span>` entry.isIndex() && app.disabledDocs.contains(entry.doc)
: ? `<span class="_list-enable" data-enable="${entry.doc.slug}">Enable</span>`
"<span class=\"_list-reveal\" data-reset-list title=\"Reveal in list\"></span>"; : '<span class="_list-reveal" data-reset-list title="Reveal in list"></span>';
if (entry.doc.version && !entry.isIndex()) { addons += `<span class="_list-count">${entry.doc.short_version}</span>`; } if (entry.doc.version && !entry.isIndex()) {
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>`; addons += `<span class="_list-count">${entry.doc.short_version}</span>`;
}
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>`;
}; };
templates.sidebarNoResults = function() { templates.sidebarNoResults = function () {
let html = " <div class=\"_list-note\">No results.</div> "; let html = ' <div class="_list-note">No results.</div> ';
if (!app.isSingleDoc() && !app.disabledDocs.isEmpty()) { html += `\ if (!app.isSingleDoc() && !app.disabledDocs.isEmpty()) {
html += `\
<div class="_list-note">Note: documentations must be <a href="/settings" class="_list-note-link">enabled</a> to appear in the search.</div>\ <div class="_list-note">Note: documentations must be <a href="/settings" class="_list-note-link">enabled</a> to appear in the search.</div>\
`; } `;
}
return html; return html;
}; };
templates.sidebarPageLink = count => `<span role="link" class="_list-item _list-pagelink">Show more\u2026 (${count})</span>`; templates.sidebarPageLink = (count) =>
`<span role="link" class="_list-item _list-pagelink">Show more\u2026 (${count})</span>`;
templates.sidebarLabel = function(doc, options) { templates.sidebarLabel = function (doc, options) {
if (options == null) { options = {}; } if (options == null) {
let label = "<label class=\"_list-item"; options = {};
if (!doc.version) { label += ` _icon-${doc.icon}`; } }
let label = '<label class="_list-item';
if (!doc.version) {
label += ` _icon-${doc.icon}`;
}
label += `"><input type="checkbox" name="${doc.slug}" class="_list-checkbox" `; label += `"><input type="checkbox" name="${doc.slug}" class="_list-checkbox" `;
if (options.checked) { label += "checked"; } if (options.checked) {
label += "checked";
}
return label + `><span class="_list-text">${doc.fullName}</span></label>`; return label + `><span class="_list-text">${doc.fullName}</span></label>`;
}; };
templates.sidebarVersionedDoc = function(doc, versions, options) { templates.sidebarVersionedDoc = function (doc, versions, options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
let html = `<div class="_list-item _list-dir _list-rdir _icon-${doc.icon}`; let html = `<div class="_list-item _list-dir _list-rdir _icon-${doc.icon}`;
if (options.open) { html += " open"; } if (options.open) {
return html + `" tabindex="0">${arrow}${doc.name}</div><div class="_list _list-sub">${versions}</div>`; html += " open";
}
return (
html +
`" tabindex="0">${arrow}${doc.name}</div><div class="_list _list-sub">${versions}</div>`
);
}; };
templates.sidebarDisabled = options => `<h6 class="_list-title">${arrow}Disabled (${options.count}) <a href="/settings" class="_list-title-link" tabindex="-1">Customize</a></h6>`; templates.sidebarDisabled = (options) =>
`<h6 class="_list-title">${arrow}Disabled (${options.count}) <a href="/settings" class="_list-title-link" tabindex="-1">Customize</a></h6>`;
templates.sidebarDisabledList = html => `<div class="_disabled-list">${html}</div>`; templates.sidebarDisabledList = (html) =>
`<div class="_disabled-list">${html}</div>`;
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>`; 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>`;
templates.docPickerHeader = "<div class=\"_list-picker-head\"><span>Documentation</span> <span>Enable</span></div>"; templates.docPickerHeader =
'<div class="_list-picker-head"><span>Documentation</span> <span>Enable</span></div>';
templates.docPickerNote = `\ templates.docPickerNote = `\
<div class="_list-note">Tip: for faster and better search results, select only the docs you need.</div> <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 = () => `\
<strong>ProTip</strong> <strong>ProTip</strong>
<span class="_notif-info">(click to dismiss)</span> <span class="_notif-info">(click to dismiss)</span>
<p class="_notif-text"> <p class="_notif-text">
Hit ${app.settings.get('arrowScroll') ? '<code class="_label">shift</code> +' : ''} <code class="_label">&darr;</code> <code class="_label">&uarr;</code> <code class="_label">&larr;</code> <code class="_label">&rarr;</code> to navigate the sidebar.<br> Hit ${
Hit <code class="_label">space / shift space</code>${app.settings.get('arrowScroll') ? ' or <code class="_label">&darr;/&uarr;</code>' : ', <code class="_label">alt &darr;/&uarr;</code> or <code class="_label">shift &darr;/&uarr;</code>'} to scroll the page. app.settings.get("arrowScroll") ? '<code class="_label">shift</code> +' : ""
} <code class="_label">&darr;</code> <code class="_label">&uarr;</code> <code class="_label">&larr;</code> <code class="_label">&rarr;</code> to navigate the sidebar.<br>
Hit <code class="_label">space / shift space</code>${
app.settings.get("arrowScroll")
? ' or <code class="_label">&darr;/&uarr;</code>'
: ', <code class="_label">alt &darr;/&uarr;</code> or <code class="_label">shift &darr;/&uarr;</code>'
} to scroll the page.
<p class="_notif-text"> <p class="_notif-text">
<a href="/help#shortcuts" class="_notif-link">See all keyboard shortcuts</a>\ <a href="/help#shortcuts" class="_notif-link">See all keyboard shortcuts</a>\
`; `;

@ -1,32 +1,55 @@
try { try {
if (app.config.env === 'production') { if (app.config.env === "production") {
if (Cookies.get('analyticsConsent') === '1') { if (Cookies.get("analyticsConsent") === "1") {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function (i, s, o, g, r, a, m) {
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), i["GoogleAnalyticsObject"] = r;
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) (i[r] =
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); i[r] ||
ga('create', 'UA-5544833-12', 'devdocs.io'); function () {
page.track(function() { (i[r].q = i[r].q || []).push(arguments);
ga('send', 'pageview', { }),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://www.google-analytics.com/analytics.js",
"ga",
);
ga("create", "UA-5544833-12", "devdocs.io");
page.track(function () {
ga("send", "pageview", {
page: location.pathname + location.search + location.hash, page: location.pathname + location.search + location.hash,
dimension1: app.router.context && app.router.context.doc && app.router.context.doc.slug_without_version dimension1:
app.router.context &&
app.router.context.doc &&
app.router.context.doc.slug_without_version,
}); });
}); });
page.track(function() { page.track(function () {
if (window._gauges) if (window._gauges) _gauges.push(["track"]);
_gauges.push(['track']);
else else
(function() { (function () {
var _gauges=_gauges||[];!function(){var a=document.createElement("script"); var _gauges = _gauges || [];
a.type="text/javascript",a.async=!0,a.id="gauges-tracker", !(function () {
a.setAttribute("data-site-id","51c15f82613f5d7819000067"), var a = document.createElement("script");
a.src="https://secure.gaug.es/track.js";var b=document.getElementsByTagName("script")[0]; (a.type = "text/javascript"),
b.parentNode.insertBefore(a,b)}(); (a.async = !0),
(a.id = "gauges-tracker"),
a.setAttribute("data-site-id", "51c15f82613f5d7819000067"),
(a.src = "https://secure.gaug.es/track.js");
var b = document.getElementsByTagName("script")[0];
b.parentNode.insertBefore(a, b);
})();
})(); })();
}); });
} else { } else {
resetAnalytics(); resetAnalytics();
} }
} }
} catch(e) { } } catch (e) {}

@ -5,171 +5,204 @@
* This is free and unencumbered software released into the public domain. * This is free and unencumbered software released into the public domain.
*/ */
(function (global, undefined) { (function (global, undefined) {
'use strict'; "use strict";
var factory = function (window) { var factory = function (window) {
if (typeof window.document !== 'object') { if (typeof window.document !== "object") {
throw new Error('Cookies.js requires a `window` with a `document` object'); throw new Error(
"Cookies.js requires a `window` with a `document` object",
);
}
var Cookies = function (key, value, options) {
return arguments.length === 1
? Cookies.get(key)
: Cookies.set(key, value, options);
};
// Allows for setter injection in unit tests
Cookies._document = window.document;
// Used to ensure cookie keys do not collide with
// built-in `Object` properties
Cookies._cacheKeyPrefix = "cookey."; // Hurr hurr, :)
Cookies._maxExpireDate = new Date("Fri, 31 Dec 9999 23:59:59 UTC");
Cookies.defaults = {
path: "/",
SameSite: "Strict",
secure: true,
};
Cookies.get = function (key) {
if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) {
Cookies._renewCache();
}
var value = Cookies._cache[Cookies._cacheKeyPrefix + key];
return value === undefined ? undefined : decodeURIComponent(value);
};
Cookies.set = function (key, value, options) {
options = Cookies._getExtendedOptions(options);
options.expires = Cookies._getExpiresDate(
value === undefined ? -1 : options.expires,
);
Cookies._document.cookie = Cookies._generateCookieString(
key,
value,
options,
);
return Cookies;
};
Cookies.expire = function (key, options) {
return Cookies.set(key, undefined, options);
};
Cookies._getExtendedOptions = function (options) {
return {
path: (options && options.path) || Cookies.defaults.path,
domain: (options && options.domain) || Cookies.defaults.domain,
SameSite: (options && options.SameSite) || Cookies.defaults.SameSite,
expires: (options && options.expires) || Cookies.defaults.expires,
secure:
options && options.secure !== undefined
? options.secure
: Cookies.defaults.secure,
};
};
Cookies._isValidDate = function (date) {
return (
Object.prototype.toString.call(date) === "[object Date]" &&
!isNaN(date.getTime())
);
};
Cookies._getExpiresDate = function (expires, now) {
now = now || new Date();
if (typeof expires === "number") {
expires =
expires === Infinity
? Cookies._maxExpireDate
: new Date(now.getTime() + expires * 1000);
} else if (typeof expires === "string") {
expires = new Date(expires);
}
if (expires && !Cookies._isValidDate(expires)) {
throw new Error(
"`expires` parameter cannot be converted to a valid Date instance",
);
}
return expires;
};
Cookies._generateCookieString = function (key, value, options) {
key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent);
key = key.replace(/\(/g, "%28").replace(/\)/g, "%29");
value = (value + "").replace(
/[^!#$&-+\--:<-\[\]-~]/g,
encodeURIComponent,
);
options = options || {};
var cookieString = key + "=" + value;
cookieString += options.path ? ";path=" + options.path : "";
cookieString += options.domain ? ";domain=" + options.domain : "";
cookieString += options.SameSite ? ";SameSite=" + options.SameSite : "";
cookieString += options.expires
? ";expires=" + options.expires.toUTCString()
: "";
cookieString += options.secure ? ";secure" : "";
return cookieString;
};
Cookies._getCacheFromString = function (documentCookie) {
var cookieCache = {};
var cookiesArray = documentCookie ? documentCookie.split("; ") : [];
for (var i = 0; i < cookiesArray.length; i++) {
var cookieKvp = Cookies._getKeyValuePairFromCookieString(
cookiesArray[i],
);
if (
cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined
) {
cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] =
cookieKvp.value;
} }
}
var Cookies = function (key, value, options) { return cookieCache;
return arguments.length === 1 ? };
Cookies.get(key) : Cookies.set(key, value, options);
};
// Allows for setter injection in unit tests Cookies._getKeyValuePairFromCookieString = function (cookieString) {
Cookies._document = window.document; // "=" is a valid character in a cookie value according to RFC6265, so cannot `split('=')`
var separatorIndex = cookieString.indexOf("=");
// Used to ensure cookie keys do not collide with
// built-in `Object` properties // IE omits the "=" when the cookie value is an empty string
Cookies._cacheKeyPrefix = 'cookey.'; // Hurr hurr, :) separatorIndex =
separatorIndex < 0 ? cookieString.length : separatorIndex;
var key = cookieString.substr(0, separatorIndex);
var decodedKey;
try {
decodedKey = decodeURIComponent(key);
} catch (e) {
if (console && typeof console.error === "function") {
console.error('Could not decode cookie with key "' + key + '"', e);
}
}
Cookies._maxExpireDate = new Date('Fri, 31 Dec 9999 23:59:59 UTC'); return {
key: decodedKey,
value: cookieString.substr(separatorIndex + 1), // Defer decoding value until accessed
};
};
Cookies.defaults = { Cookies._renewCache = function () {
path: '/', Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie);
SameSite: 'Strict', Cookies._cachedDocumentCookie = Cookies._document.cookie;
secure: true
};
Cookies.get = function (key) {
if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) {
Cookies._renewCache();
}
var value = Cookies._cache[Cookies._cacheKeyPrefix + key];
return value === undefined ? undefined : decodeURIComponent(value);
};
Cookies.set = function (key, value, options) {
options = Cookies._getExtendedOptions(options);
options.expires = Cookies._getExpiresDate(value === undefined ? -1 : options.expires);
Cookies._document.cookie = Cookies._generateCookieString(key, value, options);
return Cookies;
};
Cookies.expire = function (key, options) {
return Cookies.set(key, undefined, options);
};
Cookies._getExtendedOptions = function (options) {
return {
path: options && options.path || Cookies.defaults.path,
domain: options && options.domain || Cookies.defaults.domain,
SameSite: options && options.SameSite || Cookies.defaults.SameSite,
expires: options && options.expires || Cookies.defaults.expires,
secure: options && options.secure !== undefined ? options.secure : Cookies.defaults.secure
};
};
Cookies._isValidDate = function (date) {
return Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());
};
Cookies._getExpiresDate = function (expires, now) {
now = now || new Date();
if (typeof expires === 'number') {
expires = expires === Infinity ?
Cookies._maxExpireDate : new Date(now.getTime() + expires * 1000);
} else if (typeof expires === 'string') {
expires = new Date(expires);
}
if (expires && !Cookies._isValidDate(expires)) {
throw new Error('`expires` parameter cannot be converted to a valid Date instance');
}
return expires;
};
Cookies._generateCookieString = function (key, value, options) {
key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent);
key = key.replace(/\(/g, '%28').replace(/\)/g, '%29');
value = (value + '').replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent);
options = options || {};
var cookieString = key + '=' + value;
cookieString += options.path ? ';path=' + options.path : '';
cookieString += options.domain ? ';domain=' + options.domain : '';
cookieString += options.SameSite ? ';SameSite=' + options.SameSite : '';
cookieString += options.expires ? ';expires=' + options.expires.toUTCString() : '';
cookieString += options.secure ? ';secure' : '';
return cookieString;
};
Cookies._getCacheFromString = function (documentCookie) {
var cookieCache = {};
var cookiesArray = documentCookie ? documentCookie.split('; ') : [];
for (var i = 0; i < cookiesArray.length; i++) {
var cookieKvp = Cookies._getKeyValuePairFromCookieString(cookiesArray[i]);
if (cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined) {
cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = cookieKvp.value;
}
}
return cookieCache;
};
Cookies._getKeyValuePairFromCookieString = function (cookieString) {
// "=" is a valid character in a cookie value according to RFC6265, so cannot `split('=')`
var separatorIndex = cookieString.indexOf('=');
// IE omits the "=" when the cookie value is an empty string
separatorIndex = separatorIndex < 0 ? cookieString.length : separatorIndex;
var key = cookieString.substr(0, separatorIndex);
var decodedKey;
try {
decodedKey = decodeURIComponent(key);
} catch (e) {
if (console && typeof console.error === 'function') {
console.error('Could not decode cookie with key "' + key + '"', e);
}
}
return {
key: decodedKey,
value: cookieString.substr(separatorIndex + 1) // Defer decoding value until accessed
};
};
Cookies._renewCache = function () {
Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie);
Cookies._cachedDocumentCookie = Cookies._document.cookie;
};
Cookies._areEnabled = function () {
var testKey = 'cookies.js';
var areEnabled = Cookies.set(testKey, 1).get(testKey) === '1';
Cookies.expire(testKey);
return areEnabled;
};
Cookies.enabled = Cookies._areEnabled();
return Cookies;
}; };
var cookiesExport = (global && typeof global.document === 'object') ? factory(global) : factory;
// AMD support Cookies._areEnabled = function () {
if (typeof define === 'function' && define.amd) { var testKey = "cookies.js";
define(function () { return cookiesExport; }); var areEnabled = Cookies.set(testKey, 1).get(testKey) === "1";
Cookies.expire(testKey);
return areEnabled;
};
Cookies.enabled = Cookies._areEnabled();
return Cookies;
};
var cookiesExport =
global && typeof global.document === "object" ? factory(global) : factory;
// AMD support
if (typeof define === "function" && define.amd) {
define(function () {
return cookiesExport;
});
// CommonJS/Node.js support // CommonJS/Node.js support
} else if (typeof exports === 'object') { } else if (typeof exports === "object") {
// Support Node.js specific `module.exports` (which can be a function) // Support Node.js specific `module.exports` (which can be a function)
if (typeof module === 'object' && typeof module.exports === 'object') { if (typeof module === "object" && typeof module.exports === "object") {
exports = module.exports = cookiesExport; exports = module.exports = cookiesExport;
}
// But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)
exports.Cookies = cookiesExport;
} else {
global.Cookies = cookiesExport;
} }
})(typeof window === 'undefined' ? this : window); // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)
exports.Cookies = cookiesExport;
} else {
global.Cookies = cookiesExport;
}
})(typeof window === "undefined" ? this : window);

@ -4,17 +4,22 @@
* Adapted from: https://github.com/fred-wang/mathml.css */ * Adapted from: https://github.com/fred-wang/mathml.css */
(function () { (function () {
window.addEventListener("load", function() { window.addEventListener("load", function () {
var box, div, link, namespaceURI; var box, div, link, namespaceURI;
// First check whether the page contains any <math> element. // First check whether the page contains any <math> element.
namespaceURI = "http://www.w3.org/1998/Math/MathML"; namespaceURI = "http://www.w3.org/1998/Math/MathML";
// Create a div to test mspace, using Kuma's "offscreen" CSS // Create a div to test mspace, using Kuma's "offscreen" CSS
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>"); 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>",
);
div = document.body.firstChild; div = document.body.firstChild;
box = div.firstChild.firstChild.getBoundingClientRect(); box = div.firstChild.firstChild.getBoundingClientRect();
document.body.removeChild(div); document.body.removeChild(div);
if (Math.abs(box.height - 23) > 1 || Math.abs(box.width - 77) > 1) { if (Math.abs(box.height - 23) > 1 || Math.abs(box.width - 77) > 1) {
window.supportsMathML = false; window.supportsMathML = false;
} }
}); });
}()); })();

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -32,51 +32,46 @@ const Cls = (app.views.Content = class Content extends app.View {
} }
static initClass() { static initClass() {
this.el = '._content'; this.el = "._content";
this.loadingClass = '_content-loading'; this.loadingClass = "_content-loading";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.shortcuts = { this.shortcuts = {
altUp: 'scrollStepUp', altUp: "scrollStepUp",
altDown: 'scrollStepDown', altDown: "scrollStepDown",
pageUp: 'scrollPageUp', pageUp: "scrollPageUp",
pageDown: 'scrollPageDown', pageDown: "scrollPageDown",
pageTop: 'scrollToTop', pageTop: "scrollToTop",
pageBottom: 'scrollToBottom', pageBottom: "scrollToBottom",
altF: 'onAltF' altF: "onAltF",
}; };
this.routes = { this.routes = {
before: 'beforeRoute', before: "beforeRoute",
after: 'afterRoute' after: "afterRoute",
}; };
} }
init() { init() {
this.scrollEl = app.isMobile() ? this.scrollEl = app.isMobile()
(document.scrollingElement || document.body) ? document.scrollingElement || document.body
: : this.el;
this.el;
this.scrollMap = {}; this.scrollMap = {};
this.scrollStack = []; this.scrollStack = [];
this.rootPage = new app.views.RootPage; this.rootPage = new app.views.RootPage();
this.staticPage = new app.views.StaticPage; this.staticPage = new app.views.StaticPage();
this.settingsPage = new app.views.SettingsPage; this.settingsPage = new app.views.SettingsPage();
this.offlinePage = new app.views.OfflinePage; this.offlinePage = new app.views.OfflinePage();
this.typePage = new app.views.TypePage; this.typePage = new app.views.TypePage();
this.entryPage = new app.views.EntryPage; this.entryPage = new app.views.EntryPage();
this.entryPage this.entryPage
.on('loading', this.onEntryLoading) .on("loading", this.onEntryLoading)
.on('loaded', this.onEntryLoaded); .on("loaded", this.onEntryLoaded);
app
.on('ready', this.onReady)
.on('bootError', this.onBootError);
app.on("ready", this.onReady).on("bootError", this.onBootError);
} }
show(view) { show(view) {
@ -85,7 +80,7 @@ const Cls = (app.views.Content = class Content extends app.View {
if (this.view != null) { if (this.view != null) {
this.view.deactivate(); this.view.deactivate();
} }
this.html(this.view = view); this.html((this.view = view));
this.view.activate(); this.view.activate();
} }
} }
@ -107,7 +102,7 @@ const Cls = (app.views.Content = class Content extends app.View {
} }
smoothScrollTo(value) { smoothScrollTo(value) {
if (app.settings.get('fastScroll')) { if (app.settings.get("fastScroll")) {
this.scrollTo(value); this.scrollTo(value);
} else { } else {
$.smoothScroll(this.scrollEl, value || 0); $.smoothScroll(this.scrollEl, value || 0);
@ -144,10 +139,14 @@ const Cls = (app.views.Content = class Content extends app.View {
scrollToTarget() { scrollToTarget() {
let el; let el;
if (this.routeCtx.hash && (el = this.findTargetByHash(this.routeCtx.hash))) { if (
$.scrollToWithImageLock(el, this.scrollEl, 'top', this.routeCtx.hash &&
{margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top}); (el = this.findTargetByHash(this.routeCtx.hash))
$.highlight(el, {className: '_highlight'}); ) {
$.scrollToWithImageLock(el, this.scrollEl, "top", {
margin: this.scrollEl === this.el ? 0 : $.offset(this.el).top,
});
$.highlight(el, { className: "_highlight" });
} else { } else {
this.scrollTo(this.scrollMap[this.routeCtx.state.id]); this.scrollTo(this.scrollMap[this.routeCtx.state.id]);
} }
@ -159,7 +158,7 @@ const Cls = (app.views.Content = class Content extends app.View {
onBootError() { onBootError() {
this.hideLoading(); this.hideLoading();
this.html(this.tmpl('bootError')); this.html(this.tmpl("bootError"));
} }
onEntryLoading() { onEntryLoading() {
@ -186,8 +185,12 @@ const Cls = (app.views.Content = class Content extends app.View {
} }
cacheScrollPosition() { cacheScrollPosition() {
if (!this.routeCtx || this.routeCtx.hash) { return; } if (!this.routeCtx || this.routeCtx.hash) {
if (this.routeCtx.path === '/') { return; } return;
}
if (this.routeCtx.path === "/") {
return;
}
if (this.scrollMap[this.routeCtx.state.id] == null) { if (this.scrollMap[this.routeCtx.state.id] == null) {
this.scrollStack.push(this.routeCtx.state.id); this.scrollStack.push(this.routeCtx.state.id);
@ -200,24 +203,24 @@ const Cls = (app.views.Content = class Content extends app.View {
} }
afterRoute(route, context) { afterRoute(route, context) {
if ((route !== 'entry') && (route !== 'type')) { if (route !== "entry" && route !== "type") {
resetFavicon(); resetFavicon();
} }
switch (route) { switch (route) {
case 'root': case "root":
this.show(this.rootPage); this.show(this.rootPage);
break; break;
case 'entry': case "entry":
this.show(this.entryPage); this.show(this.entryPage);
break; break;
case 'type': case "type":
this.show(this.typePage); this.show(this.typePage);
break; break;
case 'settings': case "settings":
this.show(this.settingsPage); this.show(this.settingsPage);
break; break;
case 'offline': case "offline":
this.show(this.offlinePage); this.show(this.offlinePage);
break; break;
default: default:
@ -225,37 +228,59 @@ const Cls = (app.views.Content = class Content extends app.View {
} }
this.view.onRoute(context); this.view.onRoute(context);
app.document.setTitle(typeof this.view.getTitle === 'function' ? this.view.getTitle() : undefined); app.document.setTitle(
typeof this.view.getTitle === "function"
? this.view.getTitle()
: undefined,
);
} }
onClick(event) { onClick(event) {
const link = $.closestLink($.eventTarget(event), this.el); const link = $.closestLink($.eventTarget(event), this.el);
if (link && this.isExternalUrl(link.getAttribute('href'))) { if (link && this.isExternalUrl(link.getAttribute("href"))) {
$.stopEvent(event); $.stopEvent(event);
$.popup(link); $.popup(link);
} }
} }
onAltF(event) { onAltF(event) {
if (!document.activeElement || !$.hasChild(this.el, document.activeElement)) { if (
__guard__(this.find('a:not(:empty)'), x => x.focus()); !document.activeElement ||
!$.hasChild(this.el, document.activeElement)
) {
__guard__(this.find("a:not(:empty)"), (x) => x.focus());
return $.stopEvent(event); return $.stopEvent(event);
} }
} }
findTargetByHash(hash) { findTargetByHash(hash) {
let el = (() => { try { return $.id(decodeURIComponent(hash)); } catch (error) {} })(); let el = (() => {
if (!el) { el = (() => { try { return $.id(hash); } catch (error1) {} })(); } try {
return $.id(decodeURIComponent(hash));
} catch (error) {}
})();
if (!el) {
el = (() => {
try {
return $.id(hash);
} catch (error1) {}
})();
}
return el; return el;
} }
isExternalUrl(url) { isExternalUrl(url) {
let needle; let needle;
return (needle = __guard__(url, x => x.slice(0, 6)), ['http:/', 'https:'].includes(needle)); return (
(needle = __guard__(url, (x) => x.slice(0, 6))),
["http:/", "https:"].includes(needle)
);
} }
}); });
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -10,7 +10,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let LINKS = undefined; let LINKS = undefined;
const Cls = (app.views.EntryPage = class EntryPage extends app.View { const Cls = (app.views.EntryPage = class EntryPage extends app.View {
constructor(...args) { constructor(...args) {
@ -24,23 +24,21 @@
} }
static initClass() { static initClass() {
this.className = '_page'; this.className = "_page";
this.errorClass = '_page-error'; this.errorClass = "_page-error";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.shortcuts = { this.shortcuts = {
altC: 'onAltC', altC: "onAltC",
altO: 'onAltO' altO: "onAltO",
}; };
this.routes = this.routes = { before: "beforeRoute" };
{before: 'beforeRoute'};
LINKS = { LINKS = {
home: 'Homepage', home: "Homepage",
code: 'Source code' code: "Source code",
}; };
} }
@ -58,61 +56,84 @@
loading() { loading() {
this.empty(); this.empty();
this.trigger('loading'); this.trigger("loading");
} }
render(content, fromCache) { render(content, fromCache) {
if (content == null) { content = ''; } if (content == null) {
if (fromCache == null) { fromCache = false; } content = "";
if (!this.activated) { return; } }
if (fromCache == null) {
fromCache = false;
}
if (!this.activated) {
return;
}
this.empty(); this.empty();
this.subview = new (this.subViewClass())(this.el, this.entry); this.subview = new (this.subViewClass())(this.el, this.entry);
$.batchUpdate(this.el, () => { $.batchUpdate(this.el, () => {
this.subview.render(content, fromCache); this.subview.render(content, fromCache);
if (!fromCache) { this.addCopyButtons(); } if (!fromCache) {
this.addCopyButtons();
}
}); });
if (app.disabledDocs.findBy('slug', this.entry.doc.slug)) { if (app.disabledDocs.findBy("slug", this.entry.doc.slug)) {
this.hiddenView = new app.views.HiddenPage(this.el, this.entry); this.hiddenView = new app.views.HiddenPage(this.el, this.entry);
} }
setFaviconForDoc(this.entry.doc); setFaviconForDoc(this.entry.doc);
this.delay(this.polyfillMathML); this.delay(this.polyfillMathML);
this.trigger('loaded'); this.trigger("loaded");
} }
addCopyButtons() { addCopyButtons() {
if (!this.copyButton) { if (!this.copyButton) {
this.copyButton = document.createElement('button'); this.copyButton = document.createElement("button");
this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>'; this.copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>';
this.copyButton.type = 'button'; this.copyButton.type = "button";
this.copyButton.className = '_pre-clip'; this.copyButton.className = "_pre-clip";
this.copyButton.title = 'Copy to clipboard'; this.copyButton.title = "Copy to clipboard";
this.copyButton.setAttribute('aria-label', 'Copy to clipboard'); this.copyButton.setAttribute("aria-label", "Copy to clipboard");
}
for (var el of Array.from(this.findAllByTag("pre"))) {
el.appendChild(this.copyButton.cloneNode(true));
} }
for (var el of Array.from(this.findAllByTag('pre'))) { el.appendChild(this.copyButton.cloneNode(true)); }
} }
polyfillMathML() { polyfillMathML() {
if ((window.supportsMathML !== false) || !!this.polyfilledMathML || !this.findByTag('math')) { return; } if (
window.supportsMathML !== false ||
!!this.polyfilledMathML ||
!this.findByTag("math")
) {
return;
}
this.polyfilledMathML = true; this.polyfilledMathML = true;
$.append(document.head, `<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`); $.append(
document.head,
`<link rel="stylesheet" href="${app.config.mathml_stylesheet}">`,
);
} }
prepareContent(content) { prepareContent(content) {
if (!this.entry.isIndex() || !this.entry.doc.links) { return content; } if (!this.entry.isIndex() || !this.entry.doc.links) {
return content;
}
const links = (() => { const links = (() => {
const result = []; const result = [];
for (var link in this.entry.doc.links) { for (var link in this.entry.doc.links) {
var url = this.entry.doc.links[link]; var url = this.entry.doc.links[link];
result.push(`<a href="${url}" class="_links-link">${LINKS[link]}</a>`); result.push(
`<a href="${url}" class="_links-link">${LINKS[link]}</a>`,
);
} }
return result; return result;
})(); })();
return `<p class="_links">${links.join('')}</p>${content}`; return `<p class="_links">${links.join("")}</p>${content}`;
} }
empty() { empty() {
@ -131,11 +152,17 @@
} }
subViewClass() { subViewClass() {
return app.views[`${$.classify(this.entry.doc.type)}Page`] || app.views.BasePage; return (
app.views[`${$.classify(this.entry.doc.type)}Page`] ||
app.views.BasePage
);
} }
getTitle() { getTitle() {
return this.entry.doc.fullName + (this.entry.isIndex() ? ' documentation' : ` / ${this.entry.name}`); return (
this.entry.doc.fullName +
(this.entry.isIndex() ? " documentation" : ` / ${this.entry.name}`)
);
} }
beforeRoute() { beforeRoute() {
@ -144,9 +171,13 @@
} }
onRoute(context) { onRoute(context) {
const isSameFile = context.entry.filePath() === (this.entry != null ? this.entry.filePath() : undefined); const isSameFile =
context.entry.filePath() ===
(this.entry != null ? this.entry.filePath() : undefined);
this.entry = context.entry; this.entry = context.entry;
if (!isSameFile) { this.restore() || this.load(); } if (!isSameFile) {
this.restore() || this.load();
}
} }
load() { load() {
@ -157,19 +188,21 @@
abort() { abort() {
if (this.xhr) { if (this.xhr) {
this.xhr.abort(); this.xhr.abort();
this.xhr = (this.entry = null); this.xhr = this.entry = null;
} }
} }
onSuccess(response) { onSuccess(response) {
if (!this.activated) { return; } if (!this.activated) {
return;
}
this.xhr = null; this.xhr = null;
this.render(this.prepareContent(response)); this.render(this.prepareContent(response));
} }
onError() { onError() {
this.xhr = null; this.xhr = null;
this.render(this.tmpl('pageLoadError')); this.render(this.tmpl("pageLoadError"));
this.resetClass(); this.resetClass();
this.addClass(this.constructor.errorClass); this.addClass(this.constructor.errorClass);
if (app.serviceWorker != null) { if (app.serviceWorker != null) {
@ -179,7 +212,13 @@
cache() { cache() {
let path; let path;
if (this.xhr || !this.entry || this.cacheMap[(path = this.entry.filePath())]) { return; } if (
this.xhr ||
!this.entry ||
this.cacheMap[(path = this.entry.filePath())]
) {
return;
}
this.cacheMap[path] = this.el.innerHTML; this.cacheMap[path] = this.el.innerHTML;
this.cacheStack.push(path); this.cacheStack.push(path);
@ -199,26 +238,34 @@
onClick(event) { onClick(event) {
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.hasAttribute('data-retry')) { if (target.hasAttribute("data-retry")) {
$.stopEvent(event); $.stopEvent(event);
this.load(); this.load();
} else if (target.classList.contains('_pre-clip')) { } else if (target.classList.contains("_pre-clip")) {
$.stopEvent(event); $.stopEvent(event);
target.classList.add($.copyToClipboard(target.parentNode.textContent) ? '_pre-clip-success' : '_pre-clip-error'); target.classList.add(
setTimeout((() => target.className = '_pre-clip'), 2000); $.copyToClipboard(target.parentNode.textContent)
? "_pre-clip-success"
: "_pre-clip-error",
);
setTimeout(() => (target.className = "_pre-clip"), 2000);
} }
} }
onAltC() { onAltC() {
let link; let link;
if (!(link = this.find('._attribution:last-child ._attribution-link'))) { return; } if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
return;
}
console.log(link.href + location.hash); console.log(link.href + location.hash);
navigator.clipboard.writeText(link.href + location.hash); navigator.clipboard.writeText(link.href + location.hash);
} }
onAltO() { onAltO() {
let link; let link;
if (!(link = this.find('._attribution:last-child ._attribution-link'))) { return; } if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
return;
}
this.delay(() => $.popup(link.href + location.hash)); this.delay(() => $.popup(link.href + location.hash));
} }
}); });

@ -15,11 +15,11 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View {
} }
static initClass() { static initClass() {
this.className = '_static'; this.className = "_static";
this.events = { this.events = {
click: 'onClick', click: "onClick",
change: 'onChange' change: "onChange",
}; };
} }
@ -31,41 +31,49 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View {
render() { render() {
if (app.cookieBlocked) { if (app.cookieBlocked) {
this.html(this.tmpl('offlineError', 'cookie_blocked')); this.html(this.tmpl("offlineError", "cookie_blocked"));
return; return;
} }
app.docs.getInstallStatuses(statuses => { app.docs.getInstallStatuses((statuses) => {
if (!this.activated) { return; } if (!this.activated) {
return;
}
if (statuses === false) { if (statuses === false) {
this.html(this.tmpl('offlineError', app.db.reason, app.db.error)); this.html(this.tmpl("offlineError", app.db.reason, app.db.error));
} else { } else {
let html = ''; let html = "";
for (var doc of Array.from(app.docs.all())) { html += this.renderDoc(doc, statuses[doc.slug]); } for (var doc of Array.from(app.docs.all())) {
this.html(this.tmpl('offlinePage', html)); html += this.renderDoc(doc, statuses[doc.slug]);
}
this.html(this.tmpl("offlinePage", html));
this.refreshLinks(); this.refreshLinks();
} }
}); });
} }
renderDoc(doc, status) { renderDoc(doc, status) {
return app.templates.render('offlineDoc', doc, status); return app.templates.render("offlineDoc", doc, status);
} }
getTitle() { getTitle() {
return 'Offline'; return "Offline";
} }
refreshLinks() { refreshLinks() {
for (var action of ['install', 'update', 'uninstall']) { for (var action of ["install", "update", "uninstall"]) {
this.find(`[data-action-all='${action}']`).classList[this.find(`[data-action='${action}']`) ? 'add' : 'remove']('_show'); this.find(`[data-action-all='${action}']`).classList[
this.find(`[data-action='${action}']`) ? "add" : "remove"
]("_show");
} }
} }
docByEl(el) { docByEl(el) {
let slug; let slug;
while (!(slug = el.getAttribute('data-slug'))) { el = el.parentNode; } while (!(slug = el.getAttribute("data-slug"))) {
return app.docs.findBy('slug', slug); el = el.parentNode;
}
return app.docs.findBy("slug", slug);
} }
docEl(doc) { docEl(doc) {
@ -79,26 +87,44 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View {
onClick(event) { onClick(event) {
let action; let action;
let el = $.eventTarget(event); let el = $.eventTarget(event);
if (action = el.getAttribute('data-action')) { if ((action = el.getAttribute("data-action"))) {
const doc = this.docByEl(el); const doc = this.docByEl(el);
if (action === 'update') { action = 'install'; } if (action === "update") {
doc[action](this.onInstallSuccess.bind(this, doc), this.onInstallError.bind(this, doc), this.onInstallProgress.bind(this, doc)); action = "install";
el.parentNode.innerHTML = `${el.textContent.replace(/e$/, '')}ing…`; }
} else if (action = el.getAttribute('data-action-all') || el.parentElement.getAttribute('data-action-all')) { doc[action](
if ((action === 'uninstall') && !window.confirm('Uninstall all docs?')) { return; } this.onInstallSuccess.bind(this, doc),
this.onInstallError.bind(this, doc),
this.onInstallProgress.bind(this, doc),
);
el.parentNode.innerHTML = `${el.textContent.replace(/e$/, "")}ing…`;
} else if (
(action =
el.getAttribute("data-action-all") ||
el.parentElement.getAttribute("data-action-all"))
) {
if (action === "uninstall" && !window.confirm("Uninstall all docs?")) {
return;
}
app.db.migrate(); app.db.migrate();
for (el of Array.from(this.findAll(`[data-action='${action}']`))) { $.click(el); } for (el of Array.from(this.findAll(`[data-action='${action}']`))) {
$.click(el);
}
} }
} }
onInstallSuccess(doc) { onInstallSuccess(doc) {
if (!this.activated) { return; } if (!this.activated) {
doc.getInstallStatus(status => { return;
}
doc.getInstallStatus((status) => {
let el; let el;
if (!this.activated) { return; } if (!this.activated) {
if (el = this.docEl(doc)) { return;
}
if ((el = this.docEl(doc))) {
el.outerHTML = this.renderDoc(doc, status); el.outerHTML = this.renderDoc(doc, status);
$.highlight(el, {className: '_highlight'}); $.highlight(el, { className: "_highlight" });
this.refreshLinks(); this.refreshLinks();
} }
}); });
@ -106,24 +132,31 @@ const Cls = (app.views.OfflinePage = class OfflinePage extends app.View {
onInstallError(doc) { onInstallError(doc) {
let el; let el;
if (!this.activated) { return; } if (!this.activated) {
if (el = this.docEl(doc)) { return;
el.lastElementChild.textContent = 'Error'; }
if ((el = this.docEl(doc))) {
el.lastElementChild.textContent = "Error";
} }
} }
onInstallProgress(doc, event) { onInstallProgress(doc, event) {
let el; let el;
if (!this.activated || !event.lengthComputable) { return; } if (!this.activated || !event.lengthComputable) {
if (el = this.docEl(doc)) { return;
}
if ((el = this.docEl(doc))) {
const percentage = Math.round((event.loaded * 100) / event.total); const percentage = Math.round((event.loaded * 100) / event.total);
el.lastElementChild.textContent = el.lastElementChild.textContent.replace(/(\s.+)?$/, ` (${percentage}%)`); el.lastElementChild.textContent = el.lastElementChild.textContent.replace(
/(\s.+)?$/,
` (${percentage}%)`,
);
} }
} }
onChange(event) { onChange(event) {
if (event.target.name === 'autoUpdate') { if (event.target.name === "autoUpdate") {
app.settings.set('manualUpdate', !event.target.checked); app.settings.set("manualUpdate", !event.target.checked);
} }
} }
}); });

@ -14,26 +14,26 @@ const Cls = (app.views.RootPage = class RootPage extends app.View {
} }
static initClass() { static initClass() {
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
init() { init() {
if (!this.isHidden()) { this.setHidden(false); } // reserve space in local storage if (!this.isHidden()) {
this.setHidden(false);
} // reserve space in local storage
this.render(); this.render();
} }
render() { render() {
this.empty(); this.empty();
const tmpl = app.isAndroidWebview() ? const tmpl = app.isAndroidWebview()
'androidWarning' ? "androidWarning"
: this.isHidden() ? : this.isHidden()
'splash' ? "splash"
: app.isMobile() ? : app.isMobile()
'mobileIntro' ? "mobileIntro"
: : "intro";
'intro';
this.append(this.tmpl(tmpl)); this.append(this.tmpl(tmpl));
} }
@ -44,17 +44,17 @@ const Cls = (app.views.RootPage = class RootPage extends app.View {
} }
setHidden(value) { setHidden(value) {
app.settings.set('hideIntro', value); app.settings.set("hideIntro", value);
} }
isHidden() { isHidden() {
return app.isSingleDoc() || app.settings.get('hideIntro'); return app.isSingleDoc() || app.settings.get("hideIntro");
} }
onRoute() {} onRoute() {}
onClick(event) { onClick(event) {
if ($.eventTarget(event).hasAttribute('data-hide-intro')) { if ($.eventTarget(event).hasAttribute("data-hide-intro")) {
$.stopEvent(event); $.stopEvent(event);
this.hideIntro(); this.hideIntro();
} }

@ -17,39 +17,41 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View {
} }
static initClass() { static initClass() {
this.className = '_static'; this.className = "_static";
this.events = { this.events = {
click: 'onClick', click: "onClick",
change: 'onChange' change: "onChange",
}; };
} }
render() { render() {
this.html(this.tmpl('settingsPage', this.currentSettings())); this.html(this.tmpl("settingsPage", this.currentSettings()));
} }
currentSettings() { currentSettings() {
const settings = {}; const settings = {};
settings.theme = app.settings.get('theme'); settings.theme = app.settings.get("theme");
settings.smoothScroll = !app.settings.get('fastScroll'); settings.smoothScroll = !app.settings.get("fastScroll");
settings.arrowScroll = app.settings.get('arrowScroll'); settings.arrowScroll = app.settings.get("arrowScroll");
settings.noAutofocus = app.settings.get('noAutofocus'); settings.noAutofocus = app.settings.get("noAutofocus");
settings.autoInstall = app.settings.get('autoInstall'); settings.autoInstall = app.settings.get("autoInstall");
settings.analyticsConsent = app.settings.get('analyticsConsent'); settings.analyticsConsent = app.settings.get("analyticsConsent");
settings.spaceScroll = app.settings.get('spaceScroll'); settings.spaceScroll = app.settings.get("spaceScroll");
settings.spaceTimeout = app.settings.get('spaceTimeout'); settings.spaceTimeout = app.settings.get("spaceTimeout");
settings.autoSupported = app.settings.autoSupported; settings.autoSupported = app.settings.autoSupported;
for (var layout of Array.from(app.settings.LAYOUTS)) { settings[layout] = app.settings.hasLayout(layout); } for (var layout of Array.from(app.settings.LAYOUTS)) {
settings[layout] = app.settings.hasLayout(layout);
}
return settings; return settings;
} }
getTitle() { getTitle() {
return 'Preferences'; return "Preferences";
} }
setTheme(value) { setTheme(value) {
app.settings.set('theme', value); app.settings.set("theme", value);
} }
toggleLayout(layout, enable) { toggleLayout(layout, enable) {
@ -57,20 +59,22 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View {
} }
toggleSmoothScroll(enable) { toggleSmoothScroll(enable) {
app.settings.set('fastScroll', !enable); app.settings.set("fastScroll", !enable);
} }
toggleAnalyticsConsent(enable) { toggleAnalyticsConsent(enable) {
app.settings.set('analyticsConsent', enable ? '1' : '0'); app.settings.set("analyticsConsent", enable ? "1" : "0");
if (!enable) { resetAnalytics(); } if (!enable) {
resetAnalytics();
}
} }
toggleSpaceScroll(enable) { toggleSpaceScroll(enable) {
app.settings.set('spaceScroll', enable ? 1 : 0); app.settings.set("spaceScroll", enable ? 1 : 0);
} }
setScrollTimeout(value) { setScrollTimeout(value) {
return app.settings.set('spaceTimeout', value); return app.settings.set("spaceTimeout", value);
} }
toggle(name, enable) { toggle(name, enable) {
@ -78,31 +82,37 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View {
} }
export() { export() {
const data = new Blob([JSON.stringify(app.settings.export())], {type: 'application/json'}); const data = new Blob([JSON.stringify(app.settings.export())], {
const link = document.createElement('a'); type: "application/json",
});
const link = document.createElement("a");
link.href = URL.createObjectURL(data); link.href = URL.createObjectURL(data);
link.download = 'devdocs.json'; link.download = "devdocs.json";
link.style.display = 'none'; link.style.display = "none";
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
} }
import(file, input) { import(file, input) {
if (!file || (file.type !== 'application/json')) { if (!file || file.type !== "application/json") {
new app.views.Notif('ImportInvalid', {autoHide: false}); new app.views.Notif("ImportInvalid", { autoHide: false });
return; return;
} }
const reader = new FileReader(); const reader = new FileReader();
reader.onloadend = function() { reader.onloadend = function () {
const data = (() => { try { return JSON.parse(reader.result); } catch (error) {} })(); const data = (() => {
if (!data || (data.constructor !== Object)) { try {
new app.views.Notif('ImportInvalid', {autoHide: false}); return JSON.parse(reader.result);
} catch (error) {}
})();
if (!data || data.constructor !== Object) {
new app.views.Notif("ImportInvalid", { autoHide: false });
return; return;
} }
app.settings.import(data); app.settings.import(data);
$.trigger(input.form, 'import'); $.trigger(input.form, "import");
}; };
reader.readAsText(file); reader.readAsText(file);
} }
@ -110,25 +120,25 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View {
onChange(event) { onChange(event) {
const input = event.target; const input = event.target;
switch (input.name) { switch (input.name) {
case 'theme': case "theme":
this.setTheme(input.value); this.setTheme(input.value);
break; break;
case 'layout': case "layout":
this.toggleLayout(input.value, input.checked); this.toggleLayout(input.value, input.checked);
break; break;
case 'smoothScroll': case "smoothScroll":
this.toggleSmoothScroll(input.checked); this.toggleSmoothScroll(input.checked);
break; break;
case 'import': case "import":
this.import(input.files[0], input); this.import(input.files[0], input);
break; break;
case 'analyticsConsent': case "analyticsConsent":
this.toggleAnalyticsConsent(input.checked); this.toggleAnalyticsConsent(input.checked);
break; break;
case 'spaceScroll': case "spaceScroll":
this.toggleSpaceScroll(input.checked); this.toggleSpaceScroll(input.checked);
break; break;
case 'spaceTimeout': case "spaceTimeout":
this.setScrollTimeout(input.value); this.setScrollTimeout(input.value);
break; break;
default: default:
@ -138,8 +148,8 @@ const Cls = (app.views.SettingsPage = class SettingsPage extends app.View {
onClick(event) { onClick(event) {
const target = $.eventTarget(event); const target = $.eventTarget(event);
switch (target.getAttribute('data-action')) { switch (target.getAttribute("data-action")) {
case 'export': case "export":
$.stopEvent(event); $.stopEvent(event);
this.export(); this.export();
break; break;

@ -8,13 +8,13 @@
*/ */
const Cls = (app.views.StaticPage = class StaticPage extends app.View { const Cls = (app.views.StaticPage = class StaticPage extends app.View {
static initClass() { static initClass() {
this.className = '_static'; this.className = "_static";
this.titles = { this.titles = {
about: 'About', about: "About",
news: 'News', news: "News",
help: 'User Guide', help: "User Guide",
notFound: '404' notFound: "404",
}; };
} }
@ -35,7 +35,7 @@ const Cls = (app.views.StaticPage = class StaticPage extends app.View {
} }
onRoute(context) { onRoute(context) {
this.render(context.page || 'notFound'); this.render(context.page || "notFound");
} }
}); });
Cls.initClass(); Cls.initClass();

@ -8,7 +8,7 @@
*/ */
const Cls = (app.views.TypePage = class TypePage extends app.View { const Cls = (app.views.TypePage = class TypePage extends app.View {
static initClass() { static initClass() {
this.className = '_page'; this.className = "_page";
} }
deactivate() { deactivate() {
@ -20,7 +20,7 @@ const Cls = (app.views.TypePage = class TypePage extends app.View {
render(type) { render(type) {
this.type = type; this.type = type;
this.html(this.tmpl('typePage', this.type)); this.html(this.tmpl("typePage", this.type));
setFaviconForDoc(this.type.doc); setFaviconForDoc(this.type.doc);
} }

@ -18,40 +18,48 @@ const Cls = (app.views.Document = class Document extends app.View {
static initClass() { static initClass() {
this.el = document; this.el = document;
this.events = this.events = { visibilitychange: "onVisibilityChange" };
{visibilitychange: 'onVisibilityChange'};
this.shortcuts = { this.shortcuts = {
help: 'onHelp', help: "onHelp",
preferences: 'onPreferences', preferences: "onPreferences",
escape: 'onEscape', escape: "onEscape",
superLeft: 'onBack', superLeft: "onBack",
superRight: 'onForward' superRight: "onForward",
}; };
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
} }
init() { init() {
this.addSubview((this.menu = new app.views.Menu), this.addSubview(
this.addSubview(this.sidebar = new app.views.Sidebar)); (this.menu = new app.views.Menu()),
if (app.views.Resizer.isSupported()) { this.addSubview(this.resizer = new app.views.Resizer); } this.addSubview((this.sidebar = new app.views.Sidebar())),
this.addSubview(this.content = new app.views.Content); );
if (!app.isSingleDoc() && !app.isMobile()) { this.addSubview(this.path = new app.views.Path); } if (app.views.Resizer.isSupported()) {
if (!app.isSingleDoc()) { this.settings = new app.views.Settings; } this.addSubview((this.resizer = new app.views.Resizer()));
}
this.addSubview((this.content = new app.views.Content()));
if (!app.isSingleDoc() && !app.isMobile()) {
this.addSubview((this.path = new app.views.Path()));
}
if (!app.isSingleDoc()) {
this.settings = new app.views.Settings();
}
$.on(document.body, 'click', this.onClick); $.on(document.body, "click", this.onClick);
this.activate(); this.activate();
} }
setTitle(title) { setTitle(title) {
return this.el.title = title ? `${title} — DevDocs` : 'DevDocs API Documentation'; return (this.el.title = title
? `${title} — DevDocs`
: "DevDocs API Documentation");
} }
afterRoute(route) { afterRoute(route) {
if (route === 'settings') { if (route === "settings") {
if (this.settings != null) { if (this.settings != null) {
this.settings.activate(); this.settings.activate();
} }
@ -63,26 +71,29 @@ const Cls = (app.views.Document = class Document extends app.View {
} }
onVisibilityChange() { onVisibilityChange() {
if (this.el.visibilityState !== 'visible') { return; } if (this.el.visibilityState !== "visible") {
this.delay(function() { return;
if (app.isMobile() !== app.views.Mobile.detect()) { location.reload(); }
} }
, 300); this.delay(function () {
if (app.isMobile() !== app.views.Mobile.detect()) {
location.reload();
}
}, 300);
} }
onHelp() { onHelp() {
app.router.show('/help#shortcuts'); app.router.show("/help#shortcuts");
} }
onPreferences() { onPreferences() {
app.router.show('/settings'); app.router.show("/settings");
} }
onEscape() { onEscape() {
const path = !app.isSingleDoc() || (location.pathname === app.doc.fullPath()) ? const path =
'/' !app.isSingleDoc() || location.pathname === app.doc.fullPath()
: ? "/"
app.doc.fullPath(); : app.doc.fullPath();
app.router.show(path); app.router.show(path);
} }
@ -97,16 +108,34 @@ const Cls = (app.views.Document = class Document extends app.View {
onClick(event) { onClick(event) {
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (!target.hasAttribute('data-behavior')) { return; } if (!target.hasAttribute("data-behavior")) {
return;
}
$.stopEvent(event); $.stopEvent(event);
switch (target.getAttribute('data-behavior')) { switch (target.getAttribute("data-behavior")) {
case 'back': history.back(); break; case "back":
case 'reload': window.location.reload(); break; history.back();
case 'reboot': app.reboot(); break; break;
case 'hard-reload': app.reload(); break; case "reload":
case 'reset': if (confirm('Are you sure you want to reset DevDocs?')) { app.reset(); } break; window.location.reload();
case 'accept-analytics': Cookies.set('analyticsConsent', '1', {expires: 1e8}) && app.reboot(); break; break;
case 'decline-analytics': Cookies.set('analyticsConsent', '0', {expires: 1e8}) && app.reboot(); break; case "reboot":
app.reboot();
break;
case "hard-reload":
app.reload();
break;
case "reset":
if (confirm("Are you sure you want to reset DevDocs?")) {
app.reset();
}
break;
case "accept-analytics":
Cookies.set("analyticsConsent", "1", { expires: 1e8 }) && app.reboot();
break;
case "decline-analytics":
Cookies.set("analyticsConsent", "0", { expires: 1e8 }) && app.reboot();
break;
} }
} }
}); });

@ -13,25 +13,32 @@ const Cls = (app.views.Menu = class Menu extends app.View {
} }
static initClass() { static initClass() {
this.el = '._menu'; this.el = "._menu";
this.activeClass = 'active'; this.activeClass = "active";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
init() { init() {
$.on(document.body, 'click', this.onGlobalClick); $.on(document.body, "click", this.onGlobalClick);
} }
onClick(event) { onClick(event) {
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.tagName === 'A') { target.blur(); } if (target.tagName === "A") {
target.blur();
}
} }
onGlobalClick(event) { onGlobalClick(event) {
if (event.which !== 1) { return; } if (event.which !== 1) {
if (typeof event.target.hasAttribute === 'function' ? event.target.hasAttribute('data-toggle-menu') : undefined) { return;
}
if (
typeof event.target.hasAttribute === "function"
? event.target.hasAttribute("data-toggle-menu")
: undefined
) {
this.toggleClass(this.constructor.activeClass); this.toggleClass(this.constructor.activeClass);
} else if (this.hasClass(this.constructor.activeClass)) { } else if (this.hasClass(this.constructor.activeClass)) {
this.removeClass(this.constructor.activeClass); this.removeClass(this.constructor.activeClass);

@ -10,34 +10,36 @@
*/ */
const Cls = (app.views.Mobile = class Mobile extends app.View { const Cls = (app.views.Mobile = class Mobile extends app.View {
static initClass() { static initClass() {
this.className = '_mobile'; this.className = "_mobile";
this.elements = { this.elements = {
body: 'body', body: "body",
content: '._container', content: "._container",
sidebar: '._sidebar', sidebar: "._sidebar",
docPicker: '._settings ._sidebar' docPicker: "._settings ._sidebar",
}; };
this.shortcuts = this.shortcuts = { escape: "onEscape" };
{escape: 'onEscape'};
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
} }
static detect() { static detect() {
if (Cookies.get('override-mobile-detect') != null) { if (Cookies.get("override-mobile-detect") != null) {
return JSON.parse(Cookies.get('override-mobile-detect')); return JSON.parse(Cookies.get("override-mobile-detect"));
} }
try { try {
return (window.matchMedia('(max-width: 480px)').matches) || return (
(window.matchMedia('(max-width: 767px)').matches) || window.matchMedia("(max-width: 480px)").matches ||
(window.matchMedia('(max-height: 767px) and (max-width: 1024px)').matches) || window.matchMedia("(max-width: 767px)").matches ||
// Need to sniff the user agent because some Android and Windows Phone devices don't take window.matchMedia("(max-height: 767px) and (max-width: 1024px)")
// resolution (dpi) into account when reporting device width/height. .matches ||
((navigator.userAgent.indexOf('Android') !== -1) && (navigator.userAgent.indexOf('Mobile') !== -1)) || // Need to sniff the user agent because some Android and Windows Phone devices don't take
(navigator.userAgent.indexOf('IEMobile') !== -1); // resolution (dpi) into account when reporting device width/height.
(navigator.userAgent.indexOf("Android") !== -1 &&
navigator.userAgent.indexOf("Mobile") !== -1) ||
navigator.userAgent.indexOf("IEMobile") !== -1
);
} catch (error) { } catch (error) {
return false; return false;
} }
@ -67,30 +69,29 @@ const Cls = (app.views.Mobile = class Mobile extends app.View {
} }
init() { init() {
$.on($('._search'), 'touchend', this.onTapSearch); $.on($("._search"), "touchend", this.onTapSearch);
this.toggleSidebar = $('button[data-toggle-sidebar]'); this.toggleSidebar = $("button[data-toggle-sidebar]");
this.toggleSidebar.removeAttribute('hidden'); this.toggleSidebar.removeAttribute("hidden");
$.on(this.toggleSidebar, 'click', this.onClickToggleSidebar); $.on(this.toggleSidebar, "click", this.onClickToggleSidebar);
this.back = $('button[data-back]'); this.back = $("button[data-back]");
this.back.removeAttribute('hidden'); this.back.removeAttribute("hidden");
$.on(this.back, 'click', this.onClickBack); $.on(this.back, "click", this.onClickBack);
this.forward = $('button[data-forward]'); this.forward = $("button[data-forward]");
this.forward.removeAttribute('hidden'); this.forward.removeAttribute("hidden");
$.on(this.forward, 'click', this.onClickForward); $.on(this.forward, "click", this.onClickForward);
this.docPickerTab = $('button[data-tab="doc-picker"]'); this.docPickerTab = $('button[data-tab="doc-picker"]');
this.docPickerTab.removeAttribute('hidden'); this.docPickerTab.removeAttribute("hidden");
$.on(this.docPickerTab, 'click', this.onClickDocPickerTab); $.on(this.docPickerTab, "click", this.onClickDocPickerTab);
this.settingsTab = $('button[data-tab="settings"]'); this.settingsTab = $('button[data-tab="settings"]');
this.settingsTab.removeAttribute('hidden'); this.settingsTab.removeAttribute("hidden");
$.on(this.settingsTab, 'click', this.onClickSettingsTab); $.on(this.settingsTab, "click", this.onClickSettingsTab);
app.document.sidebar.search app.document.sidebar.search.on("searching", this.showSidebar);
.on('searching', this.showSidebar);
this.activate(); this.activate();
} }
@ -103,27 +104,36 @@ const Cls = (app.views.Mobile = class Mobile extends app.View {
} }
this.contentTop = window.scrollY; this.contentTop = window.scrollY;
this.content.style.display = 'none'; this.content.style.display = "none";
this.sidebar.style.display = 'block'; this.sidebar.style.display = "block";
if (selection = this.findByClass(app.views.ListSelect.activeClass)) { if ((selection = this.findByClass(app.views.ListSelect.activeClass))) {
const scrollContainer = window.scrollY === this.body.scrollTop ? this.body : document.documentElement; const scrollContainer =
$.scrollTo(selection, scrollContainer, 'center'); window.scrollY === this.body.scrollTop
? this.body
: document.documentElement;
$.scrollTo(selection, scrollContainer, "center");
} else { } else {
window.scrollTo(0, (this.findByClass(app.views.ListFold.activeClass) && this.sidebarTop) || 0); window.scrollTo(
0,
(this.findByClass(app.views.ListFold.activeClass) && this.sidebarTop) ||
0,
);
} }
} }
hideSidebar() { hideSidebar() {
if (!this.isSidebarShown()) { return; } if (!this.isSidebarShown()) {
return;
}
this.sidebarTop = window.scrollY; this.sidebarTop = window.scrollY;
this.sidebar.style.display = 'none'; this.sidebar.style.display = "none";
this.content.style.display = 'block'; this.content.style.display = "block";
window.scrollTo(0, this.contentTop || 0); window.scrollTo(0, this.contentTop || 0);
} }
isSidebarShown() { isSidebarShown() {
return this.sidebar.style.display !== 'none'; return this.sidebar.style.display !== "none";
} }
onClickBack() { onClickBack() {
@ -135,7 +145,11 @@ const Cls = (app.views.Mobile = class Mobile extends app.View {
} }
onClickToggleSidebar() { onClickToggleSidebar() {
if (this.isSidebarShown()) { this.hideSidebar(); } else { this.showSidebar(); } if (this.isSidebarShown()) {
this.hideSidebar();
} else {
this.showSidebar();
}
} }
onClickDocPickerTab(event) { onClickDocPickerTab(event) {
@ -150,18 +164,18 @@ const Cls = (app.views.Mobile = class Mobile extends app.View {
showDocPicker() { showDocPicker() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.docPickerTab.classList.add('active'); this.docPickerTab.classList.add("active");
this.settingsTab.classList.remove('active'); this.settingsTab.classList.remove("active");
this.docPicker.style.display = 'block'; this.docPicker.style.display = "block";
this.content.style.display = 'none'; this.content.style.display = "none";
} }
showSettings() { showSettings() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.docPickerTab.classList.remove('active'); this.docPickerTab.classList.remove("active");
this.settingsTab.classList.add('active'); this.settingsTab.classList.add("active");
this.docPicker.style.display = 'none'; this.docPicker.style.display = "none";
this.content.style.display = 'block'; this.content.style.display = "block";
} }
onTapSearch() { onTapSearch() {
@ -175,22 +189,22 @@ const Cls = (app.views.Mobile = class Mobile extends app.View {
afterRoute(route) { afterRoute(route) {
this.hideSidebar(); this.hideSidebar();
if (route === 'settings') { if (route === "settings") {
this.showDocPicker(); this.showDocPicker();
} else { } else {
this.content.style.display = 'block'; this.content.style.display = "block";
} }
if (page.canGoBack()) { if (page.canGoBack()) {
this.back.removeAttribute('disabled'); this.back.removeAttribute("disabled");
} else { } else {
this.back.setAttribute('disabled', 'disabled'); this.back.setAttribute("disabled", "disabled");
} }
if (page.canGoForward()) { if (page.canGoForward()) {
this.forward.removeAttribute('disabled'); this.forward.removeAttribute("disabled");
} else { } else {
this.forward.setAttribute('disabled', 'disabled'); this.forward.setAttribute("disabled", "disabled");
} }
} }
}); });

@ -15,33 +15,36 @@ const Cls = (app.views.Path = class Path extends app.View {
} }
static initClass() { static initClass() {
this.className = '_path'; this.className = "_path";
this.attributes = this.attributes = { role: "complementary" };
{role: 'complementary'};
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
} }
render(...args) { render(...args) {
this.html(this.tmpl('path', ...Array.from(args))); this.html(this.tmpl("path", ...Array.from(args)));
this.show(); this.show();
} }
show() { show() {
if (!this.el.parentNode) { this.prependTo(app.el); } if (!this.el.parentNode) {
this.prependTo(app.el);
}
} }
hide() { hide() {
if (this.el.parentNode) { $.remove(this.el); } if (this.el.parentNode) {
$.remove(this.el);
}
} }
onClick(event) { onClick(event) {
let link; let link;
if (link = $.closestLink(event.target, this.el)) { this.clicked = true; } if ((link = $.closestLink(event.target, this.el))) {
this.clicked = true;
}
} }
afterRoute(route, context) { afterRoute(route, context) {

@ -7,7 +7,7 @@
* DS206: Consider reworking classes to avoid initClass * DS206: Consider reworking classes to avoid initClass
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let MIN = undefined; let MIN = undefined;
let MAX = undefined; let MAX = undefined;
const Cls = (app.views.Resizer = class Resizer extends app.View { const Cls = (app.views.Resizer = class Resizer extends app.View {
@ -19,11 +19,11 @@
} }
static initClass() { static initClass() {
this.className = '_resizer'; this.className = "_resizer";
this.events = { this.events = {
dragstart: 'onDragStart', dragstart: "onDragStart",
dragend: 'onDragEnd' dragend: "onDragEnd",
}; };
MIN = 260; MIN = 260;
@ -31,42 +31,54 @@
} }
static isSupported() { static isSupported() {
return 'ondragstart' in document.createElement('div') && !app.isMobile(); return "ondragstart" in document.createElement("div") && !app.isMobile();
} }
init() { init() {
this.el.setAttribute('draggable', 'true'); this.el.setAttribute("draggable", "true");
this.appendTo($('._app')); this.appendTo($("._app"));
} }
resize(value, save) { resize(value, save) {
value -= app.el.offsetLeft; value -= app.el.offsetLeft;
if (!(value > 0)) { return; } if (!(value > 0)) {
return;
}
value = Math.min(Math.max(Math.round(value), MIN), MAX); value = Math.min(Math.max(Math.round(value), MIN), MAX);
const newSize = `${value}px`; const newSize = `${value}px`;
document.documentElement.style.setProperty('--sidebarWidth', newSize); document.documentElement.style.setProperty("--sidebarWidth", newSize);
if (save) { app.settings.setSize(value); } if (save) {
app.settings.setSize(value);
}
} }
onDragStart(event) { onDragStart(event) {
event.dataTransfer.effectAllowed = 'link'; event.dataTransfer.effectAllowed = "link";
event.dataTransfer.setData('Text', ''); event.dataTransfer.setData("Text", "");
$.on(window, 'dragover', this.onDrag); $.on(window, "dragover", this.onDrag);
} }
onDrag(event) { onDrag(event) {
const value = event.pageX; const value = event.pageX;
if (!(value > 0)) { return; } if (!(value > 0)) {
return;
}
this.lastDragValue = value; this.lastDragValue = value;
if (this.lastDrag && (this.lastDrag > (Date.now() - 50))) { return; } if (this.lastDrag && this.lastDrag > Date.now() - 50) {
return;
}
this.lastDrag = Date.now(); this.lastDrag = Date.now();
this.resize(value, false); this.resize(value, false);
} }
onDragEnd(event) { onDragEnd(event) {
$.off(window, 'dragover', this.onDrag); $.off(window, "dragover", this.onDrag);
let value = event.pageX || (event.screenX - window.screenX); let value = event.pageX || event.screenX - window.screenX;
if (this.lastDragValue && !(this.lastDragValue - 5 < value && value < this.lastDragValue + 5)) { // https://github.com/freeCodeCamp/devdocs/issues/265 if (
this.lastDragValue &&
!(this.lastDragValue - 5 < value && value < this.lastDragValue + 5)
) {
// https://github.com/freeCodeCamp/devdocs/issues/265
value = this.lastDragValue; value = this.lastDragValue;
} }
this.resize(value, true); this.resize(value, true);

@ -10,7 +10,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let SIDEBAR_HIDDEN_LAYOUT = undefined; let SIDEBAR_HIDDEN_LAYOUT = undefined;
const Cls = (app.views.Settings = class Settings extends app.View { const Cls = (app.views.Settings = class Settings extends app.View {
constructor(...args) { constructor(...args) {
@ -23,29 +23,28 @@
} }
static initClass() { static initClass() {
SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'; SIDEBAR_HIDDEN_LAYOUT = "_sidebar-hidden";
this.el = '._settings'; this.el = "._settings";
this.elements = { this.elements = {
sidebar: '._sidebar', sidebar: "._sidebar",
saveBtn: 'button[type="submit"]', saveBtn: 'button[type="submit"]',
backBtn: 'button[data-back]' backBtn: "button[data-back]",
}; };
this.events = { this.events = {
import: 'onImport', import: "onImport",
change: 'onChange', change: "onChange",
submit: 'onSubmit', submit: "onSubmit",
click: 'onClick' click: "onClick",
}; };
this.shortcuts = this.shortcuts = { enter: "onEnter" };
{enter: 'onEnter'};
} }
init() { init() {
this.addSubview(this.docPicker = new app.views.DocPicker); this.addSubview((this.docPicker = new app.views.DocPicker()));
} }
activate() { activate() {
@ -59,18 +58,22 @@
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
this.resetClass(); this.resetClass();
this.docPicker.detach(); this.docPicker.detach();
if (app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)) { document.body.classList.add(SIDEBAR_HIDDEN_LAYOUT); } if (app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)) {
document.body.classList.add(SIDEBAR_HIDDEN_LAYOUT);
}
} }
} }
render() { render() {
this.docPicker.appendTo(this.sidebar); this.docPicker.appendTo(this.sidebar);
this.refreshElements(); this.refreshElements();
this.addClass('_in'); this.addClass("_in");
} }
save(options) { save(options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
if (!this.saving) { if (!this.saving) {
let docs; let docs;
this.saving = true; this.saving = true;
@ -82,16 +85,19 @@
app.settings.setDocs(docs); app.settings.setDocs(docs);
} }
this.saveBtn.textContent = 'Saving\u2026'; this.saveBtn.textContent = "Saving\u2026";
const disabledDocs = new app.collections.Docs((() => { const disabledDocs = new app.collections.Docs(
const result = []; (() => {
for (var doc of Array.from(app.docs.all())) { if (docs.indexOf(doc.slug) === -1) { const result = [];
result.push(doc); for (var doc of Array.from(app.docs.all())) {
if (docs.indexOf(doc.slug) === -1) {
result.push(doc);
}
} }
} return result;
return result; })(),
})()); );
disabledDocs.uninstall(function() { disabledDocs.uninstall(function () {
app.db.migrate(); app.db.migrate();
return app.reload(); return app.reload();
}); });
@ -99,7 +105,7 @@
} }
onChange() { onChange() {
this.addClass('_dirty'); this.addClass("_dirty");
} }
onEnter() { onEnter() {
@ -112,15 +118,17 @@
} }
onImport() { onImport() {
this.addClass('_dirty'); this.addClass("_dirty");
this.save({import: true}); this.save({ import: true });
} }
onClick(event) { onClick(event) {
if (event.which !== 1) { return; } if (event.which !== 1) {
return;
}
if (event.target === this.backBtn) { if (event.target === this.backBtn) {
$.stopEvent(event); $.stopEvent(event);
app.router.show('/'); app.router.show("/");
} }
} }
}); });

@ -10,18 +10,17 @@
*/ */
const Cls = (app.views.ListFocus = class ListFocus extends app.View { const Cls = (app.views.ListFocus = class ListFocus extends app.View {
static initClass() { static initClass() {
this.activeClass = 'focus'; this.activeClass = "focus";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.shortcuts = { this.shortcuts = {
up: 'onUp', up: "onUp",
down: 'onDown', down: "onDown",
left: 'onLeft', left: "onLeft",
enter: 'onEnter', enter: "onEnter",
superEnter: 'onSuperEnter', superEnter: "onSuperEnter",
escape: 'blur' escape: "blur",
}; };
} }
@ -39,41 +38,51 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
} }
focus(el, options) { focus(el, options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
if (el && !el.classList.contains(this.constructor.activeClass)) { if (el && !el.classList.contains(this.constructor.activeClass)) {
this.blur(); this.blur();
el.classList.add(this.constructor.activeClass); el.classList.add(this.constructor.activeClass);
if (options.silent !== true) { $.trigger(el, 'focus'); } if (options.silent !== true) {
$.trigger(el, "focus");
}
} }
} }
blur() { blur() {
let cursor; let cursor;
if (cursor = this.getCursor()) { if ((cursor = this.getCursor())) {
cursor.classList.remove(this.constructor.activeClass); cursor.classList.remove(this.constructor.activeClass);
$.trigger(cursor, 'blur'); $.trigger(cursor, "blur");
} }
} }
getCursor() { getCursor() {
return this.findByClass(this.constructor.activeClass) || this.findByClass(app.views.ListSelect.activeClass); return (
this.findByClass(this.constructor.activeClass) ||
this.findByClass(app.views.ListSelect.activeClass)
);
} }
findNext(cursor) { findNext(cursor) {
let next; let next;
if (next = cursor.nextSibling) { if ((next = cursor.nextSibling)) {
if (next.tagName === 'A') { if (next.tagName === "A") {
return next; return next;
} else if (next.tagName === 'SPAN') { // pagination link } else if (next.tagName === "SPAN") {
// pagination link
$.click(next); $.click(next);
return this.findNext(cursor); return this.findNext(cursor);
} else if (next.tagName === 'DIV') { // sub-list } else if (next.tagName === "DIV") {
if (cursor.className.indexOf(' open') >= 0) { // sub-list
if (cursor.className.indexOf(" open") >= 0) {
return this.findFirst(next) || this.findNext(next); return this.findFirst(next) || this.findNext(next);
} else { } else {
return this.findNext(next); return this.findNext(next);
} }
} else if (next.tagName === 'H6') { // title } else if (next.tagName === "H6") {
// title
return this.findNext(next); return this.findNext(next);
} }
} else if (cursor.parentNode !== this.el) { } else if (cursor.parentNode !== this.el) {
@ -83,11 +92,14 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
findFirst(cursor) { findFirst(cursor) {
let first; let first;
if (!(first = cursor.firstChild)) { return; } if (!(first = cursor.firstChild)) {
return;
}
if (first.tagName === 'A') { if (first.tagName === "A") {
return first; return first;
} else if (first.tagName === 'SPAN') { // pagination link } else if (first.tagName === "SPAN") {
// pagination link
$.click(first); $.click(first);
return this.findFirst(cursor); return this.findFirst(cursor);
} }
@ -95,19 +107,22 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
findPrev(cursor) { findPrev(cursor) {
let prev; let prev;
if (prev = cursor.previousSibling) { if ((prev = cursor.previousSibling)) {
if (prev.tagName === 'A') { if (prev.tagName === "A") {
return prev; return prev;
} else if (prev.tagName === 'SPAN') { // pagination link } else if (prev.tagName === "SPAN") {
// pagination link
$.click(prev); $.click(prev);
return this.findPrev(cursor); return this.findPrev(cursor);
} else if (prev.tagName === 'DIV') { // sub-list } else if (prev.tagName === "DIV") {
if (prev.previousSibling.className.indexOf('open') >= 0) { // sub-list
if (prev.previousSibling.className.indexOf("open") >= 0) {
return this.findLast(prev) || this.findPrev(prev); return this.findLast(prev) || this.findPrev(prev);
} else { } else {
return this.findPrev(prev); return this.findPrev(prev);
} }
} else if (prev.tagName === 'H6') { // title } else if (prev.tagName === "H6") {
// title
return this.findPrev(prev); return this.findPrev(prev);
} }
} else if (cursor.parentNode !== this.el) { } else if (cursor.parentNode !== this.el) {
@ -117,13 +132,17 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
findLast(cursor) { findLast(cursor) {
let last; let last;
if (!(last = cursor.lastChild)) { return; } if (!(last = cursor.lastChild)) {
return;
}
if (last.tagName === 'A') { if (last.tagName === "A") {
return last; return last;
} else if ((last.tagName === 'SPAN') || (last.tagName === 'H6')) { // pagination link or title } else if (last.tagName === "SPAN" || last.tagName === "H6") {
// pagination link or title
return this.findPrev(last); return this.findPrev(last);
} else if (last.tagName === 'DIV') { // sub-list } else if (last.tagName === "DIV") {
// sub-list
return this.findLast(last); return this.findLast(last);
} }
} }
@ -133,7 +152,7 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
if ((cursor = this.getCursor())) { if ((cursor = this.getCursor())) {
this.focusOnNextFrame(this.findNext(cursor)); this.focusOnNextFrame(this.findNext(cursor));
} else { } else {
this.focusOnNextFrame(this.findByTag('a')); this.focusOnNextFrame(this.findByTag("a"));
} }
} }
@ -142,37 +161,45 @@ const Cls = (app.views.ListFocus = class ListFocus extends app.View {
if ((cursor = this.getCursor())) { if ((cursor = this.getCursor())) {
this.focusOnNextFrame(this.findPrev(cursor)); this.focusOnNextFrame(this.findPrev(cursor));
} else { } else {
this.focusOnNextFrame(this.findLastByTag('a')); this.focusOnNextFrame(this.findLastByTag("a"));
} }
} }
onLeft() { onLeft() {
const cursor = this.getCursor(); const cursor = this.getCursor();
if (cursor && !cursor.classList.contains(app.views.ListFold.activeClass) && (cursor.parentNode !== this.el)) { if (
cursor &&
!cursor.classList.contains(app.views.ListFold.activeClass) &&
cursor.parentNode !== this.el
) {
const prev = cursor.parentNode.previousSibling; const prev = cursor.parentNode.previousSibling;
if (prev && prev.classList.contains(app.views.ListFold.targetClass)) { this.focusOnNextFrame(cursor.parentNode.previousSibling); } if (prev && prev.classList.contains(app.views.ListFold.targetClass)) {
this.focusOnNextFrame(cursor.parentNode.previousSibling);
}
} }
} }
onEnter() { onEnter() {
let cursor; let cursor;
if (cursor = this.getCursor()) { if ((cursor = this.getCursor())) {
$.click(cursor); $.click(cursor);
} }
} }
onSuperEnter() { onSuperEnter() {
let cursor; let cursor;
if (cursor = this.getCursor()) { if ((cursor = this.getCursor())) {
$.popup(cursor); $.popup(cursor);
} }
} }
onClick(event) { onClick(event) {
if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } if (event.which !== 1 || event.metaKey || event.ctrlKey) {
return;
}
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.tagName === 'A') { if (target.tagName === "A") {
this.focus(target, {silent: true}); this.focus(target, { silent: true });
} }
} }
}); });

@ -10,32 +10,37 @@
*/ */
const Cls = (app.views.ListFold = class ListFold extends app.View { const Cls = (app.views.ListFold = class ListFold extends app.View {
static initClass() { static initClass() {
this.targetClass = '_list-dir'; this.targetClass = "_list-dir";
this.handleClass = '_list-arrow'; this.handleClass = "_list-arrow";
this.activeClass = 'open'; this.activeClass = "open";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.shortcuts = { this.shortcuts = {
left: 'onLeft', left: "onLeft",
right: 'onRight' right: "onRight",
}; };
} }
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); } 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);
}
open(el) { open(el) {
if (el && !el.classList.contains(this.constructor.activeClass)) { if (el && !el.classList.contains(this.constructor.activeClass)) {
el.classList.add(this.constructor.activeClass); el.classList.add(this.constructor.activeClass);
$.trigger(el, 'open'); $.trigger(el, "open");
} }
} }
close(el) { close(el) {
if (el && el.classList.contains(this.constructor.activeClass)) { if (el && el.classList.contains(this.constructor.activeClass)) {
el.classList.remove(this.constructor.activeClass); el.classList.remove(this.constructor.activeClass);
$.trigger(el, 'close'); $.trigger(el, "close");
} }
} }
@ -55,36 +60,55 @@ const Cls = (app.views.ListFold = class ListFold extends app.View {
} }
getCursor() { getCursor() {
return this.findByClass(app.views.ListFocus.activeClass) || this.findByClass(app.views.ListSelect.activeClass); return (
this.findByClass(app.views.ListFocus.activeClass) ||
this.findByClass(app.views.ListSelect.activeClass)
);
} }
onLeft() { onLeft() {
const cursor = this.getCursor(); const cursor = this.getCursor();
if (cursor != null ? cursor.classList.contains(this.constructor.activeClass) : undefined) { if (
cursor != null
? cursor.classList.contains(this.constructor.activeClass)
: undefined
) {
this.close(cursor); this.close(cursor);
} }
} }
onRight() { onRight() {
const cursor = this.getCursor(); const cursor = this.getCursor();
if (cursor != null ? cursor.classList.contains(this.constructor.targetClass) : undefined) { if (
cursor != null
? cursor.classList.contains(this.constructor.targetClass)
: undefined
) {
this.open(cursor); this.open(cursor);
} }
} }
onClick(event) { onClick(event) {
if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } if (event.which !== 1 || event.metaKey || event.ctrlKey) {
if (!event.pageY) { return; } // ignore fabricated clicks return;
}
if (!event.pageY) {
return;
} // ignore fabricated clicks
let el = $.eventTarget(event); let el = $.eventTarget(event);
if (el.parentNode.tagName.toUpperCase() === 'SVG') { el = el.parentNode; } if (el.parentNode.tagName.toUpperCase() === "SVG") {
el = el.parentNode;
}
if (el.classList.contains(this.constructor.handleClass)) { if (el.classList.contains(this.constructor.handleClass)) {
$.stopEvent(event); $.stopEvent(event);
this.toggle(el.parentNode); this.toggle(el.parentNode);
} else if (el.classList.contains(this.constructor.targetClass)) { } else if (el.classList.contains(this.constructor.targetClass)) {
if (el.hasAttribute('href')) { if (el.hasAttribute("href")) {
if (el.classList.contains(this.constructor.activeClass)) { if (el.classList.contains(this.constructor.activeClass)) {
if (el.classList.contains(app.views.ListSelect.activeClass)) { this.close(el); } if (el.classList.contains(app.views.ListSelect.activeClass)) {
this.close(el);
}
} else { } else {
this.open(el); this.open(el);
} }

@ -10,36 +10,43 @@
*/ */
const Cls = (app.views.ListSelect = class ListSelect extends app.View { const Cls = (app.views.ListSelect = class ListSelect extends app.View {
static initClass() { static initClass() {
this.activeClass = 'active'; this.activeClass = "active";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
constructor(el) { this.onClick = this.onClick.bind(this); this.el = el; super(...arguments); } constructor(el) {
this.onClick = this.onClick.bind(this);
this.el = el;
super(...arguments);
}
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { this.deselect(); } if (super.deactivate(...arguments)) {
this.deselect();
}
} }
select(el) { select(el) {
this.deselect(); this.deselect();
if (el) { if (el) {
el.classList.add(this.constructor.activeClass); el.classList.add(this.constructor.activeClass);
$.trigger(el, 'select'); $.trigger(el, "select");
} }
} }
deselect() { deselect() {
let selection; let selection;
if (selection = this.getSelection()) { if ((selection = this.getSelection())) {
selection.classList.remove(this.constructor.activeClass); selection.classList.remove(this.constructor.activeClass);
$.trigger(selection, 'deselect'); $.trigger(selection, "deselect");
} }
} }
selectByHref(href) { selectByHref(href) {
if (__guard__(this.getSelection(), x => x.getAttribute('href')) !== href) { if (
__guard__(this.getSelection(), (x) => x.getAttribute("href")) !== href
) {
this.select(this.find(`a[href='${href}']`)); this.select(this.find(`a[href='${href}']`));
} }
} }
@ -53,9 +60,11 @@ const Cls = (app.views.ListSelect = class ListSelect extends app.View {
} }
onClick(event) { onClick(event) {
if ((event.which !== 1) || event.metaKey || event.ctrlKey) { return; } if (event.which !== 1 || event.metaKey || event.ctrlKey) {
return;
}
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.tagName === 'A') { if (target.tagName === "A") {
this.select(target); this.select(target);
} }
} }
@ -63,5 +72,7 @@ const Cls = (app.views.ListSelect = class ListSelect extends app.View {
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -10,7 +10,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let PER_PAGE = undefined; let PER_PAGE = undefined;
const Cls = (app.views.PaginatedList = class PaginatedList extends app.View { const Cls = (app.views.PaginatedList = class PaginatedList extends app.View {
static initClass() { static initClass() {
@ -21,7 +21,12 @@
let base; let base;
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
this.data = data; this.data = data;
if (((base = this.constructor.events || (this.constructor.events = {}))).click == null) { base.click = 'onClick'; } if (
(base = this.constructor.events || (this.constructor.events = {}))
.click == null
) {
base.click = "onClick";
}
super(...arguments); super(...arguments);
} }
@ -42,11 +47,13 @@
} }
renderPage(page) { renderPage(page) {
return this.render(this.data.slice(((page - 1) * PER_PAGE), (page * PER_PAGE))); return this.render(
this.data.slice((page - 1) * PER_PAGE, page * PER_PAGE),
);
} }
renderPageLink(count) { renderPageLink(count) {
return this.tmpl('sidebarPageLink', count); return this.tmpl("sidebarPageLink", count);
} }
renderPrevLink(page) { renderPrevLink(page) {
@ -54,7 +61,7 @@
} }
renderNextLink(page) { renderNextLink(page) {
return this.renderPageLink(this.data.length - (page * PER_PAGE)); return this.renderPageLink(this.data.length - page * PER_PAGE);
} }
totalPages() { totalPages() {
@ -64,17 +71,27 @@
paginate(link) { paginate(link) {
$.lockScroll(link.nextSibling || link.previousSibling, () => { $.lockScroll(link.nextSibling || link.previousSibling, () => {
$.batchUpdate(this.el, () => { $.batchUpdate(this.el, () => {
if (link.nextSibling) { this.paginatePrev(link); } else { this.paginateNext(link); } if (link.nextSibling) {
this.paginatePrev(link);
} else {
this.paginateNext(link);
}
}); });
}); });
} }
paginateNext() { paginateNext() {
if (this.el.lastChild) { this.remove(this.el.lastChild); } // remove link if (this.el.lastChild) {
if (this.page >= 2) { this.hideTopPage(); } // keep previous page into view this.remove(this.el.lastChild);
} // remove link
if (this.page >= 2) {
this.hideTopPage();
} // keep previous page into view
this.page++; this.page++;
this.append(this.renderPage(this.page)); this.append(this.renderPage(this.page));
if (this.page < this.totalPages()) { this.append(this.renderNextLink(this.page)); } if (this.page < this.totalPages()) {
this.append(this.renderNextLink(this.page));
}
} }
paginatePrev() { paginatePrev() {
@ -82,37 +99,55 @@
this.hideBottomPage(); this.hideBottomPage();
this.page--; this.page--;
this.prepend(this.renderPage(this.page - 1)); // previous page is offset by one this.prepend(this.renderPage(this.page - 1)); // previous page is offset by one
if (this.page >= 3) { this.prepend(this.renderPrevLink(this.page - 1)); } if (this.page >= 3) {
this.prepend(this.renderPrevLink(this.page - 1));
}
} }
paginateTo(object) { paginateTo(object) {
const index = this.data.indexOf(object); const index = this.data.indexOf(object);
if (index >= PER_PAGE) { if (index >= PER_PAGE) {
for (let i = 0, end = Math.floor(index / PER_PAGE), asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.paginateNext(); } for (
let i = 0, end = Math.floor(index / PER_PAGE), asc = 0 <= end;
asc ? i < end : i > end;
asc ? i++ : i--
) {
this.paginateNext();
}
} }
} }
hideTopPage() { hideTopPage() {
const n = this.page <= 2 ? const n = this.page <= 2 ? PER_PAGE : PER_PAGE + 1; // remove link
PER_PAGE for (
: let i = 0, end = n, asc = 0 <= end;
PER_PAGE + 1; // remove link asc ? i < end : i > end;
for (let i = 0, end = n, asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.remove(this.el.firstChild); } asc ? i++ : i--
) {
this.remove(this.el.firstChild);
}
this.prepend(this.renderPrevLink(this.page)); this.prepend(this.renderPrevLink(this.page));
} }
hideBottomPage() { hideBottomPage() {
const n = this.page === this.totalPages() ? const n =
(this.data.length % PER_PAGE) || PER_PAGE this.page === this.totalPages()
: ? this.data.length % PER_PAGE || PER_PAGE
PER_PAGE + 1; // remove link : PER_PAGE + 1; // remove link
for (let i = 0, end = n, asc = 0 <= end; asc ? i < end : i > end; asc ? i++ : i--) { this.remove(this.el.lastChild); } for (
let i = 0, end = n, asc = 0 <= end;
asc ? i < end : i > end;
asc ? i++ : i--
) {
this.remove(this.el.lastChild);
}
this.append(this.renderNextLink(this.page - 1)); this.append(this.renderNextLink(this.page - 1));
} }
onClick(event) { onClick(event) {
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.tagName === 'SPAN') { // link if (target.tagName === "SPAN") {
// link
$.stopEvent(event); $.stopEvent(event);
this.paginate(target); this.paginate(target);
} }

@ -12,15 +12,16 @@
const Cls = (app.views.News = class News extends app.views.Notif { const Cls = (app.views.News = class News extends app.views.Notif {
static initClass() { static initClass() {
this.className += ' _notif-news'; this.className += " _notif-news";
this.defautOptions = this.defautOptions = { autoHide: 30000 };
{autoHide: 30000};
} }
init() { init() {
this.unreadNews = this.getUnreadNews(); this.unreadNews = this.getUnreadNews();
if (this.unreadNews.length) { this.show(); } if (this.unreadNews.length) {
this.show();
}
this.markAllAsRead(); this.markAllAsRead();
} }
@ -30,12 +31,16 @@ const Cls = (app.views.News = class News extends app.views.Notif {
getUnreadNews() { getUnreadNews() {
let time; let time;
if (!(time = this.getLastReadTime())) { return []; } if (!(time = this.getLastReadTime())) {
return [];
}
return (() => { return (() => {
const result = []; const result = [];
for (var news of Array.from(app.news)) { for (var news of Array.from(app.news)) {
if (new Date(news[0]).getTime() <= time) { break; } if (new Date(news[0]).getTime() <= time) {
break;
}
result.push(news); result.push(news);
} }
return result; return result;
@ -47,11 +52,11 @@ const Cls = (app.views.News = class News extends app.views.Notif {
} }
getLastReadTime() { getLastReadTime() {
return app.settings.get('news'); return app.settings.get("news");
} }
markAllAsRead() { markAllAsRead() {
app.settings.set('news', this.getLastNewsTime()); app.settings.set("news", this.getLastNewsTime());
} }
}); });
Cls.initClass(); Cls.initClass();

@ -9,23 +9,30 @@
*/ */
const Cls = (app.views.Notice = class Notice extends app.View { const Cls = (app.views.Notice = class Notice extends app.View {
static initClass() { static initClass() {
this.className = '_notice'; this.className = "_notice";
this.attributes = this.attributes = { role: "alert" };
{role: 'alert'};
} }
constructor(type, ...rest) { this.type = type; [...this.args] = Array.from(rest); super(...arguments); } constructor(type, ...rest) {
this.type = type;
[...this.args] = Array.from(rest);
super(...arguments);
}
init() { init() {
this.activate(); this.activate();
} }
activate() { activate() {
if (super.activate(...arguments)) { this.show(); } if (super.activate(...arguments)) {
this.show();
}
} }
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { this.hide(); } if (super.deactivate(...arguments)) {
this.hide();
}
} }
show() { show() {

@ -9,22 +9,21 @@
*/ */
const Cls = (app.views.Notif = class Notif extends app.View { const Cls = (app.views.Notif = class Notif extends app.View {
static initClass() { static initClass() {
this.className = '_notif'; this.className = "_notif";
this.activeClass = '_in'; this.activeClass = "_in";
this.attributes = this.attributes = { role: "alert" };
{role: 'alert'};
this.defautOptions = this.defautOptions = { autoHide: 15000 };
{autoHide: 15000};
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
constructor(type, options) { constructor(type, options) {
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
this.type = type; this.type = type;
if (options == null) { options = {}; } if (options == null) {
options = {};
}
this.options = options; this.options = options;
this.options = $.extend({}, this.constructor.defautOptions, this.options); this.options = $.extend({}, this.constructor.defautOptions, this.options);
super(...arguments); super(...arguments);
@ -45,7 +44,9 @@ const Cls = (app.views.Notif = class Notif extends app.View {
this.appendTo(document.body); this.appendTo(document.body);
this.el.offsetWidth; // force reflow this.el.offsetWidth; // force reflow
this.addClass(this.constructor.activeClass); this.addClass(this.constructor.activeClass);
if (this.options.autoHide) { this.timeout = this.delay(this.hide, this.options.autoHide); } if (this.options.autoHide) {
this.timeout = this.delay(this.hide, this.options.autoHide);
}
} }
} }
@ -63,15 +64,20 @@ const Cls = (app.views.Notif = class Notif extends app.View {
const notifications = $$(`.${app.views.Notif.className}`); const notifications = $$(`.${app.views.Notif.className}`);
if (notifications.length) { if (notifications.length) {
const lastNotif = notifications[notifications.length - 1]; const lastNotif = notifications[notifications.length - 1];
this.el.style.top = lastNotif.offsetTop + lastNotif.offsetHeight + 16 + 'px'; this.el.style.top =
lastNotif.offsetTop + lastNotif.offsetHeight + 16 + "px";
} }
} }
onClick(event) { onClick(event) {
if (event.which !== 1) { return; } if (event.which !== 1) {
return;
}
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (target.hasAttribute('data-behavior')) { return; } if (target.hasAttribute("data-behavior")) {
if ((target.tagName !== 'A') || target.classList.contains('_notif-close')) { return;
}
if (target.tagName !== "A" || target.classList.contains("_notif-close")) {
$.stopEvent(event); $.stopEvent(event);
this.hide(); this.hide();
} }

@ -9,10 +9,9 @@
const Cls = (app.views.Tip = class Tip extends app.views.Notif { const Cls = (app.views.Tip = class Tip extends app.views.Notif {
static initClass() { static initClass() {
this.className = '_notif _notif-tip'; this.className = "_notif _notif-tip";
this.defautOptions = this.defautOptions = { autoHide: false };
{autoHide: false};
} }
render() { render() {

@ -12,34 +12,47 @@
const Cls = (app.views.Updates = class Updates extends app.views.Notif { const Cls = (app.views.Updates = class Updates extends app.views.Notif {
static initClass() { static initClass() {
this.className += ' _notif-news'; this.className += " _notif-news";
this.defautOptions = this.defautOptions = { autoHide: 30000 };
{autoHide: 30000};
} }
init() { init() {
this.lastUpdateTime = this.getLastUpdateTime(); this.lastUpdateTime = this.getLastUpdateTime();
this.updatedDocs = this.getUpdatedDocs(); this.updatedDocs = this.getUpdatedDocs();
this.updatedDisabledDocs = this.getUpdatedDisabledDocs(); this.updatedDisabledDocs = this.getUpdatedDisabledDocs();
if ((this.updatedDocs.length > 0) || (this.updatedDisabledDocs.length > 0)) { this.show(); } if (this.updatedDocs.length > 0 || this.updatedDisabledDocs.length > 0) {
this.show();
}
this.markAllAsRead(); this.markAllAsRead();
} }
render() { render() {
this.html(app.templates.notifUpdates(this.updatedDocs, this.updatedDisabledDocs)); this.html(
app.templates.notifUpdates(this.updatedDocs, this.updatedDisabledDocs),
);
} }
getUpdatedDocs() { getUpdatedDocs() {
if (!this.lastUpdateTime) { return []; } if (!this.lastUpdateTime) {
return Array.from(app.docs.all()).filter((doc) => doc.mtime > this.lastUpdateTime); return [];
}
return Array.from(app.docs.all()).filter(
(doc) => doc.mtime > this.lastUpdateTime,
);
} }
getUpdatedDisabledDocs() { getUpdatedDisabledDocs() {
if (!this.lastUpdateTime) { return []; } if (!this.lastUpdateTime) {
return [];
}
return (() => { return (() => {
const result = []; const result = [];
for (var doc of Array.from(app.disabledDocs.all())) { if ((doc.mtime > this.lastUpdateTime) && app.docs.findBy('slug_without_version', doc.slug_without_version)) { for (var doc of Array.from(app.disabledDocs.all())) {
if (
doc.mtime > this.lastUpdateTime &&
app.docs.findBy("slug_without_version", doc.slug_without_version)
) {
result.push(doc); result.push(doc);
} }
} }
@ -48,11 +61,16 @@ const Cls = (app.views.Updates = class Updates extends app.views.Notif {
} }
getLastUpdateTime() { getLastUpdateTime() {
return app.settings.get('version'); return app.settings.get("version");
} }
markAllAsRead() { markAllAsRead() {
app.settings.set('version', app.config.env === 'production' ? app.config.version : Math.floor(Date.now() / 1000)); app.settings.set(
"version",
app.config.env === "production"
? app.config.version
: Math.floor(Date.now() / 1000),
);
} }
}); });
Cls.initClass(); Cls.initClass();

@ -9,31 +9,44 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
app.views.BasePage = class BasePage extends app.View { app.views.BasePage = class BasePage extends app.View {
constructor(el, entry) { this.paintCode = this.paintCode.bind(this); this.el = el; this.entry = entry; super(...arguments); } constructor(el, entry) {
this.paintCode = this.paintCode.bind(this);
this.el = el;
this.entry = entry;
super(...arguments);
}
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
return this.highlightNodes = []; return (this.highlightNodes = []);
} }
} }
render(content, fromCache) { render(content, fromCache) {
if (fromCache == null) { fromCache = false; } if (fromCache == null) {
fromCache = false;
}
this.highlightNodes = []; this.highlightNodes = [];
this.previousTiming = null; this.previousTiming = null;
if (!this.constructor.className) { this.addClass(`_${this.entry.doc.type}`); } if (!this.constructor.className) {
this.addClass(`_${this.entry.doc.type}`);
}
this.html(content); this.html(content);
if (!fromCache) { this.highlightCode(); } if (!fromCache) {
this.highlightCode();
}
this.activate(); this.activate();
if (this.afterRender) { this.delay(this.afterRender); } if (this.afterRender) {
this.delay(this.afterRender);
}
if (this.highlightNodes.length > 0) { if (this.highlightNodes.length > 0) {
$.requestAnimationFrame(() => $.requestAnimationFrame(this.paintCode)); $.requestAnimationFrame(() => $.requestAnimationFrame(this.paintCode));
} }
} }
highlightCode() { highlightCode() {
for (var el of Array.from(this.findAll('pre[data-language]'))) { for (var el of Array.from(this.findAll("pre[data-language]"))) {
var language = el.getAttribute('data-language'); var language = el.getAttribute("data-language");
el.classList.add(`language-${language}`); el.classList.add(`language-${language}`);
this.highlightNodes.push(el); this.highlightNodes.push(el);
} }
@ -41,23 +54,34 @@ app.views.BasePage = class BasePage extends app.View {
paintCode(timing) { paintCode(timing) {
if (this.previousTiming) { if (this.previousTiming) {
if (Math.round(1000 / (timing - this.previousTiming)) > 50) { // fps if (Math.round(1000 / (timing - this.previousTiming)) > 50) {
this.nodesPerFrame = Math.round(Math.min(this.nodesPerFrame * 1.25, 50)); // fps
this.nodesPerFrame = Math.round(
Math.min(this.nodesPerFrame * 1.25, 50),
);
} else { } else {
this.nodesPerFrame = Math.round(Math.max(this.nodesPerFrame * .8, 10)); this.nodesPerFrame = Math.round(Math.max(this.nodesPerFrame * 0.8, 10));
} }
} else { } else {
this.nodesPerFrame = 10; this.nodesPerFrame = 10;
} }
for (var el of Array.from(this.highlightNodes.splice(0, this.nodesPerFrame))) { for (var el of Array.from(
this.highlightNodes.splice(0, this.nodesPerFrame),
)) {
var clipEl; var clipEl;
if (clipEl = el.lastElementChild) { $.remove(clipEl); } if ((clipEl = el.lastElementChild)) {
$.remove(clipEl);
}
Prism.highlightElement(el); Prism.highlightElement(el);
if (clipEl) { $.append(el, clipEl); } if (clipEl) {
$.append(el, clipEl);
}
} }
if (this.highlightNodes.length > 0) { $.requestAnimationFrame(this.paintCode); } if (this.highlightNodes.length > 0) {
$.requestAnimationFrame(this.paintCode);
}
this.previousTiming = timing; this.previousTiming = timing;
} }
}; };

@ -8,20 +8,24 @@
*/ */
const Cls = (app.views.HiddenPage = class HiddenPage extends app.View { const Cls = (app.views.HiddenPage = class HiddenPage extends app.View {
static initClass() { static initClass() {
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
constructor(el, entry) { this.onClick = this.onClick.bind(this); this.el = el; this.entry = entry; super(...arguments); } constructor(el, entry) {
this.onClick = this.onClick.bind(this);
this.el = el;
this.entry = entry;
super(...arguments);
}
init() { init() {
this.addSubview(this.notice = new app.views.Notice('disabledDoc')); this.addSubview((this.notice = new app.views.Notice("disabledDoc")));
this.activate(); this.activate();
} }
onClick(event) { onClick(event) {
let link; let link;
if (link = $.closestLink(event.target, this.el)) { if ((link = $.closestLink(event.target, this.el))) {
$.stopEvent(event); $.stopEvent(event);
$.popup(link); $.popup(link);
} }

@ -10,46 +10,54 @@
*/ */
//= require views/pages/base //= require views/pages/base
const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage { const Cls = (app.views.JqueryPage = class JqueryPage extends (
app.views.BasePage
) {
constructor(...args) { constructor(...args) {
this.onIframeLoaded = this.onIframeLoaded.bind(this); this.onIframeLoaded = this.onIframeLoaded.bind(this);
super(...args); super(...args);
} }
static initClass() { static initClass() {
this.demoClassName = '_jquery-demo'; this.demoClassName = "_jquery-demo";
} }
afterRender() { afterRender() {
// Prevent jQuery Mobile's demo iframes from scrolling the page // Prevent jQuery Mobile's demo iframes from scrolling the page
for (var iframe of Array.from(this.findAllByTag('iframe'))) { for (var iframe of Array.from(this.findAllByTag("iframe"))) {
iframe.style.display = 'none'; iframe.style.display = "none";
$.on(iframe, 'load', this.onIframeLoaded); $.on(iframe, "load", this.onIframeLoaded);
} }
return this.runExamples(); return this.runExamples();
} }
onIframeLoaded(event) { onIframeLoaded(event) {
event.target.style.display = ''; event.target.style.display = "";
$.off(event.target, 'load', this.onIframeLoaded); $.off(event.target, "load", this.onIframeLoaded);
} }
runExamples() { runExamples() {
for (var el of Array.from(this.findAllByClass('entry-example'))) { for (var el of Array.from(this.findAllByClass("entry-example"))) {
try { this.runExample(el); } catch (error) {} try {
this.runExample(el);
} catch (error) {}
} }
} }
runExample(el) { runExample(el) {
let iframe; let iframe;
const source = el.getElementsByClassName('syntaxhighlighter')[0]; const source = el.getElementsByClassName("syntaxhighlighter")[0];
if (!source || (source.innerHTML.indexOf('!doctype') === -1)) { return; } if (!source || source.innerHTML.indexOf("!doctype") === -1) {
return;
}
if (!(iframe = el.getElementsByClassName(this.constructor.demoClassName)[0])) { if (
iframe = document.createElement('iframe'); !(iframe = el.getElementsByClassName(this.constructor.demoClassName)[0])
) {
iframe = document.createElement("iframe");
iframe.className = this.constructor.demoClassName; iframe.className = this.constructor.demoClassName;
iframe.width = '100%'; iframe.width = "100%";
iframe.height = 200; iframe.height = 200;
el.appendChild(iframe); el.appendChild(iframe);
} }
@ -60,8 +68,13 @@ const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage
} }
fixIframeSource(source) { fixIframeSource(source) {
source = source.replace('"/resources/', '"https://api.jquery.com/resources/'); // attr(), keydown() source = source.replace(
source = source.replace('</head>', `\ '"/resources/',
'"https://api.jquery.com/resources/',
); // attr(), keydown()
source = source.replace(
"</head>",
`\
<style> <style>
html, body { border: 0; margin: 0; padding: 0; } html, body { border: 0; margin: 0; padding: 0; }
body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }
@ -75,7 +88,7 @@ const Cls = (app.views.JqueryPage = class JqueryPage extends app.views.BasePage
}); });
</script> </script>
</head>\ </head>\
` `,
); );
return source.replace(/<script>/gi, '<script nonce="devdocs">'); return source.replace(/<script>/gi, '<script nonce="devdocs">');
} }

@ -10,19 +10,23 @@
const Cls = (app.views.RdocPage = class RdocPage extends app.views.BasePage { const Cls = (app.views.RdocPage = class RdocPage extends app.views.BasePage {
static initClass() { static initClass() {
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
onClick(event) { onClick(event) {
if (!event.target.classList.contains('method-click-advice')) { return; } if (!event.target.classList.contains("method-click-advice")) {
return;
}
$.stopEvent(event); $.stopEvent(event);
const source = $('.method-source-code', event.target.closest('.method-detail')); const source = $(
const isShown = source.style.display === 'block'; ".method-source-code",
event.target.closest(".method-detail"),
);
const isShown = source.style.display === "block";
source.style.display = isShown ? 'none' : 'block'; source.style.display = isShown ? "none" : "block";
return event.target.textContent = isShown ? 'Show source' : 'Hide source'; return (event.target.textContent = isShown ? "Show source" : "Hide source");
} }
}); });
Cls.initClass(); Cls.initClass();

@ -8,28 +8,33 @@
*/ */
//= require views/pages/base //= require views/pages/base
const Cls = (app.views.SqlitePage = class SqlitePage extends app.views.BasePage { const Cls = (app.views.SqlitePage = class SqlitePage extends (
app.views.BasePage
) {
constructor(...args) { constructor(...args) {
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
super(...args); super(...args);
} }
static initClass() { static initClass() {
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
onClick(event) { onClick(event) {
let el, id; let el, id;
if (!(id = event.target.getAttribute('data-toggle'))) { return; } if (!(id = event.target.getAttribute("data-toggle"))) {
if (!(el = this.find(`#${id}`))) { return; } return;
}
if (!(el = this.find(`#${id}`))) {
return;
}
$.stopEvent(event); $.stopEvent(event);
if (el.style.display === 'none') { if (el.style.display === "none") {
el.style.display = 'block'; el.style.display = "block";
event.target.textContent = 'hide'; event.target.textContent = "hide";
} else { } else {
el.style.display = 'none'; el.style.display = "none";
event.target.textContent = 'show'; event.target.textContent = "show";
} }
} }
}); });

@ -7,19 +7,24 @@
*/ */
//= require views/pages/base //= require views/pages/base
const Cls = (app.views.SupportTablesPage = class SupportTablesPage extends app.views.BasePage { const Cls = (app.views.SupportTablesPage = class SupportTablesPage extends (
app.views.BasePage
) {
static initClass() { static initClass() {
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
} }
onClick(event) { onClick(event) {
if (!event.target.classList.contains('show-all')) { return; } if (!event.target.classList.contains("show-all")) {
return;
}
$.stopEvent(event); $.stopEvent(event);
let el = event.target; let el = event.target;
while (el.tagName !== 'TABLE') { el = el.parentNode; } while (el.tagName !== "TABLE") {
el.classList.add('show-all'); el = el.parentNode;
}
el.classList.add("show-all");
} }
}); });
Cls.initClass(); Cls.initClass();

@ -9,7 +9,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let SEARCH_PARAM = undefined; let SEARCH_PARAM = undefined;
let HASH_RGX = undefined; let HASH_RGX = undefined;
const Cls = (app.views.Search = class Search extends app.View { const Cls = (app.views.Search = class Search extends app.View {
@ -34,85 +34,105 @@
static initClass() { static initClass() {
SEARCH_PARAM = app.config.search_param; SEARCH_PARAM = app.config.search_param;
this.el = '._search'; this.el = "._search";
this.activeClass = '_search-active'; this.activeClass = "_search-active";
this.elements = { this.elements = {
input: '._search-input', input: "._search-input",
resetLink: '._search-clear' resetLink: "._search-clear",
}; };
this.events = { this.events = {
input: 'onInput', input: "onInput",
click: 'onClick', click: "onClick",
submit: 'onSubmit' submit: "onSubmit",
}; };
this.shortcuts = { this.shortcuts = {
typing: 'focus', typing: "focus",
altG: 'google', altG: "google",
altS: 'stackoverflow', altS: "stackoverflow",
altD: 'duckduckgo' altD: "duckduckgo",
}; };
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.*)`); HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.*)`);
} }
init() { init() {
this.addSubview(this.scope = new app.views.SearchScope(this.el)); this.addSubview((this.scope = new app.views.SearchScope(this.el)));
this.searcher = new app.Searcher; this.searcher = new app.Searcher();
this.searcher this.searcher.on("results", this.onResults).on("end", this.onEnd);
.on('results', this.onResults)
.on('end', this.onEnd);
this.scope this.scope.on("change", this.onScopeChange);
.on('change', this.onScopeChange);
app.on('ready', this.onReady); app.on("ready", this.onReady);
$.on(window, 'hashchange', this.searchUrl); $.on(window, "hashchange", this.searchUrl);
$.on(window, 'focus', this.onWindowFocus); $.on(window, "focus", this.onWindowFocus);
} }
focus() { focus() {
if (document.activeElement === this.input) { return; } if (document.activeElement === this.input) {
if (app.settings.get('noAutofocus')) { return; } return;
}
if (app.settings.get("noAutofocus")) {
return;
}
this.input.focus(); this.input.focus();
} }
autoFocus() { autoFocus() {
if (app.isMobile() || $.isAndroid() || $.isIOS()) { return; } if (app.isMobile() || $.isAndroid() || $.isIOS()) {
if ((document.activeElement != null ? document.activeElement.tagName : undefined) === 'INPUT') { return; } return;
if (app.settings.get('noAutofocus')) { return; } }
if (
(document.activeElement != null
? document.activeElement.tagName
: undefined) === "INPUT"
) {
return;
}
if (app.settings.get("noAutofocus")) {
return;
}
this.input.focus(); this.input.focus();
} }
onWindowFocus(event) { onWindowFocus(event) {
if (event.target === window) { return this.autoFocus(); } if (event.target === window) {
return this.autoFocus();
}
} }
getScopeDoc() { getScopeDoc() {
if (this.scope.isActive()) { return this.scope.getScope(); } if (this.scope.isActive()) {
return this.scope.getScope();
}
} }
reset(force) { reset(force) {
if (force || !this.input.value) { this.scope.reset(); } if (force || !this.input.value) {
this.scope.reset();
}
this.el.reset(); this.el.reset();
this.onInput(); this.onInput();
this.autoFocus(); this.autoFocus();
} }
onReady() { onReady() {
this.value = ''; this.value = "";
this.delay(this.onInput); this.delay(this.onInput);
} }
onInput() { onInput() {
if ((this.value == null) || // ignore events pre-"ready" if (
(this.value === this.input.value)) { return; } this.value == null || // ignore events pre-"ready"
this.value === this.input.value
) {
return;
}
this.value = this.input.value; this.value = this.input.value;
if (this.value.length) { if (this.value.length) {
@ -123,25 +143,33 @@
} }
search(url) { search(url) {
if (url == null) { url = false; } if (url == null) {
url = false;
}
this.addClass(this.constructor.activeClass); this.addClass(this.constructor.activeClass);
this.trigger('searching'); this.trigger("searching");
this.hasResults = null; this.hasResults = null;
this.flags = {urlSearch: url, initialResults: true}; this.flags = { urlSearch: url, initialResults: true };
this.searcher.find(this.scope.getScope().entries.all(), 'text', this.value); this.searcher.find(
this.scope.getScope().entries.all(),
"text",
this.value,
);
} }
searchUrl() { searchUrl() {
let value; let value;
if (location.pathname === '/') { if (location.pathname === "/") {
this.scope.searchUrl(); this.scope.searchUrl();
} else if (!app.router.isIndex()) { } else if (!app.router.isIndex()) {
return; return;
} }
if (!(value = this.extractHashValue())) { return; } if (!(value = this.extractHashValue())) {
this.input.value = (this.value = value); return;
}
this.input.value = this.value = value;
this.input.setSelectionRange(value.length, value.length); this.input.setSelectionRange(value.length, value.length);
this.search(true); this.search(true);
return true; return true;
@ -149,13 +177,15 @@
clear() { clear() {
this.removeClass(this.constructor.activeClass); this.removeClass(this.constructor.activeClass);
this.trigger('clear'); this.trigger("clear");
} }
externalSearch(url) { externalSearch(url) {
let value; let value;
if (value = this.value) { if ((value = this.value)) {
if (this.scope.name()) { value = `${this.scope.name()} ${value}`; } if (this.scope.name()) {
value = `${this.scope.name()} ${value}`;
}
$.popup(`${url}${encodeURIComponent(value)}`); $.popup(`${url}${encodeURIComponent(value)}`);
this.reset(); this.reset();
} }
@ -174,13 +204,17 @@
} }
onResults(results) { onResults(results) {
if (results.length) { this.hasResults = true; } if (results.length) {
this.trigger('results', results, this.flags); this.hasResults = true;
}
this.trigger("results", results, this.flags);
this.flags.initialResults = false; this.flags.initialResults = false;
} }
onEnd() { onEnd() {
if (!this.hasResults) { this.trigger('noresults'); } if (!this.hasResults) {
this.trigger("noresults");
}
} }
onClick(event) { onClick(event) {
@ -195,14 +229,24 @@
} }
onScopeChange() { onScopeChange() {
this.value = ''; this.value = "";
this.onInput(); this.onInput();
} }
afterRoute(name, context) { afterRoute(name, context) {
if ((app.shortcuts.eventInProgress != null ? app.shortcuts.eventInProgress.name : undefined) === 'escape') { return; } if (
if (!context.init && app.router.isIndex()) { this.reset(true); } (app.shortcuts.eventInProgress != null
if (context.hash) { this.delay(this.searchUrl); } ? app.shortcuts.eventInProgress.name
: undefined) === "escape"
) {
return;
}
if (!context.init && app.router.isIndex()) {
this.reset(true);
}
if (context.hash) {
this.delay(this.searchUrl);
}
$.requestAnimationFrame(this.autoFocus); $.requestAnimationFrame(this.autoFocus);
} }
@ -215,7 +259,12 @@
} }
getHashValue() { getHashValue() {
try { return __guard__(HASH_RGX.exec($.urlDecode(location.hash)), x => x[1]); } catch (error) {} try {
return __guard__(
HASH_RGX.exec($.urlDecode(location.hash)),
(x) => x[1],
);
} catch (error) {}
} }
}); });
Cls.initClass(); Cls.initClass();
@ -223,5 +272,7 @@
})(); })();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -9,7 +9,7 @@
* DS207: Consider shorter variations of null checks * DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
(function() { (function () {
let SEARCH_PARAM = undefined; let SEARCH_PARAM = undefined;
let HASH_RGX = undefined; let HASH_RGX = undefined;
const Cls = (app.views.SearchScope = class SearchScope extends app.View { const Cls = (app.views.SearchScope = class SearchScope extends app.View {
@ -17,33 +17,41 @@
SEARCH_PARAM = app.config.search_param; SEARCH_PARAM = app.config.search_param;
this.elements = { this.elements = {
input: '._search-input', input: "._search-input",
tag: '._search-tag' tag: "._search-tag",
}; };
this.events = { this.events = {
click: 'onClick', click: "onClick",
keydown: 'onKeydown', keydown: "onKeydown",
textInput: 'onTextInput' textInput: "onTextInput",
}; };
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.+?) .`); HASH_RGX = new RegExp(`^#${SEARCH_PARAM}=(.+?) .`);
} }
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); } 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);
}
init() { init() {
this.placeholder = this.input.getAttribute('placeholder'); this.placeholder = this.input.getAttribute("placeholder");
this.searcher = new app.SynchronousSearcher({ this.searcher = new app.SynchronousSearcher({
fuzzy_min_length: 2, fuzzy_min_length: 2,
max_results: 1 max_results: 1,
}); });
this.searcher.on('results', this.onResults); this.searcher.on("results", this.onResults);
} }
getScope() { getScope() {
@ -55,26 +63,34 @@
} }
name() { name() {
return (this.doc != null ? this.doc.name : undefined); return this.doc != null ? this.doc.name : undefined;
} }
search(value, searchDisabled) { search(value, searchDisabled) {
if (searchDisabled == null) { searchDisabled = false; } if (searchDisabled == null) {
if (this.doc) { return; } searchDisabled = false;
this.searcher.find(app.docs.all(), 'text', value); }
if (!this.doc && searchDisabled) { this.searcher.find(app.disabledDocs.all(), 'text', value); } if (this.doc) {
return;
}
this.searcher.find(app.docs.all(), "text", value);
if (!this.doc && searchDisabled) {
this.searcher.find(app.disabledDocs.all(), "text", value);
}
} }
searchUrl() { searchUrl() {
let value; let value;
if (value = this.extractHashValue()) { if ((value = this.extractHashValue())) {
this.search(value, true); this.search(value, true);
} }
} }
onResults(results) { onResults(results) {
let doc; let doc;
if (!(doc = results[0])) { return; } if (!(doc = results[0])) {
return;
}
if (app.docs.contains(doc)) { if (app.docs.contains(doc)) {
this.selectDoc(doc); this.selectDoc(doc);
} else { } else {
@ -84,45 +100,49 @@
selectDoc(doc) { selectDoc(doc) {
const previousDoc = this.doc; const previousDoc = this.doc;
if (doc === previousDoc) { return; } if (doc === previousDoc) {
return;
}
this.doc = doc; this.doc = doc;
this.tag.textContent = doc.fullName; this.tag.textContent = doc.fullName;
this.tag.style.display = 'block'; this.tag.style.display = "block";
this.input.removeAttribute('placeholder'); this.input.removeAttribute("placeholder");
this.input.value = this.input.value.slice(this.input.selectionStart); this.input.value = this.input.value.slice(this.input.selectionStart);
this.input.style.paddingLeft = this.tag.offsetWidth + 10 + 'px'; this.input.style.paddingLeft = this.tag.offsetWidth + 10 + "px";
$.trigger(this.input, 'input'); $.trigger(this.input, "input");
this.trigger('change', this.doc, previousDoc); this.trigger("change", this.doc, previousDoc);
} }
redirectToDoc(doc) { redirectToDoc(doc) {
const { const { hash } = location;
hash app.router.replaceHash("");
} = location;
app.router.replaceHash('');
location.assign(doc.fullPath() + hash); location.assign(doc.fullPath() + hash);
} }
reset() { reset() {
if (!this.doc) { return; } if (!this.doc) {
return;
}
const previousDoc = this.doc; const previousDoc = this.doc;
this.doc = null; this.doc = null;
this.tag.textContent = ''; this.tag.textContent = "";
this.tag.style.display = 'none'; this.tag.style.display = "none";
this.input.setAttribute('placeholder', this.placeholder); this.input.setAttribute("placeholder", this.placeholder);
this.input.style.paddingLeft = ''; this.input.style.paddingLeft = "";
this.trigger('change', null, previousDoc); this.trigger("change", null, previousDoc);
} }
doScopeSearch(event) { doScopeSearch(event) {
this.search(this.input.value.slice(0, this.input.selectionStart)); this.search(this.input.value.slice(0, this.input.selectionStart));
if (this.doc) { $.stopEvent(event); } if (this.doc) {
$.stopEvent(event);
}
} }
onClick(event) { onClick(event) {
@ -133,38 +153,54 @@
} }
onKeydown(event) { onKeydown(event) {
if (event.which === 8) { // backspace if (event.which === 8) {
if (this.doc && (this.input.selectionEnd === 0)) { // backspace
if (this.doc && this.input.selectionEnd === 0) {
this.reset(); this.reset();
$.stopEvent(event); $.stopEvent(event);
} }
} else if (!this.doc && this.input.value && !$.isChromeForAndroid()) { } else if (!this.doc && this.input.value && !$.isChromeForAndroid()) {
if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) { return; } if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) {
if ((event.which === 9) || // tab return;
((event.which === 32) && app.isMobile())) { // space }
if (
event.which === 9 || // tab
(event.which === 32 && app.isMobile())
) {
// space
this.doScopeSearch(event); this.doScopeSearch(event);
} }
} }
} }
onTextInput(event) { onTextInput(event) {
if (!$.isChromeForAndroid()) { return; } if (!$.isChromeForAndroid()) {
if (!this.doc && this.input.value && (event.data === ' ')) { return;
}
if (!this.doc && this.input.value && event.data === " ") {
this.doScopeSearch(event); this.doScopeSearch(event);
} }
} }
extractHashValue() { extractHashValue() {
let value; let value;
if (value = this.getHashValue()) { if ((value = this.getHashValue())) {
const newHash = $.urlDecode(location.hash).replace(`#${SEARCH_PARAM}=${value} `, `#${SEARCH_PARAM}=`); const newHash = $.urlDecode(location.hash).replace(
`#${SEARCH_PARAM}=${value} `,
`#${SEARCH_PARAM}=`,
);
app.router.replaceHash(newHash); app.router.replaceHash(newHash);
return value; return value;
} }
} }
getHashValue() { getHashValue() {
try { return __guard__(HASH_RGX.exec($.urlDecode(location.hash)), x => x[1]); } catch (error) {} try {
return __guard__(
HASH_RGX.exec($.urlDecode(location.hash)),
(x) => x[1],
);
} catch (error) {}
} }
afterRoute(name, context) { afterRoute(name, context) {
@ -178,5 +214,7 @@
})(); })();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -20,65 +20,75 @@ const Cls = (app.views.DocList = class DocList extends app.View {
} }
static initClass() { static initClass() {
this.className = '_list'; this.className = "_list";
this.attributes = this.attributes = { role: "navigation" };
{role: 'navigation'};
this.events = { this.events = {
open: 'onOpen', open: "onOpen",
close: 'onClose', close: "onClose",
click: 'onClick' click: "onClick",
}; };
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
this.elements = { this.elements = {
disabledTitle: '._list-title', disabledTitle: "._list-title",
disabledList: '._disabled-list' disabledList: "._disabled-list",
}; };
} }
init() { init() {
this.lists = {}; this.lists = {};
this.addSubview(this.listFocus = new app.views.ListFocus(this.el)); this.addSubview((this.listFocus = new app.views.ListFocus(this.el)));
this.addSubview(this.listFold = new app.views.ListFold(this.el)); this.addSubview((this.listFold = new app.views.ListFold(this.el)));
this.addSubview(this.listSelect = new app.views.ListSelect(this.el)); this.addSubview((this.listSelect = new app.views.ListSelect(this.el)));
app.on('ready', this.render); app.on("ready", this.render);
} }
activate() { activate() {
if (super.activate(...arguments)) { if (super.activate(...arguments)) {
for (var slug in this.lists) { var list = this.lists[slug]; list.activate(); } for (var slug in this.lists) {
var list = this.lists[slug];
list.activate();
}
this.listSelect.selectCurrent(); this.listSelect.selectCurrent();
} }
} }
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
for (var slug in this.lists) { var list = this.lists[slug]; list.deactivate(); } for (var slug in this.lists) {
var list = this.lists[slug];
list.deactivate();
}
} }
} }
render() { render() {
let html = ''; let html = "";
for (var doc of Array.from(app.docs.all())) { for (var doc of Array.from(app.docs.all())) {
html += this.tmpl('sidebarDoc', doc, {fullName: app.docs.countAllBy('name', doc.name) > 1}); html += this.tmpl("sidebarDoc", doc, {
fullName: app.docs.countAllBy("name", doc.name) > 1,
});
} }
this.html(html); this.html(html);
if (!app.isSingleDoc() && (app.disabledDocs.size() !== 0)) { this.renderDisabled(); } if (!app.isSingleDoc() && app.disabledDocs.size() !== 0) {
this.renderDisabled();
}
} }
renderDisabled() { renderDisabled() {
this.append(this.tmpl('sidebarDisabled', {count: app.disabledDocs.size()})); this.append(
this.tmpl("sidebarDisabled", { count: app.disabledDocs.size() }),
);
this.refreshElements(); this.refreshElements();
this.renderDisabledList(); this.renderDisabledList();
} }
renderDisabledList() { renderDisabledList() {
if (app.settings.get('hideDisabled')) { if (app.settings.get("hideDisabled")) {
this.removeDisabledList(); this.removeDisabledList();
} else { } else {
this.appendDisabledList(); this.appendDisabledList();
@ -87,60 +97,67 @@ const Cls = (app.views.DocList = class DocList extends app.View {
appendDisabledList() { appendDisabledList() {
let doc; let doc;
let html = ''; let html = "";
const docs = [].concat(...Array.from(app.disabledDocs.all() || [])); const docs = [].concat(...Array.from(app.disabledDocs.all() || []));
while ((doc = docs.shift())) { while ((doc = docs.shift())) {
if (doc.version != null) { if (doc.version != null) {
var versions = ''; var versions = "";
while (true) { while (true) {
versions += this.tmpl('sidebarDoc', doc, {disabled: true}); versions += this.tmpl("sidebarDoc", doc, { disabled: true });
if ((docs[0] != null ? docs[0].name : undefined) !== doc.name) { break; } if ((docs[0] != null ? docs[0].name : undefined) !== doc.name) {
break;
}
doc = docs.shift(); doc = docs.shift();
} }
html += this.tmpl('sidebarDisabledVersionedDoc', doc, versions); html += this.tmpl("sidebarDisabledVersionedDoc", doc, versions);
} else { } else {
html += this.tmpl('sidebarDoc', doc, {disabled: true}); html += this.tmpl("sidebarDoc", doc, { disabled: true });
} }
} }
this.append(this.tmpl('sidebarDisabledList', html)); this.append(this.tmpl("sidebarDisabledList", html));
this.disabledTitle.classList.add('open-title'); this.disabledTitle.classList.add("open-title");
this.refreshElements(); this.refreshElements();
} }
removeDisabledList() { removeDisabledList() {
if (this.disabledList) { $.remove(this.disabledList); } if (this.disabledList) {
this.disabledTitle.classList.remove('open-title'); $.remove(this.disabledList);
}
this.disabledTitle.classList.remove("open-title");
this.refreshElements(); this.refreshElements();
} }
reset(options) { reset(options) {
if (options == null) { options = {}; } if (options == null) {
options = {};
}
this.listSelect.deselect(); this.listSelect.deselect();
if (this.listFocus != null) { if (this.listFocus != null) {
this.listFocus.blur(); this.listFocus.blur();
} }
this.listFold.reset(); this.listFold.reset();
if (options.revealCurrent || app.isSingleDoc()) { this.revealCurrent(); } if (options.revealCurrent || app.isSingleDoc()) {
this.revealCurrent();
}
} }
onOpen(event) { onOpen(event) {
$.stopEvent(event); $.stopEvent(event);
const doc = app.docs.findBy('slug', event.target.getAttribute('data-slug')); const doc = app.docs.findBy("slug", event.target.getAttribute("data-slug"));
if (doc && !this.lists[doc.slug]) { if (doc && !this.lists[doc.slug]) {
this.lists[doc.slug] = doc.types.isEmpty() ? this.lists[doc.slug] = doc.types.isEmpty()
new app.views.EntryList(doc.entries.all()) ? new app.views.EntryList(doc.entries.all())
: : new app.views.TypeList(doc);
new app.views.TypeList(doc);
$.after(event.target, this.lists[doc.slug].el); $.after(event.target, this.lists[doc.slug].el);
} }
} }
onClose(event) { onClose(event) {
$.stopEvent(event); $.stopEvent(event);
const doc = app.docs.findBy('slug', event.target.getAttribute('data-slug')); const doc = app.docs.findBy("slug", event.target.getAttribute("data-slug"));
if (doc && this.lists[doc.slug]) { if (doc && this.lists[doc.slug]) {
this.lists[doc.slug].detach(); this.lists[doc.slug].detach();
@ -154,7 +171,9 @@ const Cls = (app.views.DocList = class DocList extends app.View {
reveal(model) { reveal(model) {
this.openDoc(model.doc); this.openDoc(model.doc);
if (model.type) { this.openType(model.getType()); } if (model.type) {
this.openType(model.getType());
}
this.focus(model); this.focus(model);
this.paginateTo(model); this.paginateTo(model);
this.scrollTo(model); this.scrollTo(model);
@ -168,14 +187,18 @@ const Cls = (app.views.DocList = class DocList extends app.View {
revealCurrent() { revealCurrent() {
let model; let model;
if (model = app.router.context.type || app.router.context.entry) { if ((model = app.router.context.type || app.router.context.entry)) {
this.reveal(model); this.reveal(model);
this.select(model); this.select(model);
} }
} }
openDoc(doc) { openDoc(doc) {
if (app.disabledDocs.contains(doc) && doc.version) { this.listFold.open(this.find(`[data-slug='${doc.slug_without_version}']`)); } if (app.disabledDocs.contains(doc) && doc.version) {
this.listFold.open(
this.find(`[data-slug='${doc.slug_without_version}']`),
);
}
this.listFold.open(this.find(`[data-slug='${doc.slug}']`)); this.listFold.open(this.find(`[data-slug='${doc.slug}']`));
} }
@ -184,7 +207,9 @@ const Cls = (app.views.DocList = class DocList extends app.View {
} }
openType(type) { openType(type) {
this.listFold.open(this.lists[type.doc.slug].find(`[data-slug='${type.slug}']`)); this.listFold.open(
this.lists[type.doc.slug].find(`[data-slug='${type.slug}']`),
);
} }
paginateTo(model) { paginateTo(model) {
@ -194,29 +219,37 @@ const Cls = (app.views.DocList = class DocList extends app.View {
} }
scrollTo(model) { scrollTo(model) {
$.scrollTo(this.find(`a[href='${model.fullPath()}']`), null, 'top', {margin: app.isMobile() ? 48 : 0}); $.scrollTo(this.find(`a[href='${model.fullPath()}']`), null, "top", {
margin: app.isMobile() ? 48 : 0,
});
} }
toggleDisabled() { toggleDisabled() {
if (this.disabledTitle.classList.contains('open-title')) { if (this.disabledTitle.classList.contains("open-title")) {
this.removeDisabledList(); this.removeDisabledList();
app.settings.set('hideDisabled', true); app.settings.set("hideDisabled", true);
} else { } else {
this.appendDisabledList(); this.appendDisabledList();
app.settings.set('hideDisabled', false); app.settings.set("hideDisabled", false);
} }
} }
onClick(event) { onClick(event) {
let slug; let slug;
const target = $.eventTarget(event); const target = $.eventTarget(event);
if (this.disabledTitle && $.hasChild(this.disabledTitle, target) && (target.tagName !== 'A')) { if (
this.disabledTitle &&
$.hasChild(this.disabledTitle, target) &&
target.tagName !== "A"
) {
$.stopEvent(event); $.stopEvent(event);
this.toggleDisabled(); this.toggleDisabled();
} else if (slug = target.getAttribute('data-enable')) { } else if ((slug = target.getAttribute("data-enable"))) {
$.stopEvent(event); $.stopEvent(event);
const doc = app.disabledDocs.findBy('slug', slug); const doc = app.disabledDocs.findBy("slug", slug);
if (doc) { app.enableDoc(doc, this.onEnabled, this.onEnabled); } if (doc) {
app.enableDoc(doc, this.onEnabled, this.onEnabled);
}
} }
} }
@ -227,7 +260,9 @@ const Cls = (app.views.DocList = class DocList extends app.View {
afterRoute(route, context) { afterRoute(route, context) {
if (context.init) { if (context.init) {
if (this.activated) { this.reset({revealCurrent: true}); } if (this.activated) {
this.reset({ revealCurrent: true });
}
} else { } else {
this.select(context.type || context.entry); this.select(context.type || context.entry);
} }

@ -19,56 +19,71 @@ const Cls = (app.views.DocPicker = class DocPicker extends app.View {
} }
static initClass() { static initClass() {
this.className = '_list _list-picker'; this.className = "_list _list-picker";
this.events = { this.events = {
mousedown: 'onMouseDown', mousedown: "onMouseDown",
mouseup: 'onMouseUp' mouseup: "onMouseUp",
}; };
} }
init() { init() {
this.addSubview(this.listFold = new app.views.ListFold(this.el)); this.addSubview((this.listFold = new app.views.ListFold(this.el)));
} }
activate() { activate() {
if (super.activate(...arguments)) { if (super.activate(...arguments)) {
this.render(); this.render();
$.on(this.el, 'focus', this.onDOMFocus, true); $.on(this.el, "focus", this.onDOMFocus, true);
} }
} }
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
this.empty(); this.empty();
$.off(this.el, 'focus', this.onDOMFocus, true); $.off(this.el, "focus", this.onDOMFocus, true);
this.focusEl = null; this.focusEl = null;
} }
} }
render() { render() {
let doc; let doc;
let html = this.tmpl('docPickerHeader'); let html = this.tmpl("docPickerHeader");
let docs = app.docs.all().concat(...Array.from(app.disabledDocs.all() || [])); let docs = app.docs
.all()
.concat(...Array.from(app.disabledDocs.all() || []));
while ((doc = docs.shift())) { while ((doc = docs.shift())) {
if (doc.version != null) { if (doc.version != null) {
var versions; var versions;
[docs, versions] = Array.from(this.extractVersions(docs, doc)); [docs, versions] = Array.from(this.extractVersions(docs, doc));
html += this.tmpl('sidebarVersionedDoc', doc, this.renderVersions(versions), {open: app.docs.contains(doc)}); html += this.tmpl(
"sidebarVersionedDoc",
doc,
this.renderVersions(versions),
{ open: app.docs.contains(doc) },
);
} else { } else {
html += this.tmpl('sidebarLabel', doc, {checked: app.docs.contains(doc)}); html += this.tmpl("sidebarLabel", doc, {
checked: app.docs.contains(doc),
});
} }
} }
this.html(html + this.tmpl('docPickerNote')); this.html(html + this.tmpl("docPickerNote"));
$.requestAnimationFrame(() => __guard__(this.findByTag('input'), x => x.focus())); $.requestAnimationFrame(() =>
__guard__(this.findByTag("input"), (x) => x.focus()),
);
} }
renderVersions(docs) { renderVersions(docs) {
let html = ''; let html = "";
for (var doc of Array.from(docs)) { html += this.tmpl('sidebarLabel', doc, {checked: app.docs.contains(doc)}); } for (var doc of Array.from(docs)) {
html += this.tmpl("sidebarLabel", doc, {
checked: app.docs.contains(doc),
});
}
return html; return html;
} }
@ -87,8 +102,9 @@ const Cls = (app.views.DocPicker = class DocPicker extends app.View {
} }
getSelectedDocs() { getSelectedDocs() {
return Array.from(this.findAllByTag('input')).filter((input) => (input != null ? input.checked : undefined)).map((input) => return Array.from(this.findAllByTag("input"))
input.name); .filter((input) => (input != null ? input.checked : undefined))
.map((input) => input.name);
} }
onMouseDown() { onMouseDown() {
@ -100,25 +116,37 @@ const Cls = (app.views.DocPicker = class DocPicker extends app.View {
} }
onDOMFocus(event) { onDOMFocus(event) {
const { const { target } = event;
target if (target.tagName === "INPUT") {
} = event; if (
if (target.tagName === 'INPUT') { (!this.mouseDown || !(Date.now() < this.mouseDown + 100)) &&
if ((!this.mouseDown || !(Date.now() < (this.mouseDown + 100))) && (!this.mouseUp || !(Date.now() < (this.mouseUp + 100)))) { (!this.mouseUp || !(Date.now() < this.mouseUp + 100))
$.scrollTo(target.parentNode, null, 'continuous'); ) {
$.scrollTo(target.parentNode, null, "continuous");
} }
} else if (target.classList.contains(app.views.ListFold.targetClass)) { } else if (target.classList.contains(app.views.ListFold.targetClass)) {
target.blur(); target.blur();
if (!this.mouseDown || !(Date.now() < (this.mouseDown + 100))) { if (!this.mouseDown || !(Date.now() < this.mouseDown + 100)) {
if (this.focusEl === $('input', target.nextElementSibling)) { if (this.focusEl === $("input", target.nextElementSibling)) {
if (target.classList.contains(app.views.ListFold.activeClass)) { this.listFold.close(target); } if (target.classList.contains(app.views.ListFold.activeClass)) {
this.listFold.close(target);
}
let prev = target.previousElementSibling; let prev = target.previousElementSibling;
while ((prev.tagName !== 'LABEL') && !prev.classList.contains(app.views.ListFold.targetClass)) { prev = prev.previousElementSibling; } while (
if (prev.classList.contains(app.views.ListFold.activeClass)) { prev = $.makeArray($$('input', prev.nextElementSibling)).pop(); } prev.tagName !== "LABEL" &&
!prev.classList.contains(app.views.ListFold.targetClass)
) {
prev = prev.previousElementSibling;
}
if (prev.classList.contains(app.views.ListFold.activeClass)) {
prev = $.makeArray($$("input", prev.nextElementSibling)).pop();
}
this.delay(() => prev.focus()); this.delay(() => prev.focus());
} else { } else {
if (!target.classList.contains(app.views.ListFold.activeClass)) { this.listFold.open(target); } if (!target.classList.contains(app.views.ListFold.activeClass)) {
this.delay(() => $('input', target.nextElementSibling).focus()); this.listFold.open(target);
}
this.delay(() => $("input", target.nextElementSibling).focus());
} }
} }
} }
@ -128,5 +156,7 @@ const Cls = (app.views.DocPicker = class DocPicker extends app.View {
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -9,13 +9,18 @@
*/ */
//= require views/list/paginated_list //= require views/list/paginated_list
const Cls = (app.views.EntryList = class EntryList extends app.views.PaginatedList { const Cls = (app.views.EntryList = class EntryList extends (
app.views.PaginatedList
) {
static initClass() { static initClass() {
this.tagName = 'div'; this.tagName = "div";
this.className = '_list _list-sub'; this.className = "_list _list-sub";
} }
constructor(entries) { this.entries = entries; super(...arguments); } constructor(entries) {
this.entries = entries;
super(...arguments);
}
init() { init() {
this.renderPaginated(); this.renderPaginated();
@ -23,7 +28,7 @@ const Cls = (app.views.EntryList = class EntryList extends app.views.PaginatedLi
} }
render(entries) { render(entries) {
return this.tmpl('sidebarEntry', entries); return this.tmpl("sidebarEntry", entries);
} }
}); });
Cls.initClass(); Cls.initClass();

@ -10,16 +10,23 @@
*/ */
const Cls = (app.views.Results = class Results extends app.View { const Cls = (app.views.Results = class Results extends app.View {
static initClass() { static initClass() {
this.className = '_list'; this.className = "_list";
this.events = this.events = { click: "onClick" };
{click: 'onClick'};
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
} }
constructor(sidebar, search) { this.onResults = this.onResults.bind(this); this.onNoResults = this.onNoResults.bind(this); this.onClear = this.onClear.bind(this); this.afterRoute = this.afterRoute.bind(this); this.onClick = this.onClick.bind(this); this.sidebar = sidebar; this.search = search; super(...arguments); } constructor(sidebar, search) {
this.onResults = this.onResults.bind(this);
this.onNoResults = this.onNoResults.bind(this);
this.onClear = this.onClear.bind(this);
this.afterRoute = this.afterRoute.bind(this);
this.onClick = this.onClick.bind(this);
this.sidebar = sidebar;
this.search = search;
super(...arguments);
}
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
@ -28,29 +35,37 @@ const Cls = (app.views.Results = class Results extends app.View {
} }
init() { init() {
this.addSubview(this.listFocus = new app.views.ListFocus(this.el)); this.addSubview((this.listFocus = new app.views.ListFocus(this.el)));
this.addSubview(this.listSelect = new app.views.ListSelect(this.el)); this.addSubview((this.listSelect = new app.views.ListSelect(this.el)));
this.search this.search
.on('results', this.onResults) .on("results", this.onResults)
.on('noresults', this.onNoResults) .on("noresults", this.onNoResults)
.on('clear', this.onClear); .on("clear", this.onClear);
} }
onResults(entries, flags) { onResults(entries, flags) {
if (flags.initialResults) { if (this.listFocus != null) { if (flags.initialResults) {
this.listFocus.blur(); if (this.listFocus != null) {
} } this.listFocus.blur();
if (flags.initialResults) { this.empty(); } }
this.append(this.tmpl('sidebarResult', entries)); }
if (flags.initialResults) {
this.empty();
}
this.append(this.tmpl("sidebarResult", entries));
if (flags.initialResults) { if (flags.initialResults) {
if (flags.urlSearch) { this.openFirst(); } else { this.focusFirst(); } if (flags.urlSearch) {
this.openFirst();
} else {
this.focusFirst();
}
} }
} }
onNoResults() { onNoResults() {
this.html(this.tmpl('sidebarNoResults')); this.html(this.tmpl("sidebarNoResults"));
} }
onClear() { onClear() {
@ -58,9 +73,11 @@ const Cls = (app.views.Results = class Results extends app.View {
} }
focusFirst() { focusFirst() {
if (!app.isMobile()) { if (this.listFocus != null) { if (!app.isMobile()) {
this.listFocus.focusOnNextFrame(this.el.firstElementChild); if (this.listFocus != null) {
} } this.listFocus.focusOnNextFrame(this.el.firstElementChild);
}
}
} }
openFirst() { openFirst() {
@ -75,7 +92,7 @@ const Cls = (app.views.Results = class Results extends app.View {
} }
afterRoute(route, context) { afterRoute(route, context) {
if (route === 'entry') { if (route === "entry") {
this.listSelect.selectByHref(context.entry.fullPath()); this.listSelect.selectByHref(context.entry.fullPath());
} else { } else {
this.listSelect.deselect(); this.listSelect.deselect();
@ -84,11 +101,15 @@ const Cls = (app.views.Results = class Results extends app.View {
onClick(event) { onClick(event) {
let slug; let slug;
if (event.which !== 1) { return; } if (event.which !== 1) {
if (slug = $.eventTarget(event).getAttribute('data-enable')) { return;
}
if ((slug = $.eventTarget(event).getAttribute("data-enable"))) {
$.stopEvent(event); $.stopEvent(event);
const doc = app.disabledDocs.findBy('slug', slug); const doc = app.disabledDocs.findBy("slug", slug);
if (doc) { return app.enableDoc(doc, this.onDocEnabled.bind(this, doc), $.noop); } if (doc) {
return app.enableDoc(doc, this.onDocEnabled.bind(this, doc), $.noop);
}
} }
} }
}); });

@ -28,68 +28,74 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
} }
static initClass() { static initClass() {
this.el = '._sidebar'; this.el = "._sidebar";
this.events = { this.events = {
focus: 'onFocus', focus: "onFocus",
select: 'onSelect', select: "onSelect",
click: 'onClick' click: "onClick",
}; };
this.routes = this.routes = { after: "afterRoute" };
{after: 'afterRoute'};
this.shortcuts = { this.shortcuts = {
altR: 'onAltR', altR: "onAltR",
escape: 'onEscape' escape: "onEscape",
}; };
} }
init() { init() {
if (!app.isMobile()) { this.addSubview(this.hover = new app.views.SidebarHover(this.el)); } if (!app.isMobile()) {
this.addSubview(this.search = new app.views.Search); this.addSubview((this.hover = new app.views.SidebarHover(this.el)));
}
this.addSubview((this.search = new app.views.Search()));
this.search this.search
.on('searching', this.onSearching) .on("searching", this.onSearching)
.on('clear', this.onSearchClear) .on("clear", this.onSearchClear)
.scope .scope.on("change", this.onScopeChange);
.on('change', this.onScopeChange);
this.results = new app.views.Results(this, this.search); this.results = new app.views.Results(this, this.search);
this.docList = new app.views.DocList; this.docList = new app.views.DocList();
app.on('ready', this.onReady); app.on("ready", this.onReady);
$.on(document.documentElement, 'mouseleave', () => this.hide()); $.on(document.documentElement, "mouseleave", () => this.hide());
$.on(document.documentElement, 'mouseenter', () => this.resetDisplay({forceNoHover: false})); $.on(document.documentElement, "mouseenter", () =>
this.resetDisplay({ forceNoHover: false }),
);
} }
hide() { hide() {
this.removeClass('show'); this.removeClass("show");
} }
display() { display() {
this.addClass('show'); this.addClass("show");
} }
resetDisplay(options) { resetDisplay(options) {
if (options == null) { options = {}; } if (options == null) {
if (!this.hasClass('show')) { return; } options = {};
this.removeClass('show'); }
if (!this.hasClass("show")) {
return;
}
this.removeClass("show");
if ((options.forceNoHover !== false) && !this.hasClass('no-hover')) { if (options.forceNoHover !== false && !this.hasClass("no-hover")) {
this.addClass('no-hover'); this.addClass("no-hover");
$.on(window, 'mousemove', this.resetHoverOnMouseMove); $.on(window, "mousemove", this.resetHoverOnMouseMove);
} }
} }
resetHoverOnMouseMove() { resetHoverOnMouseMove() {
$.off(window, 'mousemove', this.resetHoverOnMouseMove); $.off(window, "mousemove", this.resetHoverOnMouseMove);
return $.requestAnimationFrame(this.resetHover); return $.requestAnimationFrame(this.resetHover);
} }
resetHover() { resetHover() {
return this.removeClass('no-hover'); return this.removeClass("no-hover");
} }
showView(view) { showView(view) {
@ -135,8 +141,14 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
} }
onScopeChange(newDoc, previousDoc) { onScopeChange(newDoc, previousDoc) {
if (previousDoc) { this.docList.closeDoc(previousDoc); } if (previousDoc) {
if (newDoc) { this.docList.reveal(newDoc.toEntry()); } else { this.scrollToTop(); } this.docList.closeDoc(previousDoc);
}
if (newDoc) {
this.docList.reveal(newDoc.toEntry());
} else {
this.scrollToTop();
}
} }
saveScrollPosition() { saveScrollPosition() {
@ -146,7 +158,7 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
} }
restoreScrollPosition() { restoreScrollPosition() {
if ((this.view === this.docList) && this.scrollTop) { if (this.view === this.docList && this.scrollTop) {
this.el.scrollTop = this.scrollTop; this.el.scrollTop = this.scrollTop;
this.scrollTop = null; this.scrollTop = null;
} else { } else {
@ -169,7 +181,9 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
onFocus(event) { onFocus(event) {
this.display(); this.display();
if (event.target !== this.el) { $.scrollTo(event.target, this.el, 'continuous', {bottomGap: 2}); } if (event.target !== this.el) {
$.scrollTo(event.target, this.el, "continuous", { bottomGap: 2 });
}
} }
onSelect() { onSelect() {
@ -177,8 +191,14 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
} }
onClick(event) { onClick(event) {
if (event.which !== 1) { return; } if (event.which !== 1) {
if (__guardMethod__($.eventTarget(event), 'hasAttribute', o => o.hasAttribute('data-reset-list'))) { return;
}
if (
__guardMethod__($.eventTarget(event), "hasAttribute", (o) =>
o.hasAttribute("data-reset-list"),
)
) {
$.stopEvent(event); $.stopEvent(event);
this.onAltR(); this.onAltR();
} }
@ -186,7 +206,7 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
onAltR() { onAltR() {
this.reset(); this.reset();
this.docList.reset({revealCurrent: true}); this.docList.reset({ revealCurrent: true });
this.display(); this.display();
} }
@ -194,7 +214,11 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
let doc; let doc;
this.reset(); this.reset();
this.resetDisplay(); this.resetDisplay();
if ((doc = this.search.getScopeDoc())) { this.docList.reveal(doc.toEntry()); } else { this.scrollToTop(); } if ((doc = this.search.getScopeDoc())) {
this.docList.reveal(doc.toEntry());
} else {
this.scrollToTop();
}
} }
onDocEnabled() { onDocEnabled() {
@ -203,15 +227,27 @@ const Cls = (app.views.Sidebar = class Sidebar extends app.View {
} }
afterRoute(name, context) { afterRoute(name, context) {
if ((app.shortcuts.eventInProgress != null ? app.shortcuts.eventInProgress.name : undefined) === 'escape') { return; } if (
if (!context.init && app.router.isIndex()) { this.reset(); } (app.shortcuts.eventInProgress != null
? app.shortcuts.eventInProgress.name
: undefined) === "escape"
) {
return;
}
if (!context.init && app.router.isIndex()) {
this.reset();
}
this.resetDisplay(); this.resetDisplay();
} }
}); });
Cls.initClass(); Cls.initClass();
function __guardMethod__(obj, methodName, transform) { function __guardMethod__(obj, methodName, transform) {
if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { if (
typeof obj !== "undefined" &&
obj !== null &&
typeof obj[methodName] === "function"
) {
return transform(obj, methodName); return transform(obj, methodName);
} else { } else {
return undefined; return undefined;

@ -11,19 +11,18 @@
*/ */
const Cls = (app.views.SidebarHover = class SidebarHover extends app.View { const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
static initClass() { static initClass() {
this.itemClass = '_list-hover'; this.itemClass = "_list-hover";
this.events = { this.events = {
focus: 'onFocus', focus: "onFocus",
blur: 'onBlur', blur: "onBlur",
mouseover: 'onMouseover', mouseover: "onMouseover",
mouseout: 'onMouseout', mouseout: "onMouseout",
scroll: 'onScroll', scroll: "onScroll",
click: 'onClick' click: "onClick",
}; };
this.routes = this.routes = { after: "onRoute" };
{after: 'onRoute'};
} }
constructor(el) { constructor(el) {
@ -49,7 +48,9 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
this.cursor = el; this.cursor = el;
this.clone = this.makeClone(this.cursor); this.clone = this.makeClone(this.cursor);
$.append(document.body, this.clone); $.append(document.body, this.clone);
if (this.offsetTop == null) { this.offsetTop = this.el.offsetTop; } if (this.offsetTop == null) {
this.offsetTop = this.el.offsetTop;
}
this.position(); this.position();
} }
} }
@ -58,7 +59,7 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
hide() { hide() {
if (this.cursor) { if (this.cursor) {
$.remove(this.clone); $.remove(this.clone);
this.cursor = (this.clone = null); this.cursor = this.clone = null;
} }
} }
@ -66,8 +67,8 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
if (this.cursor) { if (this.cursor) {
const rect = $.rect(this.cursor); const rect = $.rect(this.cursor);
if (rect.top >= this.offsetTop) { if (rect.top >= this.offsetTop) {
this.clone.style.top = rect.top + 'px'; this.clone.style.top = rect.top + "px";
this.clone.style.left = rect.left + 'px'; this.clone.style.left = rect.left + "px";
} else { } else {
this.hide(); this.hide();
} }
@ -76,16 +77,18 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
makeClone(el) { makeClone(el) {
const clone = el.cloneNode(true); const clone = el.cloneNode(true);
clone.classList.add('clone'); clone.classList.add("clone");
return clone; return clone;
} }
isTarget(el) { isTarget(el) {
return __guard__(el != null ? el.classList : undefined, x => x.contains(this.constructor.itemClass)); return __guard__(el != null ? el.classList : undefined, (x) =>
x.contains(this.constructor.itemClass),
);
} }
isSelected(el) { isSelected(el) {
return el.classList.contains('active'); return el.classList.contains("active");
} }
isTruncated(el) { isTruncated(el) {
@ -102,7 +105,11 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
} }
onMouseover(event) { onMouseover(event) {
if (this.isTarget(event.target) && !this.isSelected(event.target) && this.mouseActivated()) { if (
this.isTarget(event.target) &&
!this.isSelected(event.target) &&
this.mouseActivated()
) {
this.show(event.target); this.show(event.target);
} }
} }
@ -115,7 +122,7 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
mouseActivated() { mouseActivated() {
// Skip mouse events caused by focus events scrolling the sidebar. // Skip mouse events caused by focus events scrolling the sidebar.
return !this.focusTime || ((Date.now() - this.focusTime) > 500); return !this.focusTime || Date.now() - this.focusTime > 500;
} }
onScroll() { onScroll() {
@ -134,12 +141,14 @@ const Cls = (app.views.SidebarHover = class SidebarHover extends app.View {
}); });
Cls.initClass(); Cls.initClass();
var isPointerEventsSupported = function() { var isPointerEventsSupported = function () {
const el = document.createElement('div'); const el = document.createElement("div");
el.style.cssText = 'pointer-events: auto'; el.style.cssText = "pointer-events: auto";
return el.style.pointerEvents === 'auto'; return el.style.pointerEvents === "auto";
}; };
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -11,16 +11,21 @@
*/ */
const Cls = (app.views.TypeList = class TypeList extends app.View { const Cls = (app.views.TypeList = class TypeList extends app.View {
static initClass() { static initClass() {
this.tagName = 'div'; this.tagName = "div";
this.className = '_list _list-sub'; this.className = "_list _list-sub";
this.events = { this.events = {
open: 'onOpen', open: "onOpen",
close: 'onClose' close: "onClose",
}; };
} }
constructor(doc) { this.onOpen = this.onOpen.bind(this); this.onClose = this.onClose.bind(this); this.doc = doc; super(...arguments); } constructor(doc) {
this.onOpen = this.onOpen.bind(this);
this.onClose = this.onClose.bind(this);
this.doc = doc;
super(...arguments);
}
init() { init() {
this.lists = {}; this.lists = {};
@ -30,25 +35,36 @@ const Cls = (app.views.TypeList = class TypeList extends app.View {
activate() { activate() {
if (super.activate(...arguments)) { if (super.activate(...arguments)) {
for (var slug in this.lists) { var list = this.lists[slug]; list.activate(); } for (var slug in this.lists) {
var list = this.lists[slug];
list.activate();
}
} }
} }
deactivate() { deactivate() {
if (super.deactivate(...arguments)) { if (super.deactivate(...arguments)) {
for (var slug in this.lists) { var list = this.lists[slug]; list.deactivate(); } for (var slug in this.lists) {
var list = this.lists[slug];
list.deactivate();
}
} }
} }
render() { render() {
let html = ''; let html = "";
for (var group of Array.from(this.doc.types.groups())) { html += this.tmpl('sidebarType', group); } for (var group of Array.from(this.doc.types.groups())) {
html += this.tmpl("sidebarType", group);
}
return this.html(html); return this.html(html);
} }
onOpen(event) { onOpen(event) {
$.stopEvent(event); $.stopEvent(event);
const type = this.doc.types.findBy('slug', event.target.getAttribute('data-slug')); const type = this.doc.types.findBy(
"slug",
event.target.getAttribute("data-slug"),
);
if (type && !this.lists[type.slug]) { if (type && !this.lists[type.slug]) {
this.lists[type.slug] = new app.views.EntryList(type.entries()); this.lists[type.slug] = new app.views.EntryList(type.entries());
@ -58,7 +74,10 @@ const Cls = (app.views.TypeList = class TypeList extends app.View {
onClose(event) { onClose(event) {
$.stopEvent(event); $.stopEvent(event);
const type = this.doc.types.findBy('slug', event.target.getAttribute('data-slug')); const type = this.doc.types.findBy(
"slug",
event.target.getAttribute("data-slug"),
);
if (type && this.lists[type.slug]) { if (type && this.lists[type.slug]) {
this.lists[type.slug].detach(); this.lists[type.slug].detach();
@ -68,12 +87,14 @@ const Cls = (app.views.TypeList = class TypeList extends app.View {
paginateTo(model) { paginateTo(model) {
if (model.type) { if (model.type) {
__guard__(this.lists[model.getType().slug], x => x.paginateTo(model)); __guard__(this.lists[model.getType().slug], (x) => x.paginateTo(model));
} }
} }
}); });
Cls.initClass(); Cls.initClass();
function __guard__(value, transform) { function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; return typeof value !== "undefined" && value !== null
? transform(value)
: undefined;
} }

@ -15,22 +15,28 @@ const Cls = (app.View = class View {
constructor() { constructor() {
this.setupElement(); this.setupElement();
if (this.el.className) { this.originalClassName = this.el.className; } if (this.el.className) {
if (this.constructor.className) { this.resetClass(); } this.originalClassName = this.el.className;
}
if (this.constructor.className) {
this.resetClass();
}
this.refreshElements(); this.refreshElements();
if (typeof this.init === 'function') { if (typeof this.init === "function") {
this.init(); this.init();
} }
this.refreshElements(); this.refreshElements();
} }
setupElement() { setupElement() {
if (this.el == null) { this.el = typeof this.constructor.el === 'string' ? if (this.el == null) {
$(this.constructor.el) this.el =
: this.constructor.el ? typeof this.constructor.el === "string"
this.constructor.el ? $(this.constructor.el)
: : this.constructor.el
document.createElement(this.constructor.tagName || 'div'); } ? this.constructor.el
: document.createElement(this.constructor.tagName || "div");
}
if (this.constructor.attributes) { if (this.constructor.attributes) {
for (var key in this.constructor.attributes) { for (var key in this.constructor.attributes) {
@ -42,7 +48,10 @@ const Cls = (app.View = class View {
refreshElements() { refreshElements() {
if (this.constructor.elements) { if (this.constructor.elements) {
for (var name in this.constructor.elements) { var selector = this.constructor.elements[name]; this[name] = this.find(selector); } for (var name in this.constructor.elements) {
var selector = this.constructor.elements[name];
this[name] = this.find(selector);
}
} }
} }
@ -63,9 +72,11 @@ const Cls = (app.View = class View {
} }
resetClass() { resetClass() {
this.el.className = this.originalClassName || ''; this.el.className = this.originalClassName || "";
if (this.constructor.className) { if (this.constructor.className) {
for (var name of Array.from(this.constructor.className.split(' '))) { this.addClass(name); } for (var name of Array.from(this.constructor.className.split(" "))) {
this.addClass(name);
}
} }
} }
@ -146,7 +157,7 @@ const Cls = (app.View = class View {
} }
delay(fn, ...args) { delay(fn, ...args) {
const delay = typeof args[args.length - 1] === 'number' ? args.pop() : 0; const delay = typeof args[args.length - 1] === "number" ? args.pop() : 0;
return setTimeout(fn.bind(this, ...Array.from(args)), delay); return setTimeout(fn.bind(this, ...Array.from(args)), delay);
} }
@ -161,30 +172,48 @@ const Cls = (app.View = class View {
bindEvents() { bindEvents() {
let method, name; let method, name;
if (this.constructor.events) { if (this.constructor.events) {
for (name in this.constructor.events) { method = this.constructor.events[name]; this.onDOM(name, this[method]); } for (name in this.constructor.events) {
method = this.constructor.events[name];
this.onDOM(name, this[method]);
}
} }
if (this.constructor.routes) { if (this.constructor.routes) {
for (name in this.constructor.routes) { method = this.constructor.routes[name]; app.router.on(name, this[method]); } for (name in this.constructor.routes) {
method = this.constructor.routes[name];
app.router.on(name, this[method]);
}
} }
if (this.constructor.shortcuts) { if (this.constructor.shortcuts) {
for (name in this.constructor.shortcuts) { method = this.constructor.shortcuts[name]; app.shortcuts.on(name, this[method]); } for (name in this.constructor.shortcuts) {
method = this.constructor.shortcuts[name];
app.shortcuts.on(name, this[method]);
}
} }
} }
unbindEvents() { unbindEvents() {
let method, name; let method, name;
if (this.constructor.events) { if (this.constructor.events) {
for (name in this.constructor.events) { method = this.constructor.events[name]; this.offDOM(name, this[method]); } for (name in this.constructor.events) {
method = this.constructor.events[name];
this.offDOM(name, this[method]);
}
} }
if (this.constructor.routes) { if (this.constructor.routes) {
for (name in this.constructor.routes) { method = this.constructor.routes[name]; app.router.off(name, this[method]); } for (name in this.constructor.routes) {
method = this.constructor.routes[name];
app.router.off(name, this[method]);
}
} }
if (this.constructor.shortcuts) { if (this.constructor.shortcuts) {
for (name in this.constructor.shortcuts) { method = this.constructor.shortcuts[name]; app.shortcuts.off(name, this[method]); } for (name in this.constructor.shortcuts) {
method = this.constructor.shortcuts[name];
app.shortcuts.off(name, this[method]);
}
} }
} }
@ -193,17 +222,29 @@ const Cls = (app.View = class View {
} }
activate() { activate() {
if (this.activated) { return; } if (this.activated) {
return;
}
this.bindEvents(); this.bindEvents();
if (this.subviews) { for (var view of Array.from(this.subviews)) { view.activate(); } } if (this.subviews) {
for (var view of Array.from(this.subviews)) {
view.activate();
}
}
this.activated = true; this.activated = true;
return true; return true;
} }
deactivate() { deactivate() {
if (!this.activated) { return; } if (!this.activated) {
return;
}
this.unbindEvents(); this.unbindEvents();
if (this.subviews) { for (var view of Array.from(this.subviews)) { view.deactivate(); } } if (this.subviews) {
for (var view of Array.from(this.subviews)) {
view.deactivate();
}
}
this.activated = false; this.activated = false;
return true; return true;
} }

Loading…
Cancel
Save