aboutsummaryrefslogtreecommitdiff
path: root/client/js/util
diff options
context:
space:
mode:
authorShyam Sunder2020-06-05 18:03:37 -0400
committerShyam Sunder2020-06-06 08:58:23 -0400
commit57193b57157b7a42896c887a2d5930493ac7b290 (patch)
tree9555453a944caae64d8a00e4b073482d9e7fb244 /client/js/util
parentc06aaa63af977e64ef08bfba7829214f0f0ed38e (diff)
client+server: implement code autoformatting using prettier and black
Diffstat (limited to 'client/js/util')
-rw-r--r--client/js/util/keyboard.js8
-rw-r--r--client/js/util/markdown.js83
-rw-r--r--client/js/util/misc.js110
-rw-r--r--client/js/util/optimized_resize.js10
-rw-r--r--client/js/util/polyfill.js28
-rw-r--r--client/js/util/progress.js4
-rw-r--r--client/js/util/search.js14
-rw-r--r--client/js/util/touch.js65
-rw-r--r--client/js/util/uri.js35
-rw-r--r--client/js/util/views.js454
10 files changed, 433 insertions, 378 deletions
diff --git a/client/js/util/keyboard.js b/client/js/util/keyboard.js
index 8ee6ee9..3fe3263 100644
--- a/client/js/util/keyboard.js
+++ b/client/js/util/keyboard.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const mousetrap = require('mousetrap');
-const settings = require('../models/settings.js');
+const mousetrap = require("mousetrap");
+const settings = require("../models/settings.js");
let paused = false;
const _originalStopCallback = mousetrap.prototype.stopCallback;
// eslint-disable-next-line func-names
-mousetrap.prototype.stopCallback = function(...args) {
+mousetrap.prototype.stopCallback = function (...args) {
var self = this;
if (paused) {
return true;
diff --git a/client/js/util/markdown.js b/client/js/util/markdown.js
index 210280e..792c938 100644
--- a/client/js/util/markdown.js
+++ b/client/js/util/markdown.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const marked = require('marked');
+const marked = require("marked");
class BaseMarkdownWrapper {
preprocess(text) {
@@ -20,42 +20,44 @@ class SjisWrapper extends BaseMarkdownWrapper {
preprocess(text) {
return text.replace(
- /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/ig,
+ /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/gi,
(match, capture) => {
- var ret = '%%%SJIS' + this.buf.length;
+ var ret = "%%%SJIS" + this.buf.length;
this.buf.push(capture);
return ret;
- });
+ }
+ );
}
postprocess(text) {
return text.replace(
/(?:<p>)?%%%SJIS(\d+)(?:<\/p>)?/,
(match, capture) => {
- return '<div class="sjis">' + this.buf[capture] + '</div>';
- });
+ return '<div class="sjis">' + this.buf[capture] + "</div>";
+ }
+ );
}
}
// fix \ before ~ being stripped away
class TildeWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/\\~/g, '%%%T');
+ return text.replace(/\\~/g, "%%%T");
}
postprocess(text) {
- return text.replace(/%%%T/g, '\\~');
+ return text.replace(/%%%T/g, "\\~");
}
}
// prevent ^#... from being treated as headers, due to tag permalinks
class TagPermalinkFixWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/^#/g, '%%%#');
+ return text.replace(/^#/g, "%%%#");
}
postprocess(text) {
- return text.replace(/%%%#/g, '#');
+ return text.replace(/%%%#/g, "#");
}
}
@@ -63,19 +65,23 @@ class TagPermalinkFixWrapper extends BaseMarkdownWrapper {
class EntityPermalinkWrapper extends BaseMarkdownWrapper {
preprocess(text) {
// URL-based permalinks
+ text = text.replace(new RegExp("\\b/post/(\\d+)/?\\b", "g"), "@$1");
text = text.replace(
- new RegExp('\\b/post/(\\d+)/?\\b', 'g'), '@$1');
- text = text.replace(
- new RegExp('\\b/tag/([a-zA-Z0-9_-]+?)/?', 'g'), '#$1');
+ new RegExp("\\b/tag/([a-zA-Z0-9_-]+?)/?", "g"),
+ "#$1"
+ );
text = text.replace(
- new RegExp('\\b/user/([a-zA-Z0-9_-]+?)/?', 'g'), '+$1');
+ new RegExp("\\b/user/([a-zA-Z0-9_-]+?)/?", "g"),
+ "+$1"
+ );
text = text.replace(
/(^|^\(|(?:[^\]])\(|[\s<>\[\]\)])([+#@][a-zA-Z0-9_-]+)/g,
- '$1[$2]($2)');
- text = text.replace(/\]\(@(\d+)\)/g, '](/post/$1)');
- text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, '](/user/$1)');
- text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, '](/posts/query=$1)');
+ "$1[$2]($2)"
+ );
+ text = text.replace(/\]\(@(\d+)\)/g, "](/post/$1)");
+ text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, "](/user/$1)");
+ text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, "](/posts/query=$1)");
return text;
}
}
@@ -83,51 +89,58 @@ class EntityPermalinkWrapper extends BaseMarkdownWrapper {
class SearchPermalinkWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig,
- '<a href="/posts/query=$1"><code>$1</code></a>');
+ /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/gi,
+ '<a href="/posts/query=$1"><code>$1</code></a>'
+ );
}
}
class SpoilersWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig,
- '<span class="spoiler">$1</span>');
+ /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/gi,
+ '<span class="spoiler">$1</span>'
+ );
}
}
class SmallWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig,
- '<small>$1</small>');
+ /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/gi,
+ "<small>$1</small>"
+ );
}
}
class StrikeThroughWrapper extends BaseMarkdownWrapper {
postprocess(text) {
- text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
- return text.replace(/\\~/g, '~');
+ text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, "$1<del>$3</del>");
+ return text.replace(/\\~/g, "~");
}
}
function createRenderer() {
function sanitize(str) {
- return str.replace(/&<"/g, m => {
- if (m === '&') {
- return '&amp;';
+ return str.replace(/&<"/g, (m) => {
+ if (m === "&") {
+ return "&amp;";
}
- if (m === '<') {
- return '&lt;';
+ if (m === "<") {
+ return "&lt;";
}
- return '&quot;';
+ return "&quot;";
});
}
const renderer = new marked.Renderer();
renderer.image = (href, title, alt) => {
- let [_, url, width, height] =
- (/^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/).exec(href);
+ let [
+ _,
+ url,
+ width,
+ height,
+ ] = /^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/.exec(href);
let res = '<img src="' + sanitize(url) + '" alt="' + sanitize(alt);
if (width) {
res += '" width="' + width;
diff --git a/client/js/util/misc.js b/client/js/util/misc.js
index c922bb1..b299d3a 100644
--- a/client/js/util/misc.js
+++ b/client/js/util/misc.js
@@ -1,18 +1,18 @@
-'use strict';
+"use strict";
-const markdown = require('./markdown.js');
-const uri = require('./uri.js');
-const settings = require('../models/settings.js');
+const markdown = require("./markdown.js");
+const uri = require("./uri.js");
+const settings = require("../models/settings.js");
function decamelize(str, sep) {
- sep = sep === undefined ? '-' : sep;
+ sep = sep === undefined ? "-" : sep;
return str
- .replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2')
- .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2')
+ .replace(/([a-z\d])([A-Z])/g, "$1" + sep + "$2")
+ .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, "$1" + sep + "$2")
.toLowerCase();
}
-function *range(start = 0, end = null, step = 1) {
+function* range(start = 0, end = null, step = 1) {
if (end === null) {
end = start;
start = 0;
@@ -45,16 +45,17 @@ function formatFileSize(fileSize) {
return _formatUnits(
fileSize,
1024,
- ['B', 'K', 'M', 'G'],
+ ["B", "K", "M", "G"],
(number, suffix) => {
- const decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
+ const decimalPlaces = number < 20 && suffix !== "B" ? 1 : 0;
return number.toFixed(decimalPlaces) + suffix;
- });
+ }
+ );
}
function formatRelativeTime(timeString) {
if (!timeString) {
- return 'never';
+ return "never";
}
const then = Date.parse(timeString);
@@ -63,17 +64,17 @@ function formatRelativeTime(timeString) {
const future = now < then;
const descriptions = [
- [60, 'a few seconds', null],
- [60 * 2, 'a minute', null],
- [60 * 60, '% minutes', 60],
- [60 * 60 * 2, 'an hour', null],
- [60 * 60 * 24, '% hours', 60 * 60],
- [60 * 60 * 24 * 2, 'a day', null],
- [60 * 60 * 24 * 30.42, '% days', 60 * 60 * 24],
- [60 * 60 * 24 * 30.42 * 2, 'a month', null],
- [60 * 60 * 24 * 30.42 * 12, '% months', 60 * 60 * 24 * 30.42],
- [60 * 60 * 24 * 30.42 * 12 * 2, 'a year', null],
- [8640000000000000 /* max*/, '% years', 60 * 60 * 24 * 30.42 * 12],
+ [60, "a few seconds", null],
+ [60 * 2, "a minute", null],
+ [60 * 60, "% minutes", 60],
+ [60 * 60 * 2, "an hour", null],
+ [60 * 60 * 24, "% hours", 60 * 60],
+ [60 * 60 * 24 * 2, "a day", null],
+ [60 * 60 * 24 * 30.42, "% days", 60 * 60 * 24],
+ [60 * 60 * 24 * 30.42 * 2, "a month", null],
+ [60 * 60 * 24 * 30.42 * 12, "% months", 60 * 60 * 24 * 30.42],
+ [60 * 60 * 24 * 30.42 * 12 * 2, "a year", null],
+ [8640000000000000 /* max*/, "% years", 60 * 60 * 24 * 30.42 * 12],
];
let text = null;
@@ -87,10 +88,10 @@ function formatRelativeTime(timeString) {
}
}
- if (text === 'a day') {
- return future ? 'tomorrow' : 'yesterday';
+ if (text === "a day") {
+ return future ? "tomorrow" : "yesterday";
}
- return future ? 'in ' + text : text + ' ago';
+ return future ? "in " + text : text + " ago";
}
function formatMarkdown(text) {
@@ -102,7 +103,7 @@ function formatInlineMarkdown(text) {
}
function splitByWhitespace(str) {
- return str.split(/\s+/).filter(s => s);
+ return str.split(/\s+/).filter((s) => s);
}
function unindent(callSite, ...args) {
@@ -110,28 +111,30 @@ function unindent(callSite, ...args) {
let size = -1;
return str.replace(/\n(\s+)/g, (m, m1) => {
if (size < 0) {
- size = m1.replace(/\t/g, ' ').length;
+ size = m1.replace(/\t/g, " ").length;
}
- return '\n' + m1.slice(Math.min(m1.length, size));
+ return "\n" + m1.slice(Math.min(m1.length, size));
});
}
- if (typeof callSite === 'string') {
+ if (typeof callSite === "string") {
return format(callSite);
}
- if (typeof callSite === 'function') {
+ if (typeof callSite === "function") {
return (...args) => format(callSite(...args));
}
let output = callSite
.slice(0, args.length + 1)
- .map((text, i) => (i === 0 ? '' : args[i - 1]) + text)
- .join('');
+ .map((text, i) => (i === 0 ? "" : args[i - 1]) + text)
+ .join("");
return format(output);
}
function enableExitConfirmation() {
- window.onbeforeunload = e => {
- return 'Are you sure you want to leave? ' +
- 'Data you have entered may not be saved.';
+ window.onbeforeunload = (e) => {
+ return (
+ "Are you sure you want to leave? " +
+ "Data you have entered may not be saved."
+ );
};
}
@@ -150,16 +153,17 @@ function confirmPageExit() {
}
function makeCssName(text, suffix) {
- return suffix + '-' + text.replace(/[^a-z0-9]/g, '_');
+ return suffix + "-" + text.replace(/[^a-z0-9]/g, "_");
}
function escapeHtml(unsafe) {
- return unsafe.toString()
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&apos;');
+ return unsafe
+ .toString()
+ .replace(/&/g, "&amp;")
+ .replace(/</g, "&lt;")
+ .replace(/>/g, "&gt;")
+ .replace(/"/g, "&quot;")
+ .replace(/'/g, "&apos;");
}
function arraysDiffer(source1, source2, orderImportant) {
@@ -177,25 +181,27 @@ function arraysDiffer(source1, source2, orderImportant) {
return false;
}
return (
- source1.filter(value => !source2.includes(value)).length > 0 ||
- source2.filter(value => !source1.includes(value)).length > 0);
+ source1.filter((value) => !source2.includes(value)).length > 0 ||
+ source2.filter((value) => !source1.includes(value)).length > 0
+ );
}
function escapeSearchTerm(text) {
- return text.replace(/([a-z_-]):/g, '$1\\:');
+ return text.replace(/([a-z_-]):/g, "$1\\:");
}
function dataURItoBlob(dataURI) {
- const chunks = dataURI.split(',');
- const byteString = chunks[0].indexOf('base64') >= 0 ?
- window.atob(chunks[1]) :
- unescape(chunks[1]);
- const mimeString = chunks[0].split(':')[1].split(';')[0];
+ const chunks = dataURI.split(",");
+ const byteString =
+ chunks[0].indexOf("base64") >= 0
+ ? window.atob(chunks[1])
+ : unescape(chunks[1]);
+ const mimeString = chunks[0].split(":")[1].split(";")[0];
const data = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
data[i] = byteString.charCodeAt(i);
}
- return new Blob([data], {type: mimeString});
+ return new Blob([data], { type: mimeString });
}
function getPrettyTagName(tag) {
diff --git a/client/js/util/optimized_resize.js b/client/js/util/optimized_resize.js
index 545c458..d45df4a 100644
--- a/client/js/util/optimized_resize.js
+++ b/client/js/util/optimized_resize.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
let callbacks = [];
let running = false;
@@ -15,7 +15,7 @@ function resize() {
}
function runCallbacks() {
- callbacks.forEach(callback => {
+ callbacks.forEach((callback) => {
callback();
});
running = false;
@@ -26,8 +26,8 @@ function add(callback) {
}
function remove(callback) {
- callbacks = callbacks.filter(c => c !== callback);
+ callbacks = callbacks.filter((c) => c !== callback);
}
-window.addEventListener('resize', resize);
-module.exports = {add: add, remove: remove};
+window.addEventListener("resize", resize);
+module.exports = { add: add, remove: remove };
diff --git a/client/js/util/polyfill.js b/client/js/util/polyfill.js
index 09f5835..ec809ff 100644
--- a/client/js/util/polyfill.js
+++ b/client/js/util/polyfill.js
@@ -1,11 +1,11 @@
/* eslint-disable func-names, no-extend-native */
-'use strict';
+"use strict";
// fix iterating over NodeList in Chrome and Opera
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
-NodeList.prototype.querySelector = function(...args) {
+NodeList.prototype.querySelector = function (...args) {
for (let node of this) {
if (node.nodeType === 3) {
continue;
@@ -18,7 +18,7 @@ NodeList.prototype.querySelector = function(...args) {
return null;
};
-NodeList.prototype.querySelectorAll = function(...args) {
+NodeList.prototype.querySelectorAll = function (...args) {
let result = [];
for (let node of this) {
if (node.nodeType === 3) {
@@ -32,7 +32,7 @@ NodeList.prototype.querySelectorAll = function(...args) {
};
// non standard
-Node.prototype.prependChild = function(child) {
+Node.prototype.prependChild = function (child) {
if (this.firstChild) {
this.insertBefore(child, this.firstChild);
} else {
@@ -41,29 +41,25 @@ Node.prototype.prependChild = function(child) {
};
// non standard
-Promise.prototype.always = function(onResolveOrReject) {
- return this.then(
- onResolveOrReject,
- reason => {
- onResolveOrReject(reason);
- throw reason;
- });
+Promise.prototype.always = function (onResolveOrReject) {
+ return this.then(onResolveOrReject, (reason) => {
+ onResolveOrReject(reason);
+ throw reason;
+ });
};
// non standard
-Number.prototype.between = function(a, b, inclusive) {
+Number.prototype.between = function (a, b, inclusive) {
const min = Math.min(a, b);
const max = Math.max(a, b);
- return inclusive ?
- this >= min && this <= max :
- this > min && this < max;
+ return inclusive ? this >= min && this <= max : this > min && this < max;
};
// non standard
Promise.prototype.abort = () => {};
// non standard
-Date.prototype.addDays = function(days) {
+Date.prototype.addDays = function (days) {
let dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
diff --git a/client/js/util/progress.js b/client/js/util/progress.js
index 98df179..d6d12cb 100644
--- a/client/js/util/progress.js
+++ b/client/js/util/progress.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const nprogress = require('nprogress');
+const nprogress = require("nprogress");
let nesting = 0;
diff --git a/client/js/util/search.js b/client/js/util/search.js
index 8d5fca4..c540c2f 100644
--- a/client/js/util/search.js
+++ b/client/js/util/search.js
@@ -1,14 +1,16 @@
-'use strict';
+"use strict";
-const misc = require('./misc.js');
-const keyboard = require('../util/keyboard.js');
-const views = require('./views.js');
+const misc = require("./misc.js");
+const keyboard = require("../util/keyboard.js");
+const views = require("./views.js");
function searchInputNodeFocusHelper(inputNode) {
- keyboard.bind('q', () => {
+ keyboard.bind("q", () => {
inputNode.focus();
inputNode.setSelectionRange(
- inputNode.value.length, inputNode.value.length);
+ inputNode.value.length,
+ inputNode.value.length
+ );
});
}
diff --git a/client/js/util/touch.js b/client/js/util/touch.js
index 53b0978..64bd00a 100644
--- a/client/js/util/touch.js
+++ b/client/js/util/touch.js
@@ -1,11 +1,11 @@
-'use strict';
+"use strict";
const direction = {
NONE: null,
- LEFT: 'left',
- RIGHT: 'right',
- DOWN: 'down',
- UP: 'up'
+ LEFT: "left",
+ RIGHT: "right",
+ DOWN: "down",
+ UP: "up",
};
function handleTouchStart(handler, evt) {
@@ -37,20 +37,20 @@ function handleTouchMove(handler, evt) {
function handleTouchEnd(handler) {
switch (handler._direction) {
- case direction.NONE:
- return;
- case direction.LEFT:
- handler._swipeLeftTask();
- break;
- case direction.RIGHT:
- handler._swipeRightTask();
- break;
- case direction.DOWN:
- handler._swipeDownTask();
- break;
- case direction.UP:
- handler._swipeUpTask();
- // no default
+ case direction.NONE:
+ return;
+ case direction.LEFT:
+ handler._swipeLeftTask();
+ break;
+ case direction.RIGHT:
+ handler._swipeRightTask();
+ break;
+ case direction.DOWN:
+ handler._swipeDownTask();
+ break;
+ case direction.UP:
+ handler._swipeUpTask();
+ // no default
}
handler._xStart = null;
@@ -58,11 +58,13 @@ function handleTouchEnd(handler) {
}
class Touch {
- constructor(target,
+ constructor(
+ target,
swipeLeft = () => {},
swipeRight = () => {},
swipeUp = () => {},
- swipeDown = () => {}) {
+ swipeDown = () => {}
+ ) {
this._target = target;
this._swipeLeftTask = swipeLeft;
@@ -74,18 +76,15 @@ class Touch {
this._yStart = null;
this._direction = direction.NONE;
- this._target.addEventListener('touchstart',
- evt => {
- handleTouchStart(this, evt);
- });
- this._target.addEventListener('touchmove',
- evt => {
- handleTouchMove(this, evt);
- });
- this._target.addEventListener('touchend',
- () => {
- handleTouchEnd(this);
- });
+ this._target.addEventListener("touchstart", (evt) => {
+ handleTouchStart(this, evt);
+ });
+ this._target.addEventListener("touchmove", (evt) => {
+ handleTouchMove(this, evt);
+ });
+ this._target.addEventListener("touchend", () => {
+ handleTouchEnd(this);
+ });
}
}
diff --git a/client/js/util/uri.js b/client/js/util/uri.js
index 868545f..16fa4f8 100644
--- a/client/js/util/uri.js
+++ b/client/js/util/uri.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
function formatApiLink(...values) {
let parts = [];
@@ -9,18 +9,19 @@ function formatApiLink(...values) {
for (let key of Object.keys(value)) {
if (value[key]) {
variableParts.push(
- key + '=' + encodeURIComponent(value[key].toString()));
+ key + "=" + encodeURIComponent(value[key].toString())
+ );
}
}
if (variableParts.length) {
- parts.push('?' + variableParts.join('&'));
+ parts.push("?" + variableParts.join("&"));
}
break;
} else {
parts.push(encodeURIComponent(value.toString()));
}
}
- return '/' + parts.join('/');
+ return "/" + parts.join("/");
}
function escapeParam(text) {
@@ -40,48 +41,52 @@ function formatClientLink(...values) {
for (let key of Object.keys(value)) {
if (value[key]) {
variableParts.push(
- key + '=' + escapeParam(value[key].toString()));
+ key + "=" + escapeParam(value[key].toString())
+ );
}
}
if (variableParts.length) {
- parts.push(variableParts.join(';'));
+ parts.push(variableParts.join(";"));
}
break;
} else {
parts.push(escapeParam(value.toString()));
}
}
- return parts.join('/');
+ return parts.join("/");
}
function extractHostname(url) {
// https://stackoverflow.com/a/23945027
return url
- .split('/')[url.indexOf("//") > -1 ? 2 : 0]
- .split(':')[0]
- .split('?')[0];
+ .split("/")
+ [url.indexOf("//") > -1 ? 2 : 0].split(":")[0]
+ .split("?")[0];
}
function extractRootDomain(url) {
// https://stackoverflow.com/a/23945027
let domain = extractHostname(url);
- let splitArr = domain.split('.');
+ let splitArr = domain.split(".");
let arrLen = splitArr.length;
// if there is a subdomain
if (arrLen > 2) {
- domain = splitArr[arrLen - 2] + '.' + splitArr[arrLen - 1];
+ domain = splitArr[arrLen - 2] + "." + splitArr[arrLen - 1];
// check to see if it's using a Country Code Top Level Domain (ccTLD) (i.e. ".me.uk")
- if (splitArr[arrLen - 2].length === 2 && splitArr[arrLen - 1].length === 2) {
+ if (
+ splitArr[arrLen - 2].length === 2 &&
+ splitArr[arrLen - 1].length === 2
+ ) {
// this is using a ccTLD
- domain = splitArr[arrLen - 3] + '.' + domain;
+ domain = splitArr[arrLen - 3] + "." + domain;
}
}
return domain;
}
function escapeColons(text) {
- return text.replace(new RegExp(':', 'g'), '\\:');
+ return text.replace(new RegExp(":", "g"), "\\:");
}
module.exports = {
diff --git a/client/js/util/views.js b/client/js/util/views.js
index afdda76..f69b34b 100644
--- a/client/js/util/views.js
+++ b/client/js/util/views.js
@@ -1,27 +1,27 @@
-'use strict';
+"use strict";
-require('../util/polyfill.js');
-const api = require('../api.js');
-const templates = require('../templates.js');
+require("../util/polyfill.js");
+const api = require("../api.js");
+const templates = require("../templates.js");
const domParser = new DOMParser();
-const misc = require('./misc.js');
-const uri = require('./uri.js');
+const misc = require("./misc.js");
+const uri = require("./uri.js");
function _imbueId(options) {
if (!options.id) {
- options.id = 'gen-' + Math.random().toString(36).substring(7);
+ options.id = "gen-" + Math.random().toString(36).substring(7);
}
}
function _makeLabel(options, attrs) {
if (!options.text) {
- return '';
+ return "";
}
if (!attrs) {
attrs = {};
}
attrs.for = options.id;
- return makeElement('label', attrs, options.text);
+ return makeElement("label", attrs, options.text);
}
function makeFileSize(fileSize) {
@@ -34,251 +34,282 @@ function makeMarkdown(text) {
function makeRelativeTime(time) {
return makeElement(
- 'time', {datetime: time, title: time}, misc.formatRelativeTime(time));
+ "time",
+ { datetime: time, title: time },
+ misc.formatRelativeTime(time)
+ );
}
function makeThumbnail(url) {
return makeElement(
- 'span',
- url ?
- {class: 'thumbnail', style: `background-image: url(\'${url}\')`} :
- {class: 'thumbnail empty'},
- makeElement('img', {alt: 'thumbnail', src: url}));
+ "span",
+ url
+ ? {
+ class: "thumbnail",
+ style: `background-image: url(\'${url}\')`,
+ }
+ : { class: "thumbnail empty" },
+ makeElement("img", { alt: "thumbnail", src: url })
+ );
}
function makeRadio(options) {
_imbueId(options);
return makeElement(
- 'label',
- {for: options.id},
- makeElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'radio',
- checked: options.selectedValue === options.value,
- disabled: options.readonly,
- required: options.required,
- }),
- makeElement('span', {class: 'radio'}, options.text));
+ "label",
+ { for: options.id },
+ makeElement("input", {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: "radio",
+ checked: options.selectedValue === options.value,
+ disabled: options.readonly,
+ required: options.required,
+ }),
+ makeElement("span", { class: "radio" }, options.text)
+ );
}
function makeCheckbox(options) {
_imbueId(options);
return makeElement(
- 'label',
- {for: options.id},
- makeElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'checkbox',
- checked: options.checked !== undefined ?
- options.checked : false,
- disabled: options.readonly,
- required: options.required,
- }),
- makeElement('span', {class: 'checkbox'}, options.text));
+ "label",
+ { for: options.id },
+ makeElement("input", {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: "checkbox",
+ checked: options.checked !== undefined ? options.checked : false,
+ disabled: options.readonly,
+ required: options.required,
+ }),
+ makeElement("span", { class: "checkbox" }, options.text)
+ );
}
function makeSelect(options) {
- return _makeLabel(options) +
+ return (
+ _makeLabel(options) +
makeElement(
- 'select',
+ "select",
{
id: options.id,
name: options.name,
disabled: options.readonly,
},
- ...Object.keys(options.keyValues).map(key => makeElement(
- 'option',
- {value: key, selected: key === options.selectedKey},
- options.keyValues[key])));
+ ...Object.keys(options.keyValues).map((key) =>
+ makeElement(
+ "option",
+ { value: key, selected: key === options.selectedKey },
+ options.keyValues[key]
+ )
+ )
+ )
+ );
}
function makeInput(options) {
- options.value = options.value || '';
- return _makeLabel(options) + makeElement('input', options);
+ options.value = options.value || "";
+ return _makeLabel(options) + makeElement("input", options);
}
function makeButton(options) {
- options.type = 'button';
+ options.type = "button";
return makeInput(options);
}
function makeTextInput(options) {
- options.type = 'text';
+ options.type = "text";
return makeInput(options);
}
function makeTextarea(options) {
- const value = options.value || '';
+ const value = options.value || "";
delete options.value;
- return _makeLabel(options) + makeElement('textarea', options, value);
+ return _makeLabel(options) + makeElement("textarea", options, value);
}
function makePasswordInput(options) {
- options.type = 'password';
+ options.type = "password";
return makeInput(options);
}
function makeEmailInput(options) {
- options.type = 'email';
+ options.type = "email";
return makeInput(options);
}
function makeColorInput(options) {
- const textInput = makeElement(
- 'input', {
- type: 'text',
- value: options.value || '',
- required: options.required,
- class: 'color',
- });
- const backgroundPreviewNode = makeElement(
- 'div',
- {
- class: 'preview background-preview',
- style:
- `border-color: ${options.value};
+ const textInput = makeElement("input", {
+ type: "text",
+ value: options.value || "",
+ required: options.required,
+ class: "color",
+ });
+ const backgroundPreviewNode = makeElement("div", {
+ class: "preview background-preview",
+ style: `border-color: ${options.value};
background-color: ${options.value}`,
- });
- const textPreviewNode = makeElement(
- 'div',
- {
- class: 'preview text-preview',
- style:
- `border-color: ${options.value};
+ });
+ const textPreviewNode = makeElement("div", {
+ class: "preview text-preview",
+ style: `border-color: ${options.value};
color: ${options.value}`,
- });
+ });
return makeElement(
- 'label', {class: 'color'}, textInput, backgroundPreviewNode, textPreviewNode);
+ "label",
+ { class: "color" },
+ textInput,
+ backgroundPreviewNode,
+ textPreviewNode
+ );
}
function makeNumericInput(options) {
- options.type = 'number';
+ options.type = "number";
return makeInput(options);
}
function makeDateInput(options) {
- options.type = 'date';
- return makeInput(options)
+ options.type = "date";
+ return makeInput(options);
}
function getPostUrl(id, parameters) {
return uri.formatClientLink(
- 'post', id, parameters ? {query: parameters.query} : {});
+ "post",
+ id,
+ parameters ? { query: parameters.query } : {}
+ );
}
function getPostEditUrl(id, parameters) {
return uri.formatClientLink(
- 'post', id, 'edit', parameters ? {query: parameters.query} : {});
+ "post",
+ id,
+ "edit",
+ parameters ? { query: parameters.query } : {}
+ );
}
function makePostLink(id, includeHash) {
let text = id;
if (includeHash) {
- text = '@' + id;
+ text = "@" + id;
}
- return api.hasPrivilege('posts:view') ?
- makeElement(
- 'a',
- {href: uri.formatClientLink('post', id)},
- misc.escapeHtml(text)) :
- misc.escapeHtml(text);
+ return api.hasPrivilege("posts:view")
+ ? makeElement(
+ "a",
+ { href: uri.formatClientLink("post", id) },
+ misc.escapeHtml(text)
+ )
+ : misc.escapeHtml(text);
}
function makeTagLink(name, includeHash, includeCount, tag) {
- const category = tag ? tag.category : 'unknown';
+ const category = tag ? tag.category : "unknown";
let text = misc.getPrettyTagName(name);
if (includeHash === true) {
- text = '#' + text;
+ text = "#" + text;
}
if (includeCount === true) {
- text += ' (' + (tag ? tag.postCount : 0) + ')';
+ text += " (" + (tag ? tag.postCount : 0) + ")";
}
- return api.hasPrivilege('tags:view') ?
- makeElement(
- 'a',
- {
- href: uri.formatClientLink('tag', name),
- class: misc.makeCssName(category, 'tag'),
- },
- misc.escapeHtml(text)) :
- makeElement(
- 'span',
- {class: misc.makeCssName(category, 'tag')},
- misc.escapeHtml(text));
+ return api.hasPrivilege("tags:view")
+ ? makeElement(
+ "a",
+ {
+ href: uri.formatClientLink("tag", name),
+ class: misc.makeCssName(category, "tag"),
+ },
+ misc.escapeHtml(text)
+ )
+ : makeElement(
+ "span",
+ { class: misc.makeCssName(category, "tag") },
+ misc.escapeHtml(text)
+ );
}
function makePoolLink(id, includeHash, includeCount, pool, name) {
- const category = pool ? pool.category : 'unknown';
+ const category = pool ? pool.category : "unknown";
let text = name ? name : pool.names[0];
if (includeHash === true) {
- text = '#' + text;
+ text = "#" + text;
}
if (includeCount === true) {
- text += ' (' + (pool ? pool.postCount : 0) + ')';
+ text += " (" + (pool ? pool.postCount : 0) + ")";
}
- return api.hasPrivilege('pools:view') ?
- makeElement(
- 'a',
- {
- href: uri.formatClientLink('pool', id),
- class: misc.makeCssName(category, 'pool'),
- },
- misc.escapeHtml(text)) :
- makeElement(
- 'span',
- {class: misc.makeCssName(category, 'pool')},
- misc.escapeHtml(text));
+ return api.hasPrivilege("pools:view")
+ ? makeElement(
+ "a",
+ {
+ href: uri.formatClientLink("pool", id),
+ class: misc.makeCssName(category, "pool"),
+ },
+ misc.escapeHtml(text)
+ )
+ : makeElement(
+ "span",
+ { class: misc.makeCssName(category, "pool") },
+ misc.escapeHtml(text)
+ );
}
function makeUserLink(user) {
let text = makeThumbnail(user ? user.avatarUrl : null);
- text += user && user.name ? misc.escapeHtml(user.name) : 'Anonymous';
- const link = user && api.hasPrivilege('users:view') ?
- makeElement(
- 'a', {href: uri.formatClientLink('user', user.name)}, text) :
- text;
- return makeElement('span', {class: 'user'}, link);
+ text += user && user.name ? misc.escapeHtml(user.name) : "Anonymous";
+ const link =
+ user && api.hasPrivilege("users:view")
+ ? makeElement(
+ "a",
+ { href: uri.formatClientLink("user", user.name) },
+ text
+ )
+ : text;
+ return makeElement("span", { class: "user" }, link);
}
function makeFlexboxAlign(options) {
return [...misc.range(20)]
- .map(() => '<li class="flexbox-dummy"></li>').join('');
+ .map(() => '<li class="flexbox-dummy"></li>')
+ .join("");
}
function makeAccessKey(html, key) {
- const regex = new RegExp('(' + key + ')', 'i');
+ const regex = new RegExp("(" + key + ")", "i");
html = html.replace(
- regex, '<span class="access-key" data-accesskey="$1">$1</span>');
+ regex,
+ '<span class="access-key" data-accesskey="$1">$1</span>'
+ );
return html;
}
function _serializeElement(name, attributes) {
return [name]
- .concat(Object.keys(attributes).map(key => {
- if (attributes[key] === true) {
- return key;
- } else if (attributes[key] === false ||
- attributes[key] === undefined) {
- return '';
- }
- const attribute = misc.escapeHtml(attributes[key] || '');
- return `${key}="${attribute}"`;
- }))
- .join(' ');
+ .concat(
+ Object.keys(attributes).map((key) => {
+ if (attributes[key] === true) {
+ return key;
+ } else if (
+ attributes[key] === false ||
+ attributes[key] === undefined
+ ) {
+ return "";
+ }
+ const attribute = misc.escapeHtml(attributes[key] || "");
+ return `${key}="${attribute}"`;
+ })
+ )
+ .join(" ");
}
function makeElement(name, attrs, ...content) {
- return content.length !== undefined ?
- `<${_serializeElement(name, attrs)}>${content.join('')}</${name}>` :
- `<${_serializeElement(name, attrs)}/>`;
+ return content.length !== undefined
+ ? `<${_serializeElement(name, attrs)}>${content.join("")}</${name}>`
+ : `<${_serializeElement(name, attrs)}/>`;
}
function emptyContent(target) {
@@ -302,25 +333,25 @@ function replaceContent(target, source) {
function showMessage(target, message, className) {
if (!message) {
- message = 'Unknown message';
+ message = "Unknown message";
}
- const messagesHolderNode = target.querySelector('.messages');
+ const messagesHolderNode = target.querySelector(".messages");
if (!messagesHolderNode) {
return false;
}
- const textNode = document.createElement('div');
- textNode.innerHTML = message.replace(/\n/g, '<br/>');
- textNode.classList.add('message');
+ const textNode = document.createElement("div");
+ textNode.innerHTML = message.replace(/\n/g, "<br/>");
+ textNode.classList.add("message");
textNode.classList.add(className);
- const wrapperNode = document.createElement('div');
- wrapperNode.classList.add('message-wrapper');
+ const wrapperNode = document.createElement("div");
+ wrapperNode.classList.add("message-wrapper");
wrapperNode.appendChild(textNode);
messagesHolderNode.appendChild(wrapperNode);
return true;
}
function appendExclamationMark() {
- if (!document.title.startsWith('!')) {
+ if (!document.title.startsWith("!")) {
document.oldTitle = document.title;
document.title = `! ${document.title}`;
}
@@ -328,15 +359,15 @@ function appendExclamationMark() {
function showError(target, message) {
appendExclamationMark();
- return showMessage(target, misc.formatInlineMarkdown(message), 'error');
+ return showMessage(target, misc.formatInlineMarkdown(message), "error");
}
function showSuccess(target, message) {
- return showMessage(target, misc.formatInlineMarkdown(message), 'success');
+ return showMessage(target, misc.formatInlineMarkdown(message), "success");
}
function showInfo(target, message) {
- return showMessage(target, misc.formatInlineMarkdown(message), 'info');
+ return showMessage(target, misc.formatInlineMarkdown(message), "info");
}
function clearMessages(target) {
@@ -344,7 +375,7 @@ function clearMessages(target) {
document.title = document.oldTitle;
document.oldTitle = null;
}
- for (let messagesHolderNode of target.querySelectorAll('.messages')) {
+ for (let messagesHolderNode of target.querySelectorAll(".messages")) {
emptyContent(messagesHolderNode);
}
}
@@ -352,15 +383,15 @@ function clearMessages(target) {
function htmlToDom(html) {
// code taken from jQuery + Krasimir Tsonev's blog
const wrapMap = {
- _: [1, '<div>', '</div>'],
- option: [1, '<select multiple>', '</select>'],
- legend: [1, '<fieldset>', '</fieldset>'],
- area: [1, '<map>', '</map>'],
- param: [1, '<object>', '</object>'],
- thead: [1, '<table>', '</table>'],
- tr: [2, '<table><tbody>', '</tbody></table>'],
- td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
- col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+ _: [1, "<div>", "</div>"],
+ option: [1, "<select multiple>", "</select>"],
+ legend: [1, "<fieldset>", "</fieldset>"],
+ area: [1, "<map>", "</map>"],
+ param: [1, "<object>", "</object>"],
+ thead: [1, "<table>", "</table>"],
+ tr: [2, "<table><tbody>", "</tbody></table>"],
+ td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
+ col: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"],
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.thead;
@@ -369,8 +400,8 @@ function htmlToDom(html) {
wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
- let element = document.createElement('div');
- const match = (/<\s*(\w+)[^>]*?>/g).exec(html);
+ let element = document.createElement("div");
+ const match = /<\s*(\w+)[^>]*?>/g.exec(html);
if (match) {
const tag = match[1];
@@ -382,9 +413,9 @@ function htmlToDom(html) {
} else {
element.innerHTML = html;
}
- return element.childNodes.length > 1 ?
- element.childNodes :
- element.firstChild;
+ return element.childNodes.length > 1
+ ? element.childNodes
+ : element.firstChild;
}
function getTemplate(templatePath) {
@@ -392,7 +423,7 @@ function getTemplate(templatePath) {
throw `Missing template: ${templatePath}`;
}
const templateFactory = templates[templatePath];
- return ctx => {
+ return (ctx) => {
if (!ctx) {
ctx = {};
}
@@ -423,7 +454,7 @@ function getTemplate(templatePath) {
makeElement: makeElement,
makeCssName: misc.makeCssName,
makeNumericInput: makeNumericInput,
- formatClientLink: uri.formatClientLink
+ formatClientLink: uri.formatClientLink,
});
return htmlToDom(templateFactory(ctx));
};
@@ -432,49 +463,51 @@ function getTemplate(templatePath) {
function decorateValidator(form) {
// postpone showing form fields validity until user actually tries
// to submit it (seeing red/green form w/o doing anything breaks POLA)
- let submitButton = form.querySelector('.buttons input');
+ let submitButton = form.querySelector(".buttons input");
if (!submitButton) {
- submitButton = form.querySelector('input[type=submit]');
+ submitButton = form.querySelector("input[type=submit]");
}
if (submitButton) {
- submitButton.addEventListener('click', e => {
- form.classList.add('show-validation');
+ submitButton.addEventListener("click", (e) => {
+ form.classList.add("show-validation");
});
}
- form.addEventListener('submit', e => {
- form.classList.remove('show-validation');
+ form.addEventListener("submit", (e) => {
+ form.classList.remove("show-validation");
});
}
function disableForm(form) {
- for (let input of form.querySelectorAll('input')) {
+ for (let input of form.querySelectorAll("input")) {
input.disabled = true;
}
}
function enableForm(form) {
- for (let input of form.querySelectorAll('input')) {
+ for (let input of form.querySelectorAll("input")) {
input.disabled = false;
}
}
function syncScrollPosition() {
- window.requestAnimationFrame(
- () => {
- if (history.state && Object.prototype.hasOwnProperty.call(history.state, 'scrollX')) {
- window.scrollTo(history.state.scrollX, history.state.scrollY);
- } else {
- window.scrollTo(0, 0);
- }
- });
+ window.requestAnimationFrame(() => {
+ if (
+ history.state &&
+ Object.prototype.hasOwnProperty.call(history.state, "scrollX")
+ ) {
+ window.scrollTo(history.state.scrollX, history.state.scrollY);
+ } else {
+ window.scrollTo(0, 0);
+ }
+ });
}
function slideDown(element) {
const duration = 500;
return new Promise((resolve, reject) => {
const height = element.getBoundingClientRect().height;
- element.style.maxHeight = '0';
- element.style.overflow = 'hidden';
+ element.style.maxHeight = "0";
+ element.style.overflow = "hidden";
window.setTimeout(() => {
element.style.transition = `all ${duration}ms ease`;
element.style.maxHeight = `${height}px`;
@@ -489,7 +522,7 @@ function slideUp(element) {
const duration = 500;
return new Promise((resolve, reject) => {
const height = element.getBoundingClientRect().height;
- element.style.overflow = 'hidden';
+ element.style.overflow = "hidden";
element.style.maxHeight = `${height}px`;
element.style.transition = `all ${duration}ms ease`;
window.setTimeout(() => {
@@ -502,26 +535,27 @@ function slideUp(element) {
}
function monitorNodeRemoval(monitoredNode, callback) {
- const mutationObserver = new MutationObserver(
- mutations => {
- for (let mutation of mutations) {
- for (let node of mutation.removedNodes) {
- if (node.contains(monitoredNode)) {
- mutationObserver.disconnect();
- callback();
- return;
- }
+ const mutationObserver = new MutationObserver((mutations) => {
+ for (let mutation of mutations) {
+ for (let node of mutation.removedNodes) {
+ if (node.contains(monitoredNode)) {
+ mutationObserver.disconnect();
+ callback();
+ return;
}
}
- });
- mutationObserver.observe(
- document.body, {childList: true, subtree: true});
+ }
+ });
+ mutationObserver.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
}
-document.addEventListener('input', e => {
- if (e.target.classList.contains('color')) {
- let bkNode = e.target.parentNode.querySelector('.background-preview');
- let textNode = e.target.parentNode.querySelector('.text-preview');
+document.addEventListener("input", (e) => {
+ if (e.target.classList.contains("color")) {
+ let bkNode = e.target.parentNode.querySelector(".background-preview");
+ let textNode = e.target.parentNode.querySelector(".text-preview");
bkNode.style.backgroundColor = e.target.value;
bkNode.style.borderColor = e.target.value;
textNode.style.color = e.target.value;
@@ -530,8 +564,8 @@ document.addEventListener('input', e => {
});
// prevent opening buttons in new tabs
-document.addEventListener('click', e => {
- if (e.target.getAttribute('href') === '' && e.which === 2) {
+document.addEventListener("click", (e) => {
+ if (e.target.getAttribute("href") === "" && e.which === 2) {
e.preventDefault();
}
});

© 2015 - 2026 Jakob L. Kreuze