summaryrefslogtreecommitdiff
path: root/client/js/controls
diff options
context:
space:
mode:
authorShyam Sunder <sgsunder1@gmail.com>2020-06-05 18:03:37 -0400
committerShyam Sunder <sgsunder1@gmail.com>2020-06-06 08:58:23 -0400
commit57193b57157b7a42896c887a2d5930493ac7b290 (patch)
tree9555453a944caae64d8a00e4b073482d9e7fb244 /client/js/controls
parentc06aaa63af977e64ef08bfba7829214f0f0ed38e (diff)
client+server: implement code autoformatting using prettier and black
Diffstat (limited to 'client/js/controls')
-rw-r--r--client/js/controls/auto_complete_control.js175
-rw-r--r--client/js/controls/comment_control.js191
-rw-r--r--client/js/controls/comment_list_control.js29
-rw-r--r--client/js/controls/expander_control.js47
-rw-r--r--client/js/controls/file_dropper_control.js94
-rw-r--r--client/js/controls/pool_auto_complete_control.js67
-rw-r--r--client/js/controls/pool_input_control.js128
-rw-r--r--client/js/controls/post_content_control.js48
-rw-r--r--client/js/controls/post_edit_sidebar_control.js457
-rw-r--r--client/js/controls/post_notes_overlay_control.js372
-rw-r--r--client/js/controls/post_readonly_sidebar_control.js181
-rw-r--r--client/js/controls/tag_auto_complete_control.js82
-rw-r--r--client/js/controls/tag_input_control.js318
13 files changed, 1230 insertions, 959 deletions
diff --git a/client/js/controls/auto_complete_control.js b/client/js/controls/auto_complete_control.js
index a802209..6e9bf3d 100644
--- a/client/js/controls/auto_complete_control.js
+++ b/client/js/controls/auto_complete_control.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
const KEY_TAB = 9;
const KEY_RETURN = 13;
@@ -10,14 +10,14 @@ const KEY_UP = 38;
const KEY_DOWN = 40;
function _getSelectionStart(input) {
- if ('selectionStart' in input) {
+ if ("selectionStart" in input) {
return input.selectionStart;
}
if (document.selection) {
input.focus();
const sel = document.selection.createRange();
const selLen = document.selection.createRange().text.length;
- sel.moveStart('character', -input.value.length);
+ sel.moveStart("character", -input.value.length);
return sel.text.length - selLen;
}
return 0;
@@ -27,18 +27,22 @@ class AutoCompleteControl {
constructor(sourceInputNode, options) {
this._sourceInputNode = sourceInputNode;
this._options = {};
- Object.assign(this._options, {
- verticalShift: 2,
- maxResults: 15,
- getTextToFind: () => {
- const value = sourceInputNode.value;
- const start = _getSelectionStart(sourceInputNode);
- return value.substring(0, start).replace(/.*\s+/, '');
+ Object.assign(
+ this._options,
+ {
+ verticalShift: 2,
+ maxResults: 15,
+ getTextToFind: () => {
+ const value = sourceInputNode.value;
+ const start = _getSelectionStart(sourceInputNode);
+ return value.substring(0, start).replace(/.*\s+/, "");
+ },
+ confirm: null,
+ delete: null,
+ getMatches: null,
},
- confirm: null,
- delete: null,
- getMatches: null,
- }, options);
+ options
+ );
this._showTimeout = null;
this._results = [];
@@ -49,22 +53,22 @@ class AutoCompleteControl {
hide() {
window.clearTimeout(this._showTimeout);
- this._suggestionDiv.style.display = 'none';
+ this._suggestionDiv.style.display = "none";
this._isVisible = false;
}
replaceSelectedText(result, addSpace) {
const start = _getSelectionStart(this._sourceInputNode);
- let prefix = '';
+ let prefix = "";
let suffix = this._sourceInputNode.value.substring(start);
let middle = this._sourceInputNode.value.substring(0, start);
- const index = middle.lastIndexOf(' ');
+ const index = middle.lastIndexOf(" ");
if (index !== -1) {
prefix = this._sourceInputNode.value.substring(0, index + 1);
middle = this._sourceInputNode.value.substring(index + 1);
}
- this._sourceInputNode.value = (
- prefix + result.toString() + ' ' + suffix.trimLeft());
+ this._sourceInputNode.value =
+ prefix + result.toString() + " " + suffix.trimLeft();
if (!addSpace) {
this._sourceInputNode.value = this._sourceInputNode.value.trim();
}
@@ -86,7 +90,7 @@ class AutoCompleteControl {
}
_show() {
- this._suggestionDiv.style.display = 'block';
+ this._suggestionDiv.style.display = "block";
this._isVisible = true;
}
@@ -101,29 +105,32 @@ class AutoCompleteControl {
_install() {
if (!this._sourceInputNode) {
- throw new Error('Input element was not found');
+ throw new Error("Input element was not found");
}
- if (this._sourceInputNode.getAttribute('data-autocomplete')) {
+ if (this._sourceInputNode.getAttribute("data-autocomplete")) {
throw new Error(
- 'Autocompletion was already added for this element');
+ "Autocompletion was already added for this element"
+ );
}
- this._sourceInputNode.setAttribute('data-autocomplete', true);
- this._sourceInputNode.setAttribute('autocomplete', 'off');
+ this._sourceInputNode.setAttribute("data-autocomplete", true);
+ this._sourceInputNode.setAttribute("autocomplete", "off");
- this._sourceInputNode.addEventListener(
- 'keydown', e => this._evtKeyDown(e));
- this._sourceInputNode.addEventListener(
- 'blur', e => this._evtBlur(e));
+ this._sourceInputNode.addEventListener("keydown", (e) =>
+ this._evtKeyDown(e)
+ );
+ this._sourceInputNode.addEventListener("blur", (e) =>
+ this._evtBlur(e)
+ );
this._suggestionDiv = views.htmlToDom(
- '<div class="autocomplete"><ul></ul></div>');
- this._suggestionList = this._suggestionDiv.querySelector('ul');
+ '<div class="autocomplete"><ul></ul></div>'
+ );
+ this._suggestionList = this._suggestionDiv.querySelector("ul");
document.body.appendChild(this._suggestionDiv);
- views.monitorNodeRemoval(
- this._sourceInputNode, () => {
- this._uninstall();
- });
+ views.monitorNodeRemoval(this._sourceInputNode, () => {
+ this._uninstall();
+ });
}
_uninstall() {
@@ -174,10 +181,9 @@ class AutoCompleteControl {
func();
} else {
window.clearTimeout(this._showTimeout);
- this._showTimeout = window.setTimeout(
- () => {
- this._showOrHide();
- }, 250);
+ this._showTimeout = window.setTimeout(() => {
+ this._showOrHide();
+ }, 250);
}
}
@@ -196,9 +202,11 @@ class AutoCompleteControl {
}
_selectPrevious() {
- this._select(this._activeResult === -1 ?
- this._results.length - 1 :
- this._activeResult - 1);
+ this._select(
+ this._activeResult === -1
+ ? this._results.length - 1
+ : this._activeResult - 1
+ );
}
_selectNext() {
@@ -206,15 +214,18 @@ class AutoCompleteControl {
}
_select(newActiveResult) {
- this._activeResult =
- newActiveResult.between(0, this._results.length - 1, true) ?
- newActiveResult :
- -1;
+ this._activeResult = newActiveResult.between(
+ 0,
+ this._results.length - 1,
+ true
+ )
+ ? newActiveResult
+ : -1;
this._refreshActiveResult();
}
_updateResults(textToFind) {
- this._options.getMatches(textToFind).then(matches => {
+ this._options.getMatches(textToFind).then((matches) => {
const oldResults = this._results.slice();
this._results = matches.slice(0, this._options.maxResults);
const oldResultsHash = JSON.stringify(oldResults);
@@ -237,34 +248,30 @@ class AutoCompleteControl {
}
for (let [resultIndex, resultItem] of this._results.entries()) {
let resultIndexWorkaround = resultIndex;
- const listItem = document.createElement('li');
- const link = document.createElement('a');
+ const listItem = document.createElement("li");
+ const link = document.createElement("a");
link.innerHTML = resultItem.caption;
- link.setAttribute('href', '');
- link.setAttribute('data-key', resultItem.value);
- link.addEventListener(
- 'mouseenter',
- e => {
- e.preventDefault();
- this._activeResult = resultIndexWorkaround;
- this._refreshActiveResult();
- });
- link.addEventListener(
- 'mousedown',
- e => {
- e.preventDefault();
- this._activeResult = resultIndexWorkaround;
- this._confirm(this._getActiveSuggestion());
- this.hide();
- });
+ link.setAttribute("href", "");
+ link.setAttribute("data-key", resultItem.value);
+ link.addEventListener("mouseenter", (e) => {
+ e.preventDefault();
+ this._activeResult = resultIndexWorkaround;
+ this._refreshActiveResult();
+ });
+ link.addEventListener("mousedown", (e) => {
+ e.preventDefault();
+ this._activeResult = resultIndexWorkaround;
+ this._confirm(this._getActiveSuggestion());
+ this.hide();
+ });
listItem.appendChild(link);
this._suggestionList.appendChild(listItem);
}
this._refreshActiveResult();
// display the suggestions offscreen to get the height
- this._suggestionDiv.style.left = '-9999px';
- this._suggestionDiv.style.top = '-9999px';
+ this._suggestionDiv.style.left = "-9999px";
+ this._suggestionDiv.style.top = "-9999px";
this._show();
const verticalShift = this._options.verticalShift;
const inputRect = this._sourceInputNode.getBoundingClientRect();
@@ -275,17 +282,23 @@ class AutoCompleteControl {
// choose where to view the suggestions: if there's more space above
// the input - draw the suggestions above it, otherwise below
const direction =
- inputRect.top + (inputRect.height / 2) < viewPortHeight / 2 ? 1 : -1;
+ inputRect.top + inputRect.height / 2 < viewPortHeight / 2 ? 1 : -1;
let x = inputRect.left - bodyRect.left;
- let y = direction === 1 ?
- inputRect.bottom - bodyRect.top - verticalShift :
- inputRect.top - bodyRect.top - listRect.height + verticalShift;
+ let y =
+ direction === 1
+ ? inputRect.bottom - bodyRect.top - verticalShift
+ : inputRect.top -
+ bodyRect.top -
+ listRect.height +
+ verticalShift;
// remove offscreen items until whole suggestion list can fit on the
// screen
- while ((y < 0 || y + listRect.height > viewPortHeight) &&
- this._suggestionList.childNodes.length) {
+ while (
+ (y < 0 || y + listRect.height > viewPortHeight) &&
+ this._suggestionList.childNodes.length
+ ) {
this._suggestionList.removeChild(this._suggestionList.lastChild);
const prevHeight = listRect.height;
listRect = this._suggestionDiv.getBoundingClientRect();
@@ -295,19 +308,19 @@ class AutoCompleteControl {
}
}
- this._suggestionDiv.style.left = x + 'px';
- this._suggestionDiv.style.top = y + 'px';
+ this._suggestionDiv.style.left = x + "px";
+ this._suggestionDiv.style.top = y + "px";
}
_refreshActiveResult() {
- let activeItem = this._suggestionList.querySelector('li.active');
+ let activeItem = this._suggestionList.querySelector("li.active");
if (activeItem) {
- activeItem.classList.remove('active');
+ activeItem.classList.remove("active");
}
if (this._activeResult >= 0) {
- const allItems = this._suggestionList.querySelectorAll('li');
+ const allItems = this._suggestionList.querySelectorAll("li");
activeItem = allItems[this._activeResult];
- activeItem.classList.add('active');
+ activeItem.classList.add("active");
}
}
}
diff --git a/client/js/controls/comment_control.js b/client/js/controls/comment_control.js
index c105bc0..cdcfd53 100644
--- a/client/js/controls/comment_control.js
+++ b/client/js/controls/comment_control.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const events = require('../events.js');
-const views = require('../util/views.js');
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('comment');
-const scoreTemplate = views.getTemplate('score');
+const template = views.getTemplate("comment");
+const scoreTemplate = views.getTemplate("score");
class CommentControl extends events.EventTarget {
constructor(hostNode, comment, onlyEditing) {
@@ -16,104 +16,111 @@ class CommentControl extends events.EventTarget {
this._onlyEditing = onlyEditing;
if (comment) {
- comment.addEventListener(
- 'change', e => this._evtChange(e));
- comment.addEventListener(
- 'changeScore', e => this._evtChangeScore(e));
+ comment.addEventListener("change", (e) => this._evtChange(e));
+ comment.addEventListener("changeScore", (e) =>
+ this._evtChangeScore(e)
+ );
}
const isLoggedIn = comment && api.isLoggedIn(comment.user);
- const infix = isLoggedIn ? 'own' : 'any';
- views.replaceContent(this._hostNode, template({
- comment: comment,
- user: comment ? comment.user : api.user,
- canViewUsers: api.hasPrivilege('users:view'),
- canEditComment: api.hasPrivilege(`comments:edit:${infix}`),
- canDeleteComment: api.hasPrivilege(`comments:delete:${infix}`),
- onlyEditing: onlyEditing,
- }));
+ const infix = isLoggedIn ? "own" : "any";
+ views.replaceContent(
+ this._hostNode,
+ template({
+ comment: comment,
+ user: comment ? comment.user : api.user,
+ canViewUsers: api.hasPrivilege("users:view"),
+ canEditComment: api.hasPrivilege(`comments:edit:${infix}`),
+ canDeleteComment: api.hasPrivilege(`comments:delete:${infix}`),
+ onlyEditing: onlyEditing,
+ })
+ );
if (this._editButtonNodes) {
for (let node of this._editButtonNodes) {
- node.addEventListener('click', e => this._evtEditClick(e));
+ node.addEventListener("click", (e) => this._evtEditClick(e));
}
}
if (this._deleteButtonNode) {
- this._deleteButtonNode.addEventListener(
- 'click', e => this._evtDeleteClick(e));
+ this._deleteButtonNode.addEventListener("click", (e) =>
+ this._evtDeleteClick(e)
+ );
}
if (this._previewEditingButtonNode) {
- this._previewEditingButtonNode.addEventListener(
- 'click', e => this._evtPreviewEditingClick(e));
+ this._previewEditingButtonNode.addEventListener("click", (e) =>
+ this._evtPreviewEditingClick(e)
+ );
}
if (this._saveChangesButtonNode) {
- this._saveChangesButtonNode.addEventListener(
- 'click', e => this._evtSaveChangesClick(e));
+ this._saveChangesButtonNode.addEventListener("click", (e) =>
+ this._evtSaveChangesClick(e)
+ );
}
if (this._cancelEditingButtonNode) {
- this._cancelEditingButtonNode.addEventListener(
- 'click', e => this._evtCancelEditingClick(e));
+ this._cancelEditingButtonNode.addEventListener("click", (e) =>
+ this._evtCancelEditingClick(e)
+ );
}
this._installScore();
if (onlyEditing) {
- this._selectNav('edit');
- this._selectTab('edit');
+ this._selectNav("edit");
+ this._selectTab("edit");
} else {
- this._selectNav('readonly');
- this._selectTab('preview');
+ this._selectNav("readonly");
+ this._selectTab("preview");
}
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _scoreContainerNode() {
- return this._hostNode.querySelector('.score-container');
+ return this._hostNode.querySelector(".score-container");
}
get _editButtonNodes() {
- return this._hostNode.querySelectorAll('li.edit>a, a.edit');
+ return this._hostNode.querySelectorAll("li.edit>a, a.edit");
}
get _previewEditingButtonNode() {
- return this._hostNode.querySelector('li.preview>a');
+ return this._hostNode.querySelector("li.preview>a");
}
get _deleteButtonNode() {
- return this._hostNode.querySelector('.delete');
+ return this._hostNode.querySelector(".delete");
}
get _upvoteButtonNode() {
- return this._hostNode.querySelector('.upvote');
+ return this._hostNode.querySelector(".upvote");
}
get _downvoteButtonNode() {
- return this._hostNode.querySelector('.downvote');
+ return this._hostNode.querySelector(".downvote");
}
get _saveChangesButtonNode() {
- return this._hostNode.querySelector('.save-changes');
+ return this._hostNode.querySelector(".save-changes");
}
get _cancelEditingButtonNode() {
- return this._hostNode.querySelector('.cancel-editing');
+ return this._hostNode.querySelector(".cancel-editing");
}
get _textareaNode() {
- return this._hostNode.querySelector('.tab.edit textarea');
+ return this._hostNode.querySelector(".tab.edit textarea");
}
get _contentNode() {
- return this._hostNode.querySelector('.tab.preview .comment-content');
+ return this._hostNode.querySelector(".tab.preview .comment-content");
}
get _heightKeeperNode() {
- return this._hostNode.querySelector('.keep-height');
+ return this._hostNode.querySelector(".keep-height");
}
_installScore() {
@@ -122,32 +129,35 @@ class CommentControl extends events.EventTarget {
scoreTemplate({
score: this._comment ? this._comment.score : 0,
ownScore: this._comment ? this._comment.ownScore : 0,
- canScore: api.hasPrivilege('comments:score'),
- }));
+ canScore: api.hasPrivilege("comments:score"),
+ })
+ );
if (this._upvoteButtonNode) {
- this._upvoteButtonNode.addEventListener(
- 'click', e => this._evtScoreClick(e, 1));
+ this._upvoteButtonNode.addEventListener("click", (e) =>
+ this._evtScoreClick(e, 1)
+ );
}
if (this._downvoteButtonNode) {
- this._downvoteButtonNode.addEventListener(
- 'click', e => this._evtScoreClick(e, -1));
+ this._downvoteButtonNode.addEventListener("click", (e) =>
+ this._evtScoreClick(e, -1)
+ );
}
}
enterEditMode() {
- this._selectNav('edit');
- this._selectTab('edit');
+ this._selectNav("edit");
+ this._selectTab("edit");
}
exitEditMode() {
if (this._onlyEditing) {
- this._selectNav('edit');
- this._selectTab('edit');
- this._setText('');
+ this._selectNav("edit");
+ this._selectTab("edit");
+ this._setText("");
} else {
- this._selectNav('readonly');
- this._selectTab('preview');
+ this._selectNav("readonly");
+ this._selectTab("preview");
this._setText(this._comment.text);
}
this._forgetHeight();
@@ -173,27 +183,31 @@ class CommentControl extends events.EventTarget {
_evtScoreClick(e, score) {
e.preventDefault();
- if (!api.hasPrivilege('comments:score')) {
+ if (!api.hasPrivilege("comments:score")) {
return;
}
- this.dispatchEvent(new CustomEvent('score', {
- detail: {
- comment: this._comment,
- score: this._comment.ownScore === score ? 0 : score,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("score", {
+ detail: {
+ comment: this._comment,
+ score: this._comment.ownScore === score ? 0 : score,
+ },
+ })
+ );
}
_evtDeleteClick(e) {
e.preventDefault();
- if (!window.confirm('Are you sure you want to delete this comment?')) {
+ if (!window.confirm("Are you sure you want to delete this comment?")) {
return;
}
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- comment: this._comment,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ comment: this._comment,
+ },
+ })
+ );
}
_evtChange(e) {
@@ -206,21 +220,24 @@ class CommentControl extends events.EventTarget {
_evtPreviewEditingClick(e) {
e.preventDefault();
- this._contentNode.innerHTML =
- misc.formatMarkdown(this._textareaNode.value);
- this._selectTab('edit');
- this._selectTab('preview');
+ this._contentNode.innerHTML = misc.formatMarkdown(
+ this._textareaNode.value
+ );
+ this._selectTab("edit");
+ this._selectTab("preview");
}
_evtSaveChangesClick(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- target: this,
- comment: this._comment,
- text: this._textareaNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ target: this,
+ comment: this._comment,
+ text: this._textareaNode.value,
+ },
+ })
+ );
}
_evtCancelEditingClick(e) {
@@ -234,22 +251,22 @@ class CommentControl extends events.EventTarget {
}
_selectNav(modeName) {
- for (let node of this._hostNode.querySelectorAll('nav')) {
- node.classList.toggle('active', node.classList.contains(modeName));
+ for (let node of this._hostNode.querySelectorAll("nav")) {
+ node.classList.toggle("active", node.classList.contains(modeName));
}
}
_selectTab(tabName) {
this._ensureHeight();
- for (let node of this._hostNode.querySelectorAll('.tab, .tabs li')) {
- node.classList.toggle('active', node.classList.contains(tabName));
+ for (let node of this._hostNode.querySelectorAll(".tab, .tabs li")) {
+ node.classList.toggle("active", node.classList.contains(tabName));
}
}
_ensureHeight() {
this._heightKeeperNode.style.minHeight =
- this._heightKeeperNode.getBoundingClientRect().height + 'px';
+ this._heightKeeperNode.getBoundingClientRect().height + "px";
}
_forgetHeight() {
diff --git a/client/js/controls/comment_list_control.js b/client/js/controls/comment_list_control.js
index 4f57fd2..7717ee5 100644
--- a/client/js/controls/comment_list_control.js
+++ b/client/js/controls/comment_list_control.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const CommentControl = require('../controls/comment_control.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const CommentControl = require("../controls/comment_control.js");
-const template = views.getTemplate('comment-list');
+const template = views.getTemplate("comment-list");
class CommentListControl extends events.EventTarget {
constructor(hostNode, comments, reversed) {
@@ -13,8 +13,8 @@ class CommentListControl extends events.EventTarget {
this._comments = comments;
this._commentIdToNode = {};
- comments.addEventListener('add', e => this._evtAdd(e));
- comments.addEventListener('remove', e => this._evtRemove(e));
+ comments.addEventListener("add", (e) => this._evtAdd(e));
+ comments.addEventListener("remove", (e) => this._evtRemove(e));
views.replaceContent(this._hostNode, template());
@@ -28,16 +28,19 @@ class CommentListControl extends events.EventTarget {
}
get _commentListNode() {
- return this._hostNode.querySelector('ul');
+ return this._hostNode.querySelector("ul");
}
_installCommentNode(comment) {
- const commentListItemNode = document.createElement('li');
+ const commentListItemNode = document.createElement("li");
const commentControl = new CommentControl(
- commentListItemNode, comment, false);
- events.proxyEvent(commentControl, this, 'submit');
- events.proxyEvent(commentControl, this, 'score');
- events.proxyEvent(commentControl, this, 'delete');
+ commentListItemNode,
+ comment,
+ false
+ );
+ events.proxyEvent(commentControl, this, "submit");
+ events.proxyEvent(commentControl, this, "score");
+ events.proxyEvent(commentControl, this, "delete");
this._commentIdToNode[comment.id] = commentListItemNode;
this._commentListNode.appendChild(commentListItemNode);
}
diff --git a/client/js/controls/expander_control.js b/client/js/controls/expander_control.js
index 28a4ffb..11ad3ef 100644
--- a/client/js/controls/expander_control.js
+++ b/client/js/controls/expander_control.js
@@ -1,26 +1,28 @@
-'use strict';
+"use strict";
-const ICON_CLASS_OPENED = 'fa-chevron-down';
-const ICON_CLASS_CLOSED = 'fa-chevron-up';
+const ICON_CLASS_OPENED = "fa-chevron-down";
+const ICON_CLASS_CLOSED = "fa-chevron-up";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('expander');
+const template = views.getTemplate("expander");
class ExpanderControl {
constructor(name, title, nodes) {
this._name = name;
- nodes = Array.from(nodes).filter(n => n);
+ nodes = Array.from(nodes).filter((n) => n);
if (!nodes.length) {
return;
}
- const expanderNode = template({title: title});
- const toggleLinkNode = expanderNode.querySelector('a');
- const toggleIconNode = expanderNode.querySelector('i');
- const expanderContentNode = expanderNode.querySelector('div');
- toggleLinkNode.addEventListener('click', e => this._evtToggleClick(e));
+ const expanderNode = template({ title: title });
+ const toggleLinkNode = expanderNode.querySelector("a");
+ const toggleIconNode = expanderNode.querySelector("i");
+ const expanderContentNode = expanderNode.querySelector("div");
+ toggleLinkNode.addEventListener("click", (e) =>
+ this._evtToggleClick(e)
+ );
nodes[0].parentNode.insertBefore(expanderNode, nodes[0]);
@@ -32,29 +34,30 @@ class ExpanderControl {
this._toggleIconNode = toggleIconNode;
expanderNode.classList.toggle(
- 'collapsed',
- this._allStates[this._name] === undefined ?
- false :
- !this._allStates[this._name]);
+ "collapsed",
+ this._allStates[this._name] === undefined
+ ? false
+ : !this._allStates[this._name]
+ );
this._syncIcon();
}
// eslint-disable-next-line accessor-pairs
set title(newTitle) {
if (this._expanderNode) {
- this._expanderNode
- .querySelector('header span')
- .textContent = newTitle;
+ this._expanderNode.querySelector(
+ "header span"
+ ).textContent = newTitle;
}
}
get _isOpened() {
- return !this._expanderNode.classList.contains('collapsed');
+ return !this._expanderNode.classList.contains("collapsed");
}
get _allStates() {
try {
- return JSON.parse(localStorage.getItem('expander')) || {};
+ return JSON.parse(localStorage.getItem("expander")) || {};
} catch (e) {
return {};
}
@@ -63,12 +66,12 @@ class ExpanderControl {
_save() {
const newStates = Object.assign({}, this._allStates);
newStates[this._name] = this._isOpened;
- localStorage.setItem('expander', JSON.stringify(newStates));
+ localStorage.setItem("expander", JSON.stringify(newStates));
}
_evtToggleClick(e) {
e.preventDefault();
- this._expanderNode.classList.toggle('collapsed');
+ this._expanderNode.classList.toggle("collapsed");
this._save();
this._syncIcon();
}
diff --git a/client/js/controls/file_dropper_control.js b/client/js/controls/file_dropper_control.js
index a618720..2dfb492 100644
--- a/client/js/controls/file_dropper_control.js
+++ b/client/js/controls/file_dropper_control.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('file-dropper');
+const template = views.getTemplate("file-dropper");
const KEY_RETURN = 13;
@@ -17,37 +17,42 @@ class FileDropperControl extends events.EventTarget {
allowMultiple: options.allowMultiple,
allowUrls: options.allowUrls,
lock: options.lock,
- id: 'file-' + Math.random().toString(36).substring(7),
+ id: "file-" + Math.random().toString(36).substring(7),
urlPlaceholder:
- options.urlPlaceholder || 'Alternatively, paste an URL here.',
+ options.urlPlaceholder || "Alternatively, paste an URL here.",
});
- this._dropperNode = source.querySelector('.file-dropper');
- this._urlInputNode = source.querySelector('input[type=text]');
- this._urlConfirmButtonNode = source.querySelector('button');
- this._fileInputNode = source.querySelector('input[type=file]');
- this._fileInputNode.style.display = 'none';
+ this._dropperNode = source.querySelector(".file-dropper");
+ this._urlInputNode = source.querySelector("input[type=text]");
+ this._urlConfirmButtonNode = source.querySelector("button");
+ this._fileInputNode = source.querySelector("input[type=file]");
+ this._fileInputNode.style.display = "none";
this._fileInputNode.multiple = options.allowMultiple || false;
this._counter = 0;
- this._dropperNode.addEventListener(
- 'dragenter', e => this._evtDragEnter(e));
- this._dropperNode.addEventListener(
- 'dragleave', e => this._evtDragLeave(e));
- this._dropperNode.addEventListener(
- 'dragover', e => this._evtDragOver(e));
- this._dropperNode.addEventListener(
- 'drop', e => this._evtDrop(e));
- this._fileInputNode.addEventListener(
- 'change', e => this._evtFileChange(e));
+ this._dropperNode.addEventListener("dragenter", (e) =>
+ this._evtDragEnter(e)
+ );
+ this._dropperNode.addEventListener("dragleave", (e) =>
+ this._evtDragLeave(e)
+ );
+ this._dropperNode.addEventListener("dragover", (e) =>
+ this._evtDragOver(e)
+ );
+ this._dropperNode.addEventListener("drop", (e) => this._evtDrop(e));
+ this._fileInputNode.addEventListener("change", (e) =>
+ this._evtFileChange(e)
+ );
if (this._urlInputNode) {
- this._urlInputNode.addEventListener(
- 'keydown', e => this._evtUrlInputKeyDown(e));
+ this._urlInputNode.addEventListener("keydown", (e) =>
+ this._evtUrlInputKeyDown(e)
+ );
}
if (this._urlConfirmButtonNode) {
- this._urlConfirmButtonNode.addEventListener(
- 'click', e => this._evtUrlConfirmButtonClick(e));
+ this._urlConfirmButtonNode.addEventListener("click", (e) =>
+ this._evtUrlConfirmButtonClick(e)
+ );
}
this._originalHtml = this._dropperNode.innerHTML;
@@ -56,24 +61,27 @@ class FileDropperControl extends events.EventTarget {
reset() {
this._dropperNode.innerHTML = this._originalHtml;
- this.dispatchEvent(new CustomEvent('reset'));
+ this.dispatchEvent(new CustomEvent("reset"));
}
_emitFiles(files) {
files = Array.from(files);
if (this._options.lock) {
- this._dropperNode.innerText =
- files.map(file => file.name).join(', ');
+ this._dropperNode.innerText = files
+ .map((file) => file.name)
+ .join(", ");
}
this.dispatchEvent(
- new CustomEvent('fileadd', {detail: {files: files}}));
+ new CustomEvent("fileadd", { detail: { files: files } })
+ );
}
_emitUrls(urls) {
- urls = Array.from(urls).map(url => url.trim());
+ urls = Array.from(urls).map((url) => url.trim());
if (this._options.lock) {
- this._dropperNode.innerText =
- urls.map(url => url.split(/\//).reverse()[0]).join(', ');
+ this._dropperNode.innerText = urls
+ .map((url) => url.split(/\//).reverse()[0])
+ .join(", ");
}
for (let url of urls) {
if (!url) {
@@ -84,18 +92,20 @@ class FileDropperControl extends events.EventTarget {
return;
}
}
- this.dispatchEvent(new CustomEvent('urladd', {detail: {urls: urls}}));
+ this.dispatchEvent(
+ new CustomEvent("urladd", { detail: { urls: urls } })
+ );
}
_evtDragEnter(e) {
- this._dropperNode.classList.add('active');
+ this._dropperNode.classList.add("active");
this._counter++;
}
_evtDragLeave(e) {
this._counter--;
if (this._counter === 0) {
- this._dropperNode.classList.remove('active');
+ this._dropperNode.classList.remove("active");
}
}
@@ -109,12 +119,12 @@ class FileDropperControl extends events.EventTarget {
_evtDrop(e) {
e.preventDefault();
- this._dropperNode.classList.remove('active');
+ this._dropperNode.classList.remove("active");
if (!e.dataTransfer.files.length) {
- window.alert('Only files are supported.');
+ window.alert("Only files are supported.");
}
if (!this._options.allowMultiple && e.dataTransfer.files.length > 1) {
- window.alert('Cannot select multiple files.');
+ window.alert("Cannot select multiple files.");
}
this._emitFiles(e.dataTransfer.files);
}
@@ -124,16 +134,16 @@ class FileDropperControl extends events.EventTarget {
return;
}
e.preventDefault();
- this._dropperNode.classList.remove('active');
+ this._dropperNode.classList.remove("active");
this._emitUrls(this._urlInputNode.value.split(/[\r\n]/));
- this._urlInputNode.value = '';
+ this._urlInputNode.value = "";
}
_evtUrlConfirmButtonClick(e) {
e.preventDefault();
- this._dropperNode.classList.remove('active');
+ this._dropperNode.classList.remove("active");
this._emitUrls(this._urlInputNode.value.split(/[\r\n]/));
- this._urlInputNode.value = '';
+ this._urlInputNode.value = "";
}
}
diff --git a/client/js/controls/pool_auto_complete_control.js b/client/js/controls/pool_auto_complete_control.js
index f720833..97794a8 100644
--- a/client/js/controls/pool_auto_complete_control.js
+++ b/client/js/controls/pool_auto_complete_control.js
@@ -1,43 +1,54 @@
-'use strict';
+"use strict";
-const misc = require('../util/misc.js');
-const PoolList = require('../models/pool_list.js');
-const AutoCompleteControl = require('./auto_complete_control.js');
+const misc = require("../util/misc.js");
+const PoolList = require("../models/pool_list.js");
+const AutoCompleteControl = require("./auto_complete_control.js");
function _poolListToMatches(pools, options) {
- return [...pools].sort((pool1, pool2) => {
- return pool2.postCount - pool1.postCount;
- }).map(pool => {
- let cssName = misc.makeCssName(pool.category, 'pool');
- const caption = (
- '<span class="' + cssName + '">'
- + misc.escapeHtml(pool.names[0] + ' (' + pool.postCount + ')')
- + '</span>');
- return {
- caption: caption,
- value: pool,
- };
- });
+ return [...pools]
+ .sort((pool1, pool2) => {
+ return pool2.postCount - pool1.postCount;
+ })
+ .map((pool) => {
+ let cssName = misc.makeCssName(pool.category, "pool");
+ const caption =
+ '<span class="' +
+ cssName +
+ '">' +
+ misc.escapeHtml(pool.names[0] + " (" + pool.postCount + ")") +
+ "</span>";
+ return {
+ caption: caption,
+ value: pool,
+ };
+ });
}
class PoolAutoCompleteControl extends AutoCompleteControl {
constructor(input, options) {
const minLengthForPartialSearch = 3;
- options.getMatches = text => {
+ options.getMatches = (text) => {
const term = misc.escapeSearchTerm(text);
- const query = (
- text.length < minLengthForPartialSearch
- ? term + '*'
- : '*' + term + '*') + ' sort:post-count';
+ const query =
+ (text.length < minLengthForPartialSearch
+ ? term + "*"
+ : "*" + term + "*") + " sort:post-count";
return new Promise((resolve, reject) => {
- PoolList.search(
- query, 0, this._options.maxResults, ['id', 'names', 'category', 'postCount', 'version'])
- .then(
- response => resolve(
- _poolListToMatches(response.results, this._options)),
- reject);
+ PoolList.search(query, 0, this._options.maxResults, [
+ "id",
+ "names",
+ "category",
+ "postCount",
+ "version",
+ ]).then(
+ (response) =>
+ resolve(
+ _poolListToMatches(response.results, this._options)
+ ),
+ reject
+ );
});
};
diff --git a/client/js/controls/pool_input_control.js b/client/js/controls/pool_input_control.js
index af1c744..c8995da 100644
--- a/client/js/controls/pool_input_control.js
+++ b/client/js/controls/pool_input_control.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const pools = require('../pools.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const Pool = require('../models/pool.js');
-const settings = require('../models/settings.js');
-const events = require('../events.js');
-const views = require('../util/views.js');
-const PoolAutoCompleteControl = require('./pool_auto_complete_control.js');
+const api = require("../api.js");
+const pools = require("../pools.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const Pool = require("../models/pool.js");
+const settings = require("../models/settings.js");
+const events = require("../events.js");
+const views = require("../util/views.js");
+const PoolAutoCompleteControl = require("./pool_auto_complete_control.js");
const KEY_SPACE = 32;
const KEY_RETURN = 13;
-const SOURCE_INIT = 'init';
-const SOURCE_IMPLICATION = 'implication';
-const SOURCE_USER_INPUT = 'user-input';
-const SOURCE_CLIPBOARD = 'clipboard';
+const SOURCE_INIT = "init";
+const SOURCE_IMPLICATION = "implication";
+const SOURCE_USER_INPUT = "user-input";
+const SOURCE_CLIPBOARD = "clipboard";
-const template = views.getTemplate('pool-input');
+const template = views.getTemplate("pool-input");
function _fadeOutListItemNodeStatus(listItemNode) {
if (listItemNode.classList.length) {
@@ -27,8 +27,7 @@ function _fadeOutListItemNodeStatus(listItemNode) {
}
listItemNode.fadeTimeout = window.setTimeout(() => {
while (listItemNode.classList.length) {
- listItemNode.classList.remove(
- listItemNode.classList.item(0));
+ listItemNode.classList.remove(listItemNode.classList.item(0));
}
listItemNode.fadeTimeout = null;
}, 2500);
@@ -45,29 +44,33 @@ class PoolInputControl extends events.EventTarget {
// dom
const editAreaNode = template();
this._editAreaNode = editAreaNode;
- this._poolInputNode = editAreaNode.querySelector('input');
- this._poolListNode = editAreaNode.querySelector('ul.compact-pools');
+ this._poolInputNode = editAreaNode.querySelector("input");
+ this._poolListNode = editAreaNode.querySelector("ul.compact-pools");
this._autoCompleteControl = new PoolAutoCompleteControl(
- this._poolInputNode, {
+ this._poolInputNode,
+ {
getTextToFind: () => {
return this._poolInputNode.value;
},
- confirm: pool => {
- this._poolInputNode.value = '';
+ confirm: (pool) => {
+ this._poolInputNode.value = "";
this.addPool(pool, SOURCE_USER_INPUT);
},
- delete: pool => {
- this._poolInputNode.value = '';
+ delete: (pool) => {
+ this._poolInputNode.value = "";
this.deletePool(pool);
},
- verticalShift: -2
- });
+ verticalShift: -2,
+ }
+ );
// show
- this._hostNode.style.display = 'none';
+ this._hostNode.style.display = "none";
this._hostNode.parentNode.insertBefore(
- this._editAreaNode, hostNode.nextSibling);
+ this._editAreaNode,
+ hostNode.nextSibling
+ );
// add existing pools
for (let pool of [...this.pools]) {
@@ -81,19 +84,21 @@ class PoolInputControl extends events.EventTarget {
return Promise.resolve();
}
- this.pools.add(pool, false)
+ this.pools.add(pool, false);
const listItemNode = this._createListItemNode(pool);
if (!pool.category) {
- listItemNode.classList.add('new');
+ listItemNode.classList.add("new");
}
this._poolListNode.prependChild(listItemNode);
_fadeOutListItemNodeStatus(listItemNode);
- this.dispatchEvent(new CustomEvent('add', {
- detail: {pool: pool, source: source},
- }));
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(
+ new CustomEvent("add", {
+ detail: { pool: pool, source: source },
+ })
+ );
+ this.dispatchEvent(new CustomEvent("change"));
return Promise.resolve();
}
@@ -107,52 +112,57 @@ class PoolInputControl extends events.EventTarget {
this._deleteListItemNode(pool);
- this.dispatchEvent(new CustomEvent('remove', {
- detail: {pool: pool},
- }));
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(
+ new CustomEvent("remove", {
+ detail: { pool: pool },
+ })
+ );
+ this.dispatchEvent(new CustomEvent("change"));
}
_createListItemNode(pool) {
- const className = pool.category ?
- misc.makeCssName(pool.category, 'pool') :
- null;
+ const className = pool.category
+ ? misc.makeCssName(pool.category, "pool")
+ : null;
- const poolLinkNode = document.createElement('a');
+ const poolLinkNode = document.createElement("a");
if (className) {
poolLinkNode.classList.add(className);
}
poolLinkNode.setAttribute(
- 'href', uri.formatClientLink('pool', pool.names[0]));
+ "href",
+ uri.formatClientLink("pool", pool.names[0])
+ );
- const poolIconNode = document.createElement('i');
- poolIconNode.classList.add('fa');
- poolIconNode.classList.add('fa-pool');
+ const poolIconNode = document.createElement("i");
+ poolIconNode.classList.add("fa");
+ poolIconNode.classList.add("fa-pool");
poolLinkNode.appendChild(poolIconNode);
- const searchLinkNode = document.createElement('a');
+ const searchLinkNode = document.createElement("a");
if (className) {
searchLinkNode.classList.add(className);
}
searchLinkNode.setAttribute(
- 'href', uri.formatClientLink(
- 'posts', {query: "pool:" + pool.id}));
- searchLinkNode.textContent = pool.names[0] + ' ';
+ "href",
+ uri.formatClientLink("posts", { query: "pool:" + pool.id })
+ );
+ searchLinkNode.textContent = pool.names[0] + " ";
- const usagesNode = document.createElement('span');
- usagesNode.classList.add('pool-usages');
- usagesNode.setAttribute('data-pseudo-content', pool.postCount);
+ const usagesNode = document.createElement("span");
+ usagesNode.classList.add("pool-usages");
+ usagesNode.setAttribute("data-pseudo-content", pool.postCount);
- const removalLinkNode = document.createElement('a');
- removalLinkNode.classList.add('remove-pool');
- removalLinkNode.setAttribute('href', '');
- removalLinkNode.setAttribute('data-pseudo-content', '×');
- removalLinkNode.addEventListener('click', e => {
+ const removalLinkNode = document.createElement("a");
+ removalLinkNode.classList.add("remove-pool");
+ removalLinkNode.setAttribute("href", "");
+ removalLinkNode.setAttribute("data-pseudo-content", "×");
+ removalLinkNode.addEventListener("click", (e) => {
e.preventDefault();
this.deletePool(pool);
});
- const listItemNode = document.createElement('li');
+ const listItemNode = document.createElement("li");
listItemNode.appendChild(removalLinkNode);
listItemNode.appendChild(poolLinkNode);
listItemNode.appendChild(searchLinkNode);
diff --git a/client/js/controls/post_content_control.js b/client/js/controls/post_content_control.js
index d1848b3..55daca7 100644
--- a/client/js/controls/post_content_control.js
+++ b/client/js/controls/post_content_control.js
@@ -1,36 +1,38 @@
-'use strict';
+"use strict";
-const settings = require('../models/settings.js');
-const views = require('../util/views.js');
-const optimizedResize = require('../util/optimized_resize.js');
+const settings = require("../models/settings.js");
+const views = require("../util/views.js");
+const optimizedResize = require("../util/optimized_resize.js");
class PostContentControl {
constructor(hostNode, post, viewportSizeCalculator, fitFunctionOverride) {
this._post = post;
this._viewportSizeCalculator = viewportSizeCalculator;
this._hostNode = hostNode;
- this._template = views.getTemplate('post-content');
+ this._template = views.getTemplate("post-content");
let fitMode = settings.get().fitMode;
- if (typeof fitFunctionOverride !== 'undefined') {
+ if (typeof fitFunctionOverride !== "undefined") {
fitMode = fitFunctionOverride;
}
- this._currentFitFunction = {
- 'fit-both': this.fitBoth,
- 'fit-original': this.fitOriginal,
- 'fit-width': this.fitWidth,
- 'fit-height': this.fitHeight,
- }[fitMode] || this.fitBoth;
+ this._currentFitFunction =
+ {
+ "fit-both": this.fitBoth,
+ "fit-original": this.fitOriginal,
+ "fit-width": this.fitWidth,
+ "fit-height": this.fitHeight,
+ }[fitMode] || this.fitBoth;
this._install();
- this._post.addEventListener(
- 'changeContent', e => this._evtPostContentChange(e));
+ this._post.addEventListener("changeContent", (e) =>
+ this._evtPostContentChange(e)
+ );
}
disableOverlay() {
- this._hostNode.querySelector('.post-overlay').style.display = 'none';
+ this._hostNode.querySelector(".post-overlay").style.display = "none";
}
fitWidth() {
@@ -92,10 +94,11 @@ class PostContentControl {
_resize(width, height) {
const resizeListenerNodes = [this._postContentNode].concat(
- ...this._postContentNode.querySelectorAll('.resize-listener'));
+ ...this._postContentNode.querySelectorAll(".resize-listener")
+ );
for (let node of resizeListenerNodes) {
- node.style.width = width + 'px';
- node.style.height = height + 'px';
+ node.style.width = width + "px";
+ node.style.height = height + "px";
}
}
@@ -106,10 +109,9 @@ class PostContentControl {
_install() {
this._reinstall();
optimizedResize.add(() => this._refreshSize());
- views.monitorNodeRemoval(
- this._hostNode, () => {
- this._uninstall();
- });
+ views.monitorNodeRemoval(this._hostNode, () => {
+ this._uninstall();
+ });
}
_reinstall() {
@@ -118,7 +120,7 @@ class PostContentControl {
autoplay: settings.get().autoplayVideos,
});
if (settings.get().transparencyGrid) {
- newNode.classList.add('transparency-grid');
+ newNode.classList.add("transparency-grid");
}
if (this._postContentNode) {
this._hostNode.replaceChild(newNode, this._postContentNode);
diff --git a/client/js/controls/post_edit_sidebar_control.js b/client/js/controls/post_edit_sidebar_control.js
index 495dcdb..c6b7c22 100644
--- a/client/js/controls/post_edit_sidebar_control.js
+++ b/client/js/controls/post_edit_sidebar_control.js
@@ -1,17 +1,17 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const events = require('../events.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const Note = require('../models/note.js');
-const Point = require('../models/point.js');
-const TagInputControl = require('./tag_input_control.js');
-const PoolInputControl = require('./pool_input_control.js');
-const ExpanderControl = require('../controls/expander_control.js');
-const FileDropperControl = require('../controls/file_dropper_control.js');
+const api = require("../api.js");
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const Note = require("../models/note.js");
+const Point = require("../models/point.js");
+const TagInputControl = require("./tag_input_control.js");
+const PoolInputControl = require("./pool_input_control.js");
+const ExpanderControl = require("../controls/expander_control.js");
+const FileDropperControl = require("../controls/file_dropper_control.js");
-const template = views.getTemplate('post-edit-sidebar');
+const template = views.getTemplate("post-edit-sidebar");
class PostEditSidebarControl extends events.EventTarget {
constructor(hostNode, post, postContentControl, postNotesOverlayControl) {
@@ -24,182 +24,222 @@ class PostEditSidebarControl extends events.EventTarget {
this._postNotesOverlayControl.switchToPassiveEdit();
- views.replaceContent(this._hostNode, template({
- post: this._post,
- enableSafety: api.safetyEnabled(),
- hasClipboard: document.queryCommandSupported('copy'),
- canEditPostSafety: api.hasPrivilege('posts:edit:safety'),
- canEditPostSource: api.hasPrivilege('posts:edit:source'),
- canEditPostTags: api.hasPrivilege('posts:edit:tags'),
- canEditPostRelations: api.hasPrivilege('posts:edit:relations'),
- canEditPostNotes: api.hasPrivilege('posts:edit:notes') &&
- post.type !== 'video' &&
- post.type !== 'flash',
- canEditPostFlags: api.hasPrivilege('posts:edit:flags'),
- canEditPostContent: api.hasPrivilege('posts:edit:content'),
- canEditPostThumbnail: api.hasPrivilege('posts:edit:thumbnail'),
- canEditPoolPosts: api.hasPrivilege('pools:edit:posts'),
- canCreateAnonymousPosts: api.hasPrivilege('posts:create:anonymous'),
- canDeletePosts: api.hasPrivilege('posts:delete'),
- canFeaturePosts: api.hasPrivilege('posts:feature'),
- canMergePosts: api.hasPrivilege('posts:merge'),
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ post: this._post,
+ enableSafety: api.safetyEnabled(),
+ hasClipboard: document.queryCommandSupported("copy"),
+ canEditPostSafety: api.hasPrivilege("posts:edit:safety"),
+ canEditPostSource: api.hasPrivilege("posts:edit:source"),
+ canEditPostTags: api.hasPrivilege("posts:edit:tags"),
+ canEditPostRelations: api.hasPrivilege("posts:edit:relations"),
+ canEditPostNotes:
+ api.hasPrivilege("posts:edit:notes") &&
+ post.type !== "video" &&
+ post.type !== "flash",
+ canEditPostFlags: api.hasPrivilege("posts:edit:flags"),
+ canEditPostContent: api.hasPrivilege("posts:edit:content"),
+ canEditPostThumbnail: api.hasPrivilege("posts:edit:thumbnail"),
+ canEditPoolPosts: api.hasPrivilege("pools:edit:posts"),
+ canCreateAnonymousPosts: api.hasPrivilege(
+ "posts:create:anonymous"
+ ),
+ canDeletePosts: api.hasPrivilege("posts:delete"),
+ canFeaturePosts: api.hasPrivilege("posts:feature"),
+ canMergePosts: api.hasPrivilege("posts:merge"),
+ })
+ );
new ExpanderControl(
- 'post-info',
- 'Basic info',
- this._hostNode.querySelectorAll('.safety, .relations, .flags, .post-source'));
+ "post-info",
+ "Basic info",
+ this._hostNode.querySelectorAll(
+ ".safety, .relations, .flags, .post-source"
+ )
+ );
this._tagsExpander = new ExpanderControl(
- 'post-tags',
+ "post-tags",
`Tags (${this._post.tags.length})`,
- this._hostNode.querySelectorAll('.tags'));
+ this._hostNode.querySelectorAll(".tags")
+ );
this._notesExpander = new ExpanderControl(
- 'post-notes',
- 'Notes',
- this._hostNode.querySelectorAll('.notes'));
+ "post-notes",
+ "Notes",
+ this._hostNode.querySelectorAll(".notes")
+ );
this._poolsExpander = new ExpanderControl(
- 'post-pools',
+ "post-pools",
`Pools (${this._post.pools.length})`,
- this._hostNode.querySelectorAll('.pools'));
+ this._hostNode.querySelectorAll(".pools")
+ );
new ExpanderControl(
- 'post-content',
- 'Content',
- this._hostNode.querySelectorAll('.post-content, .post-thumbnail'));
+ "post-content",
+ "Content",
+ this._hostNode.querySelectorAll(".post-content, .post-thumbnail")
+ );
new ExpanderControl(
- 'post-management',
- 'Management',
- this._hostNode.querySelectorAll('.management'));
+ "post-management",
+ "Management",
+ this._hostNode.querySelectorAll(".management")
+ );
this._syncExpanderTitles();
if (this._formNode) {
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtSubmit(e)
+ );
}
if (this._tagInputNode) {
this._tagControl = new TagInputControl(
- this._tagInputNode, post.tags);
+ this._tagInputNode,
+ post.tags
+ );
}
if (this._poolInputNode) {
this._poolControl = new PoolInputControl(
- this._poolInputNode, post.pools);
+ this._poolInputNode,
+ post.pools
+ );
}
if (this._contentInputNode) {
this._contentFileDropper = new FileDropperControl(
- this._contentInputNode, {allowUrls: true,
+ this._contentInputNode,
+ {
+ allowUrls: true,
lock: true,
- urlPlaceholder: '...or paste an URL here.'});
- this._contentFileDropper.addEventListener('fileadd', e => {
+ urlPlaceholder: "...or paste an URL here.",
+ }
+ );
+ this._contentFileDropper.addEventListener("fileadd", (e) => {
this._newPostContent = e.detail.files[0];
});
- this._contentFileDropper.addEventListener('urladd', e => {
+ this._contentFileDropper.addEventListener("urladd", (e) => {
this._newPostContent = e.detail.urls[0];
});
}
if (this._thumbnailInputNode) {
this._thumbnailFileDropper = new FileDropperControl(
- this._thumbnailInputNode, {lock: true});
- this._thumbnailFileDropper.addEventListener('fileadd', e => {
+ this._thumbnailInputNode,
+ { lock: true }
+ );
+ this._thumbnailFileDropper.addEventListener("fileadd", (e) => {
this._newPostThumbnail = e.detail.files[0];
- this._thumbnailRemovalLinkNode.style.display = 'block';
+ this._thumbnailRemovalLinkNode.style.display = "block";
});
}
if (this._thumbnailRemovalLinkNode) {
- this._thumbnailRemovalLinkNode.addEventListener(
- 'click', e => this._evtRemoveThumbnailClick(e));
- this._thumbnailRemovalLinkNode.style.display =
- this._post.hasCustomThumbnail ? 'block' : 'none';
+ this._thumbnailRemovalLinkNode.addEventListener("click", (e) =>
+ this._evtRemoveThumbnailClick(e)
+ );
+ this._thumbnailRemovalLinkNode.style.display = this._post
+ .hasCustomThumbnail
+ ? "block"
+ : "none";
}
if (this._addNoteLinkNode) {
- this._addNoteLinkNode.addEventListener(
- 'click', e => this._evtAddNoteClick(e));
+ this._addNoteLinkNode.addEventListener("click", (e) =>
+ this._evtAddNoteClick(e)
+ );
}
if (this._copyNotesLinkNode) {
- this._copyNotesLinkNode.addEventListener(
- 'click', e => this._evtCopyNotesClick(e));
+ this._copyNotesLinkNode.addEventListener("click", (e) =>
+ this._evtCopyNotesClick(e)
+ );
}
if (this._pasteNotesLinkNode) {
- this._pasteNotesLinkNode.addEventListener(
- 'click', e => this._evtPasteNotesClick(e));
+ this._pasteNotesLinkNode.addEventListener("click", (e) =>
+ this._evtPasteNotesClick(e)
+ );
}
if (this._deleteNoteLinkNode) {
- this._deleteNoteLinkNode.addEventListener(
- 'click', e => this._evtDeleteNoteClick(e));
+ this._deleteNoteLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteNoteClick(e)
+ );
}
if (this._featureLinkNode) {
- this._featureLinkNode.addEventListener(
- 'click', e => this._evtFeatureClick(e));
+ this._featureLinkNode.addEventListener("click", (e) =>
+ this._evtFeatureClick(e)
+ );
}
if (this._mergeLinkNode) {
- this._mergeLinkNode.addEventListener(
- 'click', e => this._evtMergeClick(e));
+ this._mergeLinkNode.addEventListener("click", (e) =>
+ this._evtMergeClick(e)
+ );
}
if (this._deleteLinkNode) {
- this._deleteLinkNode.addEventListener(
- 'click', e => this._evtDeleteClick(e));
+ this._deleteLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteClick(e)
+ );
}
- this._postNotesOverlayControl.addEventListener(
- 'blur', e => this._evtNoteBlur(e));
+ this._postNotesOverlayControl.addEventListener("blur", (e) =>
+ this._evtNoteBlur(e)
+ );
- this._postNotesOverlayControl.addEventListener(
- 'focus', e => this._evtNoteFocus(e));
+ this._postNotesOverlayControl.addEventListener("focus", (e) =>
+ this._evtNoteFocus(e)
+ );
- this._post.addEventListener(
- 'changeContent', e => this._evtPostContentChange(e));
+ this._post.addEventListener("changeContent", (e) =>
+ this._evtPostContentChange(e)
+ );
- this._post.addEventListener(
- 'changeThumbnail', e => this._evtPostThumbnailChange(e));
+ this._post.addEventListener("changeThumbnail", (e) =>
+ this._evtPostThumbnailChange(e)
+ );
if (this._formNode) {
const inputNodes = this._formNode.querySelectorAll(
- 'input, textarea');
+ "input, textarea"
+ );
for (let node of inputNodes) {
- node.addEventListener(
- 'change',
- e => this.dispatchEvent(new CustomEvent('change')));
+ node.addEventListener("change", (e) =>
+ this.dispatchEvent(new CustomEvent("change"))
+ );
}
- this._postNotesOverlayControl.addEventListener(
- 'change',
- e => this.dispatchEvent(new CustomEvent('change')));
+ this._postNotesOverlayControl.addEventListener("change", (e) =>
+ this.dispatchEvent(new CustomEvent("change"))
+ );
}
- for (let eventType of ['add', 'remove']) {
- this._post.notes.addEventListener(eventType, e => {
+ for (let eventType of ["add", "remove"]) {
+ this._post.notes.addEventListener(eventType, (e) => {
this._syncExpanderTitles();
});
- this._post.pools.addEventListener(eventType, e => {
+ this._post.pools.addEventListener(eventType, (e) => {
this._syncExpanderTitles();
});
}
- this._tagControl.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- this._syncExpanderTitles();
- });
+ this._tagControl.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ this._syncExpanderTitles();
+ });
if (this._noteTextareaNode) {
- this._noteTextareaNode.addEventListener(
- 'change', e => this._evtNoteTextChangeRequest(e));
+ this._noteTextareaNode.addEventListener("change", (e) =>
+ this._evtNoteTextChangeRequest(e)
+ );
}
- this._poolControl.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- this._syncExpanderTitles();
- });
+ this._poolControl.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ this._syncExpanderTitles();
+ });
}
_syncExpanderTitles() {
@@ -220,37 +260,43 @@ class PostEditSidebarControl extends events.EventTarget {
e.preventDefault();
this._thumbnailFileDropper.reset();
this._newPostThumbnail = null;
- this._thumbnailRemovalLinkNode.style.display = 'none';
+ this._thumbnailRemovalLinkNode.style.display = "none";
}
_evtFeatureClick(e) {
e.preventDefault();
- if (confirm('Are you sure you want to feature this post?')) {
- this.dispatchEvent(new CustomEvent('feature', {
- detail: {
- post: this._post,
- },
- }));
+ if (confirm("Are you sure you want to feature this post?")) {
+ this.dispatchEvent(
+ new CustomEvent("feature", {
+ detail: {
+ post: this._post,
+ },
+ })
+ );
}
}
_evtMergeClick(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('merge', {
- detail: {
- post: this._post,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("merge", {
+ detail: {
+ post: this._post,
+ },
+ })
+ );
}
_evtDeleteClick(e) {
e.preventDefault();
- if (confirm('Are you sure you want to delete this post?')) {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- post: this._post,
- },
- }));
+ if (confirm("Are you sure you want to delete this post?")) {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ post: this._post,
+ },
+ })
+ );
}
}
@@ -262,60 +308,64 @@ class PostEditSidebarControl extends events.EventTarget {
_evtNoteFocus(e) {
this._editedNote = e.detail.note;
- this._addNoteLinkNode.classList.remove('inactive');
- this._deleteNoteLinkNode.classList.remove('inactive');
- this._noteTextareaNode.removeAttribute('disabled');
+ this._addNoteLinkNode.classList.remove("inactive");
+ this._deleteNoteLinkNode.classList.remove("inactive");
+ this._noteTextareaNode.removeAttribute("disabled");
this._noteTextareaNode.value = e.detail.note.text;
}
_evtNoteBlur(e) {
this._evtNoteTextChangeRequest(null);
- this._addNoteLinkNode.classList.remove('inactive');
- this._deleteNoteLinkNode.classList.add('inactive');
+ this._addNoteLinkNode.classList.remove("inactive");
+ this._deleteNoteLinkNode.classList.add("inactive");
this._noteTextareaNode.blur();
- this._noteTextareaNode.setAttribute('disabled', 'disabled');
- this._noteTextareaNode.value = '';
+ this._noteTextareaNode.setAttribute("disabled", "disabled");
+ this._noteTextareaNode.value = "";
}
_evtAddNoteClick(e) {
e.preventDefault();
- if (e.target.classList.contains('inactive')) {
+ if (e.target.classList.contains("inactive")) {
return;
}
- this._addNoteLinkNode.classList.add('inactive');
+ this._addNoteLinkNode.classList.add("inactive");
this._postNotesOverlayControl.switchToDrawing();
}
_evtCopyNotesClick(e) {
e.preventDefault();
- let textarea = document.createElement('textarea');
- textarea.style.position = 'fixed';
- textarea.style.opacity = '0';
- textarea.value = JSON.stringify([...this._post.notes].map(note => ({
- polygon: [...note.polygon].map(
- point => [point.x, point.y]),
- text: note.text,
- })));
+ let textarea = document.createElement("textarea");
+ textarea.style.position = "fixed";
+ textarea.style.opacity = "0";
+ textarea.value = JSON.stringify(
+ [...this._post.notes].map((note) => ({
+ polygon: [...note.polygon].map((point) => [point.x, point.y]),
+ text: note.text,
+ }))
+ );
document.body.appendChild(textarea);
textarea.select();
let success = false;
try {
- success = document.execCommand('copy');
+ success = document.execCommand("copy");
} catch (err) {
// continue regardless of error
}
textarea.blur();
document.body.removeChild(textarea);
- alert(success
- ? 'Notes copied to clipboard.'
- : 'Failed to copy the text to clipboard. Sorry.');
+ alert(
+ success
+ ? "Notes copied to clipboard."
+ : "Failed to copy the text to clipboard. Sorry."
+ );
}
_evtPasteNotesClick(e) {
e.preventDefault();
const text = window.prompt(
- 'Please enter the exported notes snapshot:');
+ "Please enter the exported notes snapshot:"
+ );
if (!text) {
return;
}
@@ -333,7 +383,7 @@ class PostEditSidebarControl extends events.EventTarget {
_evtDeleteNoteClick(e) {
e.preventDefault();
- if (e.target.classList.contains('inactive')) {
+ if (e.target.classList.contains("inactive")) {
return;
}
this._post.notes.remove(this._editedNote);
@@ -342,72 +392,78 @@ class PostEditSidebarControl extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- post: this._post,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ post: this._post,
- safety: this._safetyButtonNodes.length ?
- Array.from(this._safetyButtonNodes)
- .filter(node => node.checked)[0]
- .value.toLowerCase() :
- undefined,
+ safety: this._safetyButtonNodes.length
+ ? Array.from(this._safetyButtonNodes)
+ .filter((node) => node.checked)[0]
+ .value.toLowerCase()
+ : undefined,
- flags: this._videoFlags,
+ flags: this._videoFlags,
- tags: this._tagInputNode ?
- misc.splitByWhitespace(this._tagInputNode.value) :
- undefined,
+ tags: this._tagInputNode
+ ? misc.splitByWhitespace(this._tagInputNode.value)
+ : undefined,
- pools: this._poolInputNode ?
- misc.splitByWhitespace(this._poolInputNode.value) :
- undefined,
+ pools: this._poolInputNode
+ ? misc.splitByWhitespace(this._poolInputNode.value)
+ : undefined,
- relations: this._relationsInputNode ?
- misc.splitByWhitespace(this._relationsInputNode.value)
- .map(x => parseInt(x)) :
- undefined,
+ relations: this._relationsInputNode
+ ? misc
+ .splitByWhitespace(
+ this._relationsInputNode.value
+ )
+ .map((x) => parseInt(x))
+ : undefined,
- content: this._newPostContent ?
- this._newPostContent :
- undefined,
+ content: this._newPostContent
+ ? this._newPostContent
+ : undefined,
- thumbnail: this._newPostThumbnail !== undefined ?
- this._newPostThumbnail :
- undefined,
+ thumbnail:
+ this._newPostThumbnail !== undefined
+ ? this._newPostThumbnail
+ : undefined,
- source: this._sourceInputNode ?
- this._sourceInputNode.value :
- undefined,
- },
- }));
+ source: this._sourceInputNode
+ ? this._sourceInputNode.value
+ : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _submitButtonNode() {
- return this._hostNode.querySelector('.submit');
+ return this._hostNode.querySelector(".submit");
}
get _safetyButtonNodes() {
- return this._formNode.querySelectorAll('.safety input');
+ return this._formNode.querySelectorAll(".safety input");
}
get _tagInputNode() {
- return this._formNode.querySelector('.tags input');
+ return this._formNode.querySelector(".tags input");
}
get _poolInputNode() {
- return this._formNode.querySelector('.pools input');
+ return this._formNode.querySelector(".pools input");
}
get _loopVideoInputNode() {
- return this._formNode.querySelector('.flags input[name=loop]');
+ return this._formNode.querySelector(".flags input[name=loop]");
}
get _soundVideoInputNode() {
- return this._formNode.querySelector('.flags input[name=sound]');
+ return this._formNode.querySelector(".flags input[name=sound]");
}
get _videoFlags() {
@@ -416,65 +472,68 @@ class PostEditSidebarControl extends events.EventTarget {
}
let ret = [];
if (this._loopVideoInputNode.checked) {
- ret.push('loop');
+ ret.push("loop");
}
if (this._soundVideoInputNode.checked) {
- ret.push('sound');
+ ret.push("sound");
}
return ret;
}
get _relationsInputNode() {
- return this._formNode.querySelector('.relations input');
+ return this._formNode.querySelector(".relations input");
}
get _contentInputNode() {
- return this._formNode.querySelector('.post-content .dropper-container');
+ return this._formNode.querySelector(
+ ".post-content .dropper-container"
+ );
}
get _thumbnailInputNode() {
return this._formNode.querySelector(
- '.post-thumbnail .dropper-container');
+ ".post-thumbnail .dropper-container"
+ );
}
get _thumbnailRemovalLinkNode() {
- return this._formNode.querySelector('.post-thumbnail a');
+ return this._formNode.querySelector(".post-thumbnail a");
}
get _sourceInputNode() {
- return this._formNode.querySelector('.post-source textarea');
+ return this._formNode.querySelector(".post-source textarea");
}
get _featureLinkNode() {
- return this._formNode.querySelector('.management .feature');
+ return this._formNode.querySelector(".management .feature");
}
get _mergeLinkNode() {
- return this._formNode.querySelector('.management .merge');
+ return this._formNode.querySelector(".management .merge");
}
get _deleteLinkNode() {
- return this._formNode.querySelector('.management .delete');
+ return this._formNode.querySelector(".management .delete");
}
get _addNoteLinkNode() {
- return this._formNode.querySelector('.notes .add');
+ return this._formNode.querySelector(".notes .add");
}
get _copyNotesLinkNode() {
- return this._formNode.querySelector('.notes .copy');
+ return this._formNode.querySelector(".notes .copy");
}
get _pasteNotesLinkNode() {
- return this._formNode.querySelector('.notes .paste');
+ return this._formNode.querySelector(".notes .paste");
}
get _deleteNoteLinkNode() {
- return this._formNode.querySelector('.notes .delete');
+ return this._formNode.querySelector(".notes .delete");
}
get _noteTextareaNode() {
- return this._formNode.querySelector('.notes textarea');
+ return this._formNode.querySelector(".notes textarea");
}
enableForm() {
diff --git a/client/js/controls/post_notes_overlay_control.js b/client/js/controls/post_notes_overlay_control.js
index 7bf69b2..030f7f2 100644
--- a/client/js/controls/post_notes_overlay_control.js
+++ b/client/js/controls/post_notes_overlay_control.js
@@ -1,13 +1,13 @@
-'use strict';
+"use strict";
-const keyboard = require('../util/keyboard.js');
-const views = require('../util/views.js');
-const events = require('../events.js');
-const misc = require('../util/misc.js');
-const Note = require('../models/note.js');
-const Point = require('../models/point.js');
+const keyboard = require("../util/keyboard.js");
+const views = require("../util/views.js");
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const Note = require("../models/note.js");
+const Point = require("../models/point.js");
-const svgNS = 'http://www.w3.org/2000/svg';
+const svgNS = "http://www.w3.org/2000/svg";
const snapThreshold = 10;
const circleSize = 10;
@@ -22,19 +22,19 @@ const KEY_RETURN = 13;
function _getDistance(point1, point2) {
return Math.sqrt(
- Math.pow(point1.x - point2.x, 2) +
- Math.pow(point1.y - point2.y, 2));
+ Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)
+ );
}
function _setNodeState(node, stateName) {
if (node === null) {
return;
}
- node.setAttribute('data-state', stateName);
+ node.setAttribute("data-state", stateName);
}
function _clearEditedNote(hostNode) {
- const node = hostNode.querySelector('[data-state=\'editing\']');
+ const node = hostNode.querySelector("[data-state='editing']");
_setNodeState(node, null);
return node !== null;
}
@@ -48,7 +48,7 @@ function _getNoteCentroid(note) {
const y0 = note.polygon.at(i).y;
const x1 = note.polygon.at((i + 1) % vertexCount).x;
const y1 = note.polygon.at((i + 1) % vertexCount).y;
- const a = (x0 * y1) - (x1 * y0);
+ const a = x0 * y1 - x1 * y0;
signedArea += a;
centroid.x += (x0 + x1) * a;
centroid.y += (y0 + y1) * a;
@@ -82,32 +82,30 @@ class State {
return false;
}
- evtCanvasKeyDown(e) {
- }
+ evtCanvasKeyDown(e) {}
- evtNoteMouseDown(e, hoveredNote) {
- }
+ evtNoteMouseDown(e, hoveredNote) {}
- evtCanvasMouseDown(e) {
- }
+ evtCanvasMouseDown(e) {}
- evtCanvasMouseMove(e) {
- }
+ evtCanvasMouseMove(e) {}
- evtCanvasMouseUp(e) {
- }
+ evtCanvasMouseUp(e) {}
_getScreenPoint(point) {
return new Point(
point.x * this._control.boundingBox.width,
- point.y * this._control.boundingBox.height);
+ point.y * this._control.boundingBox.height
+ );
}
_snapPoints(targetPoint, referencePoint) {
const targetScreenPoint = this._getScreenPoint(targetPoint);
const referenceScreenPoint = this._getScreenPoint(referencePoint);
- if (_getDistance(targetScreenPoint, referenceScreenPoint) <
- snapThreshold) {
+ if (
+ _getDistance(targetScreenPoint, referenceScreenPoint) <
+ snapThreshold
+ ) {
targetPoint.x = referencePoint.x;
targetPoint.y = referencePoint.y;
}
@@ -124,15 +122,16 @@ class State {
(e.clientX - this._control.boundingBox.left) /
this._control.boundingBox.width,
(e.clientY - this._control.boundingBox.top) /
- this._control.boundingBox.height);
+ this._control.boundingBox.height
+ );
}
}
class ReadOnlyState extends State {
constructor(control) {
- super(control, 'read-only');
+ super(control, "read-only");
if (_clearEditedNote(control._hostNode)) {
- this._control.dispatchEvent(new CustomEvent('blur'));
+ this._control.dispatchEvent(new CustomEvent("blur"));
}
keyboard.unpause();
}
@@ -144,9 +143,9 @@ class ReadOnlyState extends State {
class PassiveState extends State {
constructor(control) {
- super(control, 'passive');
+ super(control, "passive");
if (_clearEditedNote(control._hostNode)) {
- this._control.dispatchEvent(new CustomEvent('blur'));
+ this._control.dispatchEvent(new CustomEvent("blur"));
}
keyboard.unpause();
}
@@ -164,23 +163,24 @@ class ActiveState extends State {
constructor(control, note, stateName) {
super(control, stateName);
if (_clearEditedNote(control._hostNode)) {
- this._control.dispatchEvent(new CustomEvent('blur'));
+ this._control.dispatchEvent(new CustomEvent("blur"));
}
keyboard.pause();
if (note !== null) {
this._note = note;
this._control.dispatchEvent(
- new CustomEvent('focus', {
- detail: {note: note},
- }));
- _setNodeState(this._note.groupNode, 'editing');
+ new CustomEvent("focus", {
+ detail: { note: note },
+ })
+ );
+ _setNodeState(this._note.groupNode, "editing");
}
}
}
class SelectedState extends ActiveState {
constructor(control, note) {
- super(control, note, 'selected');
+ super(control, note, "selected");
this._clickTimeout = null;
this._control._hideNoteText();
}
@@ -211,27 +211,40 @@ class SelectedState extends ActiveState {
const mouseScreenPoint = this._getScreenPoint(mousePoint);
if (e.shiftKey) {
this._control._state = new ScalingNoteState(
- this._control, this._note, mousePoint);
+ this._control,
+ this._note,
+ mousePoint
+ );
return;
}
if (this._note !== hoveredNote) {
- this._control._state =
- new SelectedState(this._control, hoveredNote);
+ this._control._state = new SelectedState(
+ this._control,
+ hoveredNote
+ );
return;
}
this._clickTimeout = window.setTimeout(() => {
for (let polygonPoint of this._note.polygon) {
const distance = _getDistance(
mouseScreenPoint,
- this._getScreenPoint(polygonPoint));
+ this._getScreenPoint(polygonPoint)
+ );
if (distance < circleSize) {
this._control._state = new MovingPointState(
- this._control, this._note, polygonPoint, mousePoint);
+ this._control,
+ this._note,
+ polygonPoint,
+ mousePoint
+ );
return;
}
}
this._control._state = new MovingNoteState(
- this._control, this._note, mousePoint);
+ this._control,
+ this._note,
+ mousePoint
+ );
}, 100);
}
@@ -241,9 +254,12 @@ class SelectedState extends ActiveState {
for (let polygonPoint of this._note.polygon) {
const distance = _getDistance(
mouseScreenPoint,
- this._getScreenPoint(polygonPoint));
+ this._getScreenPoint(polygonPoint)
+ );
polygonPoint.edgeNode.classList.toggle(
- 'nearby', distance < circleSize);
+ "nearby",
+ distance < circleSize
+ );
}
}
@@ -252,16 +268,24 @@ class SelectedState extends ActiveState {
const mouseScreenPoint = this._getScreenPoint(mousePoint);
if (e.shiftKey) {
this._control._state = new ScalingNoteState(
- this._control, this._note, mousePoint);
+ this._control,
+ this._note,
+ mousePoint
+ );
return;
}
for (let polygonPoint of this._note.polygon) {
const distance = _getDistance(
mouseScreenPoint,
- this._getScreenPoint(polygonPoint));
+ this._getScreenPoint(polygonPoint)
+ );
if (distance < circleSize) {
this._control._state = new MovingPointState(
- this._control, this._note, polygonPoint, mousePoint);
+ this._control,
+ this._note,
+ polygonPoint,
+ mousePoint
+ );
return;
}
}
@@ -283,32 +307,37 @@ class SelectedState extends ActiveState {
const origin = _getNoteCentroid(this._note);
const originalSize = _getNoteSize(this._note);
const targetSize = new Point(
- originalSize.x + (x / this._control.boundingBox.width),
- originalSize.y + (y / this._control.boundingBox.height));
+ originalSize.x + x / this._control.boundingBox.width,
+ originalSize.y + y / this._control.boundingBox.height
+ );
const scale = new Point(
targetSize.x / originalSize.x,
- targetSize.y / originalSize.y);
+ targetSize.y / originalSize.y
+ );
for (let point of this._note.polygon) {
- point.x = origin.x + ((point.x - origin.x) * scale.x);
- point.y = origin.y + ((point.y - origin.y) * scale.y);
+ point.x = origin.x + (point.x - origin.x) * scale.x;
+ point.y = origin.y + (point.y - origin.y) * scale.y;
}
}
}
class MovingPointState extends ActiveState {
constructor(control, note, notePoint, mousePoint) {
- super(control, note, 'moving-point');
+ super(control, note, "moving-point");
this._notePoint = notePoint;
- this._originalNotePoint = {x: notePoint.x, y: notePoint.y};
+ this._originalNotePoint = { x: notePoint.x, y: notePoint.y };
this._originalPosition = mousePoint;
- _setNodeState(this._note.groupNode, 'editing');
+ _setNodeState(this._note.groupNode, "editing");
}
evtCanvasKeyDown(e) {
if (e.which === KEY_ESCAPE) {
this._notePoint.x = this._originalNotePoint.x;
this._notePoint.y = this._originalNotePoint.y;
- this._control._state = new SelectedState(this._control, this._note);
+ this._control._state = new SelectedState(
+ this._control,
+ this._note
+ );
}
}
@@ -326,9 +355,11 @@ class MovingPointState extends ActiveState {
class MovingNoteState extends ActiveState {
constructor(control, note, mousePoint) {
- super(control, note, 'moving-note');
- this._originalPolygon = [...note.polygon].map(
- point => ({x: point.x, y: point.y}));
+ super(control, note, "moving-note");
+ this._originalPolygon = [...note.polygon].map((point) => ({
+ x: point.x,
+ y: point.y,
+ }));
this._originalPosition = mousePoint;
}
@@ -338,7 +369,10 @@ class MovingNoteState extends ActiveState {
this._note.polygon.at(i).x = this._originalPolygon[i].x;
this._note.polygon.at(i).y = this._originalPolygon[i].y;
}
- this._control._state = new SelectedState(this._control, this._note);
+ this._control._state = new SelectedState(
+ this._control,
+ this._note
+ );
}
}
@@ -358,9 +392,11 @@ class MovingNoteState extends ActiveState {
class ScalingNoteState extends ActiveState {
constructor(control, note, mousePoint) {
- super(control, note, 'scaling-note');
- this._originalPolygon = [...note.polygon].map(
- point => ({x: point.x, y: point.y}));
+ super(control, note, "scaling-note");
+ this._originalPolygon = [...note.polygon].map((point) => ({
+ x: point.x,
+ y: point.y,
+ }));
this._originalMousePoint = mousePoint;
this._originalSize = _getNoteSize(note);
}
@@ -371,7 +407,10 @@ class ScalingNoteState extends ActiveState {
this._note.polygon.at(i).x = this._originalPolygon[i].x;
this._note.polygon.at(i).y = this._originalPolygon[i].y;
}
- this._control._state = new SelectedState(this._control, this._note);
+ this._control._state = new SelectedState(
+ this._control,
+ this._note
+ );
}
}
@@ -384,12 +423,16 @@ class ScalingNoteState extends ActiveState {
const originalPolygonPoint = this._originalPolygon[i];
polygonPoint.x =
originalMousePoint.x +
- ((originalPolygonPoint.x - originalMousePoint.x) *
- (1 + ((mousePoint.x - originalMousePoint.x) / originalSize.x)));
+ (originalPolygonPoint.x - originalMousePoint.x) *
+ (1 +
+ (mousePoint.x - originalMousePoint.x) /
+ originalSize.x);
polygonPoint.y =
originalMousePoint.y +
- ((originalPolygonPoint.y - originalMousePoint.y) *
- (1 + ((mousePoint.y - originalMousePoint.y) / originalSize.y)));
+ (originalPolygonPoint.y - originalMousePoint.y) *
+ (1 +
+ (mousePoint.y - originalMousePoint.y) /
+ originalSize.y);
}
}
@@ -400,7 +443,7 @@ class ScalingNoteState extends ActiveState {
class ReadyToDrawState extends ActiveState {
constructor(control) {
- super(control, null, 'ready-to-draw');
+ super(control, null, "ready-to-draw");
}
evtNoteMouseDown(e, hoveredNote) {
@@ -411,23 +454,27 @@ class ReadyToDrawState extends ActiveState {
const mousePoint = this._getPointFromEvent(e);
if (e.shiftKey) {
this._control._state = new DrawingRectangleState(
- this._control, mousePoint);
+ this._control,
+ mousePoint
+ );
} else {
this._control._state = new DrawingPolygonState(
- this._control, mousePoint);
+ this._control,
+ mousePoint
+ );
}
}
}
class DrawingRectangleState extends ActiveState {
constructor(control, mousePoint) {
- super(control, null, 'drawing-rectangle');
+ super(control, null, "drawing-rectangle");
this._note = this._createNote();
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
- _setNodeState(this._note.groupNode, 'drawing');
+ _setNodeState(this._note.groupNode, "drawing");
}
evtCanvasMouseUp(e) {
@@ -443,7 +490,10 @@ class DrawingRectangleState extends ActiveState {
this._control._state = new ReadyToDrawState(this._control);
} else {
this._control._post.notes.add(this._note);
- this._control._state = new SelectedState(this._control, this._note);
+ this._control._state = new SelectedState(
+ this._control,
+ this._note
+ );
}
}
@@ -458,11 +508,11 @@ class DrawingRectangleState extends ActiveState {
class DrawingPolygonState extends ActiveState {
constructor(control, mousePoint) {
- super(control, null, 'drawing-polygon');
+ super(control, null, "drawing-polygon");
this._note = this._createNote();
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
this._note.polygon.add(new Point(mousePoint.x, mousePoint.y));
- _setNodeState(this._note.groupNode, 'drawing');
+ _setNodeState(this._note.groupNode, "drawing");
}
evtCanvasKeyDown(e) {
@@ -502,11 +552,16 @@ class DrawingPolygonState extends ActiveState {
}
if (e.shiftKey && secondLastPoint) {
- const direction = (Math.round(
- Math.atan2(
- secondLastPoint.y - mousePoint.y,
- secondLastPoint.x - mousePoint.x) /
- (2 * Math.PI / 4)) + 4) % 4;
+ const direction =
+ (Math.round(
+ Math.atan2(
+ secondLastPoint.y - mousePoint.y,
+ secondLastPoint.x - mousePoint.x
+ ) /
+ ((2 * Math.PI) / 4)
+ ) +
+ 4) %
+ 4;
if (direction === 0 || direction === 2) {
lastPoint.x = mousePoint.x;
lastPoint.y = secondLastPoint.y;
@@ -533,7 +588,10 @@ class DrawingPolygonState extends ActiveState {
} else {
this._control._deleteDomNode(this._note);
this._control._post.notes.add(this._note);
- this._control._state = new SelectedState(this._control, this._note);
+ this._control._state = new SelectedState(
+ this._control,
+ this._note
+ );
}
}
}
@@ -544,48 +602,51 @@ class PostNotesOverlayControl extends events.EventTarget {
this._post = post;
this._hostNode = hostNode;
- this._svgNode = document.createElementNS(svgNS, 'svg');
- this._svgNode.classList.add('resize-listener');
- this._svgNode.classList.add('notes-overlay');
- this._svgNode.setAttribute('preserveAspectRatio', 'none');
- this._svgNode.setAttribute('viewBox', '0 0 1 1');
+ this._svgNode = document.createElementNS(svgNS, "svg");
+ this._svgNode.classList.add("resize-listener");
+ this._svgNode.classList.add("notes-overlay");
+ this._svgNode.setAttribute("preserveAspectRatio", "none");
+ this._svgNode.setAttribute("viewBox", "0 0 1 1");
for (let note of this._post.notes) {
this._createPolygonNode(note);
}
this._hostNode.appendChild(this._svgNode);
- this._post.addEventListener('change', e => this._evtPostChange(e));
- this._post.notes.addEventListener('remove', e => {
+ this._post.addEventListener("change", (e) => this._evtPostChange(e));
+ this._post.notes.addEventListener("remove", (e) => {
this._deleteDomNode(e.detail.note);
});
- this._post.notes.addEventListener('add', e => {
+ this._post.notes.addEventListener("add", (e) => {
this._createPolygonNode(e.detail.note);
});
- const keyHandler = e => this._evtCanvasKeyDown(e);
- document.addEventListener('keydown', keyHandler);
- this._svgNode.addEventListener(
- 'mousedown', e => this._evtCanvasMouseDown(e));
- this._svgNode.addEventListener(
- 'mouseup', e => this._evtCanvasMouseUp(e));
- this._svgNode.addEventListener(
- 'mousemove', e => this._evtCanvasMouseMove(e));
+ const keyHandler = (e) => this._evtCanvasKeyDown(e);
+ document.addEventListener("keydown", keyHandler);
+ this._svgNode.addEventListener("mousedown", (e) =>
+ this._evtCanvasMouseDown(e)
+ );
+ this._svgNode.addEventListener("mouseup", (e) =>
+ this._evtCanvasMouseUp(e)
+ );
+ this._svgNode.addEventListener("mousemove", (e) =>
+ this._evtCanvasMouseMove(e)
+ );
- const wrapperNode = document.createElement('div');
- wrapperNode.classList.add('wrapper');
- this._textNode = document.createElement('div');
- this._textNode.classList.add('note-text');
+ const wrapperNode = document.createElement("div");
+ wrapperNode.classList.add("wrapper");
+ this._textNode = document.createElement("div");
+ this._textNode.classList.add("note-text");
this._textNode.appendChild(wrapperNode);
- this._textNode.addEventListener(
- 'mouseleave', e => this._evtNoteMouseLeave(e));
+ this._textNode.addEventListener("mouseleave", (e) =>
+ this._evtNoteMouseLeave(e)
+ );
document.body.appendChild(this._textNode);
- views.monitorNodeRemoval(
- this._hostNode, () => {
- this._hostNode.removeChild(this._svgNode);
- document.removeEventListener('keydown', keyHandler);
- document.body.removeChild(this._textNode);
- this._state = new ReadOnlyState(this);
- });
+ views.monitorNodeRemoval(this._hostNode, () => {
+ this._hostNode.removeChild(this._svgNode);
+ document.removeEventListener("keydown", keyHandler);
+ document.body.removeChild(this._textNode);
+ this._state = new ReadOnlyState(this);
+ });
this._state = new ReadOnlyState(this);
}
@@ -613,7 +674,7 @@ class PostNotesOverlayControl extends events.EventTarget {
}
_evtCanvasKeyDown(e) {
- const illegalNodeNames = ['textarea', 'input', 'select'];
+ const illegalNodeNames = ["textarea", "input", "select"];
if (illegalNodeNames.includes(e.target.nodeName.toLowerCase())) {
return;
}
@@ -655,53 +716,58 @@ class PostNotesOverlayControl extends events.EventTarget {
_evtNoteMouseLeave(e) {
const newElement = e.relatedTarget;
- if (newElement === this._svgNode ||
- (!this._svgNode.contains(newElement) &&
+ if (
+ newElement === this._svgNode ||
+ (!this._svgNode.contains(newElement) &&
!this._textNode.contains(newElement) &&
- newElement !== this._textNode)) {
+ newElement !== this._textNode)
+ ) {
this._hideNoteText();
}
}
_showNoteText(note) {
- this._textNode.querySelector('.wrapper').innerHTML =
- misc.formatMarkdown(note.text);
- this._textNode.style.display = 'block';
+ this._textNode.querySelector(
+ ".wrapper"
+ ).innerHTML = misc.formatMarkdown(note.text);
+ this._textNode.style.display = "block";
const bodyRect = document.body.getBoundingClientRect();
const noteRect = this._textNode.getBoundingClientRect();
const svgRect = this.boundingBox;
const centroid = _getNoteCentroid(note);
- const x = (
+ const x =
-bodyRect.left +
svgRect.left +
- (svgRect.width * centroid.x) -
- (noteRect.width / 2));
- const y = (
+ svgRect.width * centroid.x -
+ noteRect.width / 2;
+ const y =
-bodyRect.top +
svgRect.top +
- (svgRect.height * centroid.y) -
- (noteRect.height / 2));
- this._textNode.style.left = x + 'px';
- this._textNode.style.top = y + 'px';
+ svgRect.height * centroid.y -
+ noteRect.height / 2;
+ this._textNode.style.left = x + "px";
+ this._textNode.style.top = y + "px";
}
_hideNoteText() {
- this._textNode.style.display = 'none';
+ this._textNode.style.display = "none";
}
_updatePolygonNotePoints(note) {
note.polygonNode.setAttribute(
- 'points',
- [...note.polygon].map(
- point => [point.x, point.y].join(',')).join(' '));
+ "points",
+ [...note.polygon]
+ .map((point) => [point.x, point.y].join(","))
+ .join(" ")
+ );
}
_createEdgeNode(point, groupNode) {
- const node = document.createElementNS(svgNS, 'ellipse');
- node.setAttribute('cx', point.x);
- node.setAttribute('cy', point.y);
- node.setAttribute('rx', circleSize / 2 / this.boundingBox.width);
- node.setAttribute('ry', circleSize / 2 / this.boundingBox.height);
+ const node = document.createElementNS(svgNS, "ellipse");
+ node.setAttribute("cx", point.x);
+ node.setAttribute("cy", point.y);
+ node.setAttribute("rx", circleSize / 2 / this.boundingBox.width);
+ node.setAttribute("ry", circleSize / 2 / this.boundingBox.height);
point.edgeNode = node;
groupNode.appendChild(node);
}
@@ -713,8 +779,8 @@ class PostNotesOverlayControl extends events.EventTarget {
_updateEdgeNode(point, note) {
this._updatePolygonNotePoints(note);
- point.edgeNode.setAttribute('cx', point.x);
- point.edgeNode.setAttribute('cy', point.y);
+ point.edgeNode.setAttribute("cx", point.x);
+ point.edgeNode.setAttribute("cy", point.y);
}
_deleteDomNode(note) {
@@ -722,17 +788,19 @@ class PostNotesOverlayControl extends events.EventTarget {
}
_createPolygonNode(note) {
- const groupNode = document.createElementNS(svgNS, 'g');
+ const groupNode = document.createElementNS(svgNS, "g");
note.groupNode = groupNode;
{
- const node = document.createElementNS(svgNS, 'polygon');
+ const node = document.createElementNS(svgNS, "polygon");
note.polygonNode = node;
- node.setAttribute('vector-effect', 'non-scaling-stroke');
- node.setAttribute('stroke-alignment', 'inside');
- node.addEventListener(
- 'mouseenter', e => this._evtNoteMouseEnter(e, note));
- node.addEventListener(
- 'mouseleave', e => this._evtNoteMouseLeave(e));
+ node.setAttribute("vector-effect", "non-scaling-stroke");
+ node.setAttribute("stroke-alignment", "inside");
+ node.addEventListener("mouseenter", (e) =>
+ this._evtNoteMouseEnter(e, note)
+ );
+ node.addEventListener("mouseleave", (e) =>
+ this._evtNoteMouseLeave(e)
+ );
this._updatePolygonNotePoints(note);
groupNode.appendChild(node);
}
@@ -740,17 +808,17 @@ class PostNotesOverlayControl extends events.EventTarget {
this._createEdgeNode(point, groupNode);
}
- note.polygon.addEventListener('change', e => {
+ note.polygon.addEventListener("change", (e) => {
this._updateEdgeNode(e.detail.point, note);
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(new CustomEvent("change"));
});
- note.polygon.addEventListener('remove', e => {
+ note.polygon.addEventListener("remove", (e) => {
this._deleteEdgeNode(e.detail.point, note);
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(new CustomEvent("change"));
});
- note.polygon.addEventListener('add', e => {
+ note.polygon.addEventListener("add", (e) => {
this._createEdgeNode(e.detail.point, groupNode);
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(new CustomEvent("change"));
});
this._svgNode.appendChild(groupNode);
diff --git a/client/js/controls/post_readonly_sidebar_control.js b/client/js/controls/post_readonly_sidebar_control.js
index 388c238..580ef43 100644
--- a/client/js/controls/post_readonly_sidebar_control.js
+++ b/client/js/controls/post_readonly_sidebar_control.js
@@ -1,14 +1,14 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const events = require('../events.js');
-const views = require('../util/views.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
+const api = require("../api.js");
+const events = require("../events.js");
+const views = require("../util/views.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
-const template = views.getTemplate('post-readonly-sidebar');
-const scoreTemplate = views.getTemplate('score');
-const favTemplate = views.getTemplate('fav');
+const template = views.getTemplate("post-readonly-sidebar");
+const scoreTemplate = views.getTemplate("score");
+const favTemplate = views.getTemplate("fav");
class PostReadonlySidebarControl extends events.EventTarget {
constructor(hostNode, post, postContentControl) {
@@ -17,19 +17,22 @@ class PostReadonlySidebarControl extends events.EventTarget {
this._post = post;
this._postContentControl = postContentControl;
- post.addEventListener('changeFavorite', e => this._evtChangeFav(e));
- post.addEventListener('changeScore', e => this._evtChangeScore(e));
+ post.addEventListener("changeFavorite", (e) => this._evtChangeFav(e));
+ post.addEventListener("changeScore", (e) => this._evtChangeScore(e));
- views.replaceContent(this._hostNode, template({
- post: this._post,
- enableSafety: api.safetyEnabled(),
- canListPosts: api.hasPrivilege('posts:list'),
- canEditPosts: api.hasPrivilege('posts:edit'),
- canViewTags: api.hasPrivilege('tags:view'),
- escapeColons: uri.escapeColons,
- extractRootDomain: uri.extractRootDomain,
- getPrettyTagName: misc.getPrettyTagName,
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ post: this._post,
+ enableSafety: api.safetyEnabled(),
+ canListPosts: api.hasPrivilege("posts:list"),
+ canEditPosts: api.hasPrivilege("posts:edit"),
+ canViewTags: api.hasPrivilege("tags:view"),
+ escapeColons: uri.escapeColons,
+ extractRootDomain: uri.extractRootDomain,
+ getPrettyTagName: misc.getPrettyTagName,
+ })
+ );
this._installFav();
this._installScore();
@@ -38,58 +41,62 @@ class PostReadonlySidebarControl extends events.EventTarget {
}
get _scoreContainerNode() {
- return this._hostNode.querySelector('.score-container');
+ return this._hostNode.querySelector(".score-container");
}
get _favContainerNode() {
- return this._hostNode.querySelector('.fav-container');
+ return this._hostNode.querySelector(".fav-container");
}
get _upvoteButtonNode() {
- return this._hostNode.querySelector('.upvote');
+ return this._hostNode.querySelector(".upvote");
}
get _downvoteButtonNode() {
- return this._hostNode.querySelector('.downvote');
+ return this._hostNode.querySelector(".downvote");
}
get _addFavButtonNode() {
- return this._hostNode.querySelector('.add-favorite');
+ return this._hostNode.querySelector(".add-favorite");
}
get _remFavButtonNode() {
- return this._hostNode.querySelector('.remove-favorite');
+ return this._hostNode.querySelector(".remove-favorite");
}
get _fitBothButtonNode() {
- return this._hostNode.querySelector('.fit-both');
+ return this._hostNode.querySelector(".fit-both");
}
get _fitOriginalButtonNode() {
- return this._hostNode.querySelector('.fit-original');
+ return this._hostNode.querySelector(".fit-original");
}
get _fitWidthButtonNode() {
- return this._hostNode.querySelector('.fit-width');
+ return this._hostNode.querySelector(".fit-width");
}
get _fitHeightButtonNode() {
- return this._hostNode.querySelector('.fit-height');
+ return this._hostNode.querySelector(".fit-height");
}
_installFitButtons() {
this._fitBothButtonNode.addEventListener(
- 'click', this._eventZoomProxy(
- () => this._postContentControl.fitBoth()));
+ "click",
+ this._eventZoomProxy(() => this._postContentControl.fitBoth())
+ );
this._fitOriginalButtonNode.addEventListener(
- 'click', this._eventZoomProxy(
- () => this._postContentControl.fitOriginal()));
+ "click",
+ this._eventZoomProxy(() => this._postContentControl.fitOriginal())
+ );
this._fitWidthButtonNode.addEventListener(
- 'click', this._eventZoomProxy(
- () => this._postContentControl.fitWidth()));
+ "click",
+ this._eventZoomProxy(() => this._postContentControl.fitWidth())
+ );
this._fitHeightButtonNode.addEventListener(
- 'click', this._eventZoomProxy(
- () => this._postContentControl.fitHeight()));
+ "click",
+ this._eventZoomProxy(() => this._postContentControl.fitHeight())
+ );
}
_installFav() {
@@ -98,16 +105,19 @@ class PostReadonlySidebarControl extends events.EventTarget {
favTemplate({
favoriteCount: this._post.favoriteCount,
ownFavorite: this._post.ownFavorite,
- canFavorite: api.hasPrivilege('posts:favorite'),
- }));
+ canFavorite: api.hasPrivilege("posts:favorite"),
+ })
+ );
if (this._addFavButtonNode) {
- this._addFavButtonNode.addEventListener(
- 'click', e => this._evtAddToFavoritesClick(e));
+ this._addFavButtonNode.addEventListener("click", (e) =>
+ this._evtAddToFavoritesClick(e)
+ );
}
if (this._remFavButtonNode) {
- this._remFavButtonNode.addEventListener(
- 'click', e => this._evtRemoveFromFavoritesClick(e));
+ this._remFavButtonNode.addEventListener("click", (e) =>
+ this._evtRemoveFromFavoritesClick(e)
+ );
}
}
@@ -117,77 +127,88 @@ class PostReadonlySidebarControl extends events.EventTarget {
scoreTemplate({
score: this._post.score,
ownScore: this._post.ownScore,
- canScore: api.hasPrivilege('posts:score'),
- }));
+ canScore: api.hasPrivilege("posts:score"),
+ })
+ );
if (this._upvoteButtonNode) {
- this._upvoteButtonNode.addEventListener(
- 'click', e => this._evtScoreClick(e, 1));
+ this._upvoteButtonNode.addEventListener("click", (e) =>
+ this._evtScoreClick(e, 1)
+ );
}
if (this._downvoteButtonNode) {
- this._downvoteButtonNode.addEventListener(
- 'click', e => this._evtScoreClick(e, -1));
+ this._downvoteButtonNode.addEventListener("click", (e) =>
+ this._evtScoreClick(e, -1)
+ );
}
}
_eventZoomProxy(func) {
- return e => {
+ return (e) => {
e.preventDefault();
e.target.blur();
func();
this._syncFitButton();
- this.dispatchEvent(new CustomEvent('fitModeChange', {
- detail: {
- mode: this._getFitMode(),
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("fitModeChange", {
+ detail: {
+ mode: this._getFitMode(),
+ },
+ })
+ );
};
}
_getFitMode() {
const funcToName = {};
- funcToName[this._postContentControl.fitBoth] = 'fit-both';
- funcToName[this._postContentControl.fitOriginal] = 'fit-original';
- funcToName[this._postContentControl.fitWidth] = 'fit-width';
- funcToName[this._postContentControl.fitHeight] = 'fit-height';
+ funcToName[this._postContentControl.fitBoth] = "fit-both";
+ funcToName[this._postContentControl.fitOriginal] = "fit-original";
+ funcToName[this._postContentControl.fitWidth] = "fit-width";
+ funcToName[this._postContentControl.fitHeight] = "fit-height";
return funcToName[this._postContentControl._currentFitFunction];
}
_syncFitButton() {
const className = this._getFitMode();
- const oldNode = this._hostNode.querySelector('.zoom a.active');
+ const oldNode = this._hostNode.querySelector(".zoom a.active");
const newNode = this._hostNode.querySelector(`.zoom a.${className}`);
if (oldNode) {
- oldNode.classList.remove('active');
+ oldNode.classList.remove("active");
}
- newNode.classList.add('active');
+ newNode.classList.add("active");
}
_evtAddToFavoritesClick(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('favorite', {
- detail: {
- post: this._post,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("favorite", {
+ detail: {
+ post: this._post,
+ },
+ })
+ );
}
_evtRemoveFromFavoritesClick(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('unfavorite', {
- detail: {
- post: this._post,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("unfavorite", {
+ detail: {
+ post: this._post,
+ },
+ })
+ );
}
_evtScoreClick(e, score) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('score', {
- detail: {
- post: this._post,
- score: this._post.ownScore === score ? 0 : score,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("score", {
+ detail: {
+ post: this._post,
+ score: this._post.ownScore === score ? 0 : score,
+ },
+ })
+ );
}
_evtChangeFav(e) {
diff --git a/client/js/controls/tag_auto_complete_control.js b/client/js/controls/tag_auto_complete_control.js
index f8d3f6c..8ee6aa8 100644
--- a/client/js/controls/tag_auto_complete_control.js
+++ b/client/js/controls/tag_auto_complete_control.js
@@ -1,51 +1,63 @@
-'use strict';
+"use strict";
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const TagList = require('../models/tag_list.js');
-const AutoCompleteControl = require('./auto_complete_control.js');
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const TagList = require("../models/tag_list.js");
+const AutoCompleteControl = require("./auto_complete_control.js");
function _tagListToMatches(tags, options) {
- return [...tags].sort((tag1, tag2) => {
- return tag2.usages - tag1.usages;
- }).map(tag => {
- let cssName = misc.makeCssName(tag.category, 'tag');
- if (options.isTaggedWith(tag.names[0])) {
- cssName += ' disabled';
- }
- const caption = (
- '<span class="' + cssName + '">'
- + misc.escapeHtml(tag.names[0] + ' (' + tag.postCount + ')')
- + '</span>');
- return {
- caption: caption,
- value: tag,
- };
- });
+ return [...tags]
+ .sort((tag1, tag2) => {
+ return tag2.usages - tag1.usages;
+ })
+ .map((tag) => {
+ let cssName = misc.makeCssName(tag.category, "tag");
+ if (options.isTaggedWith(tag.names[0])) {
+ cssName += " disabled";
+ }
+ const caption =
+ '<span class="' +
+ cssName +
+ '">' +
+ misc.escapeHtml(tag.names[0] + " (" + tag.postCount + ")") +
+ "</span>";
+ return {
+ caption: caption,
+ value: tag,
+ };
+ });
}
class TagAutoCompleteControl extends AutoCompleteControl {
constructor(input, options) {
const minLengthForPartialSearch = 3;
- options = Object.assign({
- isTaggedWith: tag => false,
- }, options);
+ options = Object.assign(
+ {
+ isTaggedWith: (tag) => false,
+ },
+ options
+ );
- options.getMatches = text => {
+ options.getMatches = (text) => {
const term = misc.escapeSearchTerm(text);
- const query = (
- text.length < minLengthForPartialSearch
- ? term + '*'
- : '*' + term + '*') + ' sort:usages';
+ const query =
+ (text.length < minLengthForPartialSearch
+ ? term + "*"
+ : "*" + term + "*") + " sort:usages";
return new Promise((resolve, reject) => {
- TagList.search(
- query, 0, this._options.maxResults, ['names', 'category', 'usages'])
- .then(
- response => resolve(
- _tagListToMatches(response.results, this._options)),
- reject);
+ TagList.search(query, 0, this._options.maxResults, [
+ "names",
+ "category",
+ "usages",
+ ]).then(
+ (response) =>
+ resolve(
+ _tagListToMatches(response.results, this._options)
+ ),
+ reject
+ );
});
};
diff --git a/client/js/controls/tag_input_control.js b/client/js/controls/tag_input_control.js
index e0b1339..7d069f9 100644
--- a/client/js/controls/tag_input_control.js
+++ b/client/js/controls/tag_input_control.js
@@ -1,25 +1,25 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const tags = require('../tags.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const Tag = require('../models/tag.js');
-const settings = require('../models/settings.js');
-const events = require('../events.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl = require('./tag_auto_complete_control.js');
+const api = require("../api.js");
+const tags = require("../tags.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const Tag = require("../models/tag.js");
+const settings = require("../models/settings.js");
+const events = require("../events.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("./tag_auto_complete_control.js");
const KEY_SPACE = 32;
const KEY_RETURN = 13;
-const SOURCE_INIT = 'init';
-const SOURCE_IMPLICATION = 'implication';
-const SOURCE_USER_INPUT = 'user-input';
-const SOURCE_SUGGESTION = 'suggestions';
-const SOURCE_CLIPBOARD = 'clipboard';
+const SOURCE_INIT = "init";
+const SOURCE_IMPLICATION = "implication";
+const SOURCE_USER_INPUT = "user-input";
+const SOURCE_SUGGESTION = "suggestions";
+const SOURCE_CLIPBOARD = "clipboard";
-const template = views.getTemplate('tag-input');
+const template = views.getTemplate("tag-input");
function _fadeOutListItemNodeStatus(listItemNode) {
if (listItemNode.classList.length) {
@@ -28,8 +28,7 @@ function _fadeOutListItemNodeStatus(listItemNode) {
}
listItemNode.fadeTimeout = window.setTimeout(() => {
while (listItemNode.classList.length) {
- listItemNode.classList.remove(
- listItemNode.classList.item(0));
+ listItemNode.classList.remove(listItemNode.classList.item(0));
}
listItemNode.fadeTimeout = null;
}, 2500);
@@ -51,7 +50,9 @@ class SuggestionList {
}
set(suggestion, weight) {
- if (Object.prototype.hasOwnProperty.call(this._suggestions, suggestion)) {
+ if (
+ Object.prototype.hasOwnProperty.call(this._suggestions, suggestion)
+ ) {
weight = Math.max(weight, this._suggestions[suggestion]);
}
this._suggestions[suggestion] = weight;
@@ -74,8 +75,8 @@ class SuggestionList {
let nameDiff = a[0].localeCompare(b[0]);
return weightDiff === 0 ? nameDiff : weightDiff;
});
- return tuples.map(tuple => {
- return {tagName: tuple[0], weight: tuple[1]};
+ return tuples.map((tuple) => {
+ return { tagName: tuple[0], weight: tuple[1] };
});
}
}
@@ -91,45 +92,58 @@ class TagInputControl extends events.EventTarget {
// dom
const editAreaNode = template();
this._editAreaNode = editAreaNode;
- this._tagInputNode = editAreaNode.querySelector('input');
- this._suggestionsNode = editAreaNode.querySelector('.tag-suggestions');
- this._tagListNode = editAreaNode.querySelector('ul.compact-tags');
+ this._tagInputNode = editAreaNode.querySelector("input");
+ this._suggestionsNode = editAreaNode.querySelector(".tag-suggestions");
+ this._tagListNode = editAreaNode.querySelector("ul.compact-tags");
this._autoCompleteControl = new TagAutoCompleteControl(
- this._tagInputNode, {
+ this._tagInputNode,
+ {
getTextToFind: () => {
return this._tagInputNode.value;
},
- confirm: tag => {
- this._tagInputNode.value = '';
+ confirm: (tag) => {
+ this._tagInputNode.value = "";
// note: tags from autocomplete don't contain implications
// so they need to be looked up in API
this.addTagByName(tag.names[0], SOURCE_USER_INPUT);
},
- delete: tag => {
- this._tagInputNode.value = '';
+ delete: (tag) => {
+ this._tagInputNode.value = "";
this.deleteTag(tag);
},
verticalShift: -2,
- isTaggedWith: tagName => this.tags.isTaggedWith(tagName),
- });
+ isTaggedWith: (tagName) => this.tags.isTaggedWith(tagName),
+ }
+ );
// dom events
- this._tagInputNode.addEventListener(
- 'keydown', e => this._evtInputKeyDown(e));
- this._tagInputNode.addEventListener(
- 'paste', e => this._evtInputPaste(e));
- this._editAreaNode.querySelector('a.opacity').addEventListener(
- 'click', e => this._evtToggleSuggestionsPopupOpacityClick(e));
- this._editAreaNode.querySelector('a.close').addEventListener(
- 'click', e => this._evtCloseSuggestionsPopupClick(e));
- this._editAreaNode.querySelector('button').addEventListener(
- 'click', e => this._evtAddTagButtonClick(e));
+ this._tagInputNode.addEventListener("keydown", (e) =>
+ this._evtInputKeyDown(e)
+ );
+ this._tagInputNode.addEventListener("paste", (e) =>
+ this._evtInputPaste(e)
+ );
+ this._editAreaNode
+ .querySelector("a.opacity")
+ .addEventListener("click", (e) =>
+ this._evtToggleSuggestionsPopupOpacityClick(e)
+ );
+ this._editAreaNode
+ .querySelector("a.close")
+ .addEventListener("click", (e) =>
+ this._evtCloseSuggestionsPopupClick(e)
+ );
+ this._editAreaNode
+ .querySelector("button")
+ .addEventListener("click", (e) => this._evtAddTagButtonClick(e));
// show
- this._hostNode.style.display = 'none';
+ this._hostNode.style.display = "none";
this._hostNode.parentNode.insertBefore(
- this._editAreaNode, hostNode.nextSibling);
+ this._editAreaNode,
+ hostNode.nextSibling
+ );
// add existing tags
for (let tag of [...this.tags]) {
@@ -139,7 +153,10 @@ class TagInputControl extends events.EventTarget {
}
addTagByText(text, source) {
- for (let tagName of text.split(/\s+/).filter(word => word).reverse()) {
+ for (let tagName of text
+ .split(/\s+/)
+ .filter((word) => word)
+ .reverse()) {
this.addTagByName(tagName, source);
}
}
@@ -149,48 +166,60 @@ class TagInputControl extends events.EventTarget {
if (!name) {
return;
}
- return Tag.get(name).then(tag => {
- return this.addTag(tag, source);
- }, () => {
- const tag = new Tag();
- tag.names = [name];
- tag.category = null;
- return this.addTag(tag, source);
- });
+ return Tag.get(name).then(
+ (tag) => {
+ return this.addTag(tag, source);
+ },
+ () => {
+ const tag = new Tag();
+ tag.names = [name];
+ tag.category = null;
+ return this.addTag(tag, source);
+ }
+ );
}
addTag(tag, source) {
if (source !== SOURCE_INIT && this.tags.isTaggedWith(tag.names[0])) {
const listItemNode = this._getListItemNode(tag);
if (source !== SOURCE_IMPLICATION) {
- listItemNode.classList.add('duplicate');
+ listItemNode.classList.add("duplicate");
_fadeOutListItemNodeStatus(listItemNode);
}
return Promise.resolve();
}
- return this.tags.addByName(tag.names[0], false).then(() => {
- const listItemNode = this._createListItemNode(tag);
- if (!tag.category) {
- listItemNode.classList.add('new');
- }
- if (source === SOURCE_IMPLICATION) {
- listItemNode.classList.add('implication');
- }
- this._tagListNode.prependChild(listItemNode);
- _fadeOutListItemNodeStatus(listItemNode);
+ return this.tags
+ .addByName(tag.names[0], false)
+ .then(() => {
+ const listItemNode = this._createListItemNode(tag);
+ if (!tag.category) {
+ listItemNode.classList.add("new");
+ }
+ if (source === SOURCE_IMPLICATION) {
+ listItemNode.classList.add("implication");
+ }
+ this._tagListNode.prependChild(listItemNode);
+ _fadeOutListItemNodeStatus(listItemNode);
- return Promise.all(
- tag.implications.map(
- implication => this.addTagByName(
- implication.names[0], SOURCE_IMPLICATION)));
- }).then(() => {
- this.dispatchEvent(new CustomEvent('add', {
- detail: {tag: tag, source: source},
- }));
- this.dispatchEvent(new CustomEvent('change'));
- return Promise.resolve();
- });
+ return Promise.all(
+ tag.implications.map((implication) =>
+ this.addTagByName(
+ implication.names[0],
+ SOURCE_IMPLICATION
+ )
+ )
+ );
+ })
+ .then(() => {
+ this.dispatchEvent(
+ new CustomEvent("add", {
+ detail: { tag: tag, source: source },
+ })
+ );
+ this.dispatchEvent(new CustomEvent("change"));
+ return Promise.resolve();
+ });
}
deleteTag(tag) {
@@ -202,25 +231,27 @@ class TagInputControl extends events.EventTarget {
this._deleteListItemNode(tag);
- this.dispatchEvent(new CustomEvent('remove', {
- detail: {tag: tag},
- }));
- this.dispatchEvent(new CustomEvent('change'));
+ this.dispatchEvent(
+ new CustomEvent("remove", {
+ detail: { tag: tag },
+ })
+ );
+ this.dispatchEvent(new CustomEvent("change"));
}
_evtInputPaste(e) {
e.preventDefault();
- const pastedText = window.clipboardData ?
- window.clipboardData.getData('Text') :
- (e.originalEvent || e).clipboardData.getData('text/plain');
+ const pastedText = window.clipboardData
+ ? window.clipboardData.getData("Text")
+ : (e.originalEvent || e).clipboardData.getData("text/plain");
if (pastedText.length > 2000) {
- window.alert('Pasted text is too long.');
+ window.alert("Pasted text is too long.");
return;
}
this._hideAutoComplete();
this.addTagByText(pastedText, SOURCE_CLIPBOARD);
- this._tagInputNode.value = '';
+ this._tagInputNode.value = "";
}
_evtCloseSuggestionsPopupClick(e) {
@@ -231,7 +262,7 @@ class TagInputControl extends events.EventTarget {
_evtAddTagButtonClick(e) {
e.preventDefault();
this.addTagByName(this._tagInputNode.value, SOURCE_USER_INPUT);
- this._tagInputNode.value = '';
+ this._tagInputNode.value = "";
}
_evtToggleSuggestionsPopupOpacityClick(e) {
@@ -244,36 +275,41 @@ class TagInputControl extends events.EventTarget {
e.preventDefault();
this._hideAutoComplete();
this.addTagByText(this._tagInputNode.value, SOURCE_USER_INPUT);
- this._tagInputNode.value = '';
+ this._tagInputNode.value = "";
}
}
_createListItemNode(tag) {
- const className = tag.category ?
- misc.makeCssName(tag.category, 'tag') :
- null;
+ const className = tag.category
+ ? misc.makeCssName(tag.category, "tag")
+ : null;
- const tagLinkNode = document.createElement('a');
+ const tagLinkNode = document.createElement("a");
if (className) {
tagLinkNode.classList.add(className);
}
tagLinkNode.setAttribute(
- 'href', uri.formatClientLink('tag', tag.names[0]));
+ "href",
+ uri.formatClientLink("tag", tag.names[0])
+ );
- const tagIconNode = document.createElement('i');
- tagIconNode.classList.add('fa');
- tagIconNode.classList.add('fa-tag');
+ const tagIconNode = document.createElement("i");
+ tagIconNode.classList.add("fa");
+ tagIconNode.classList.add("fa-tag");
tagLinkNode.appendChild(tagIconNode);
- const searchLinkNode = document.createElement('a');
+ const searchLinkNode = document.createElement("a");
if (className) {
searchLinkNode.classList.add(className);
}
searchLinkNode.setAttribute(
- 'href', uri.formatClientLink(
- 'posts', {query: uri.escapeColons(tag.names[0])}));
- searchLinkNode.textContent = tag.names[0] + ' ';
- searchLinkNode.addEventListener('click', e => {
+ "href",
+ uri.formatClientLink("posts", {
+ query: uri.escapeColons(tag.names[0]),
+ })
+ );
+ searchLinkNode.textContent = tag.names[0] + " ";
+ searchLinkNode.addEventListener("click", (e) => {
e.preventDefault();
this._suggestions.clear();
if (tag.postCount > 0) {
@@ -284,20 +320,20 @@ class TagInputControl extends events.EventTarget {
}
});
- const usagesNode = document.createElement('span');
- usagesNode.classList.add('tag-usages');
- usagesNode.setAttribute('data-pseudo-content', tag.postCount);
+ const usagesNode = document.createElement("span");
+ usagesNode.classList.add("tag-usages");
+ usagesNode.setAttribute("data-pseudo-content", tag.postCount);
- const removalLinkNode = document.createElement('a');
- removalLinkNode.classList.add('remove-tag');
- removalLinkNode.setAttribute('href', '');
- removalLinkNode.setAttribute('data-pseudo-content', '×');
- removalLinkNode.addEventListener('click', e => {
+ const removalLinkNode = document.createElement("a");
+ removalLinkNode.classList.add("remove-tag");
+ removalLinkNode.setAttribute("href", "");
+ removalLinkNode.setAttribute("data-pseudo-content", "×");
+ removalLinkNode.addEventListener("click", (e) => {
e.preventDefault();
this.deleteTag(tag);
});
- const listItemNode = document.createElement('li');
+ const listItemNode = document.createElement("li");
listItemNode.appendChild(removalLinkNode);
listItemNode.appendChild(tagLinkNode);
listItemNode.appendChild(searchLinkNode);
@@ -327,20 +363,25 @@ class TagInputControl extends events.EventTarget {
if (!browsingSettings.tagSuggestions) {
return;
}
- api.get(
- uri.formatApiLink('tag-siblings', tag.names[0]),
- {noProgress: true})
- .then(response => {
- return Promise.resolve(response.results);
- }, response => {
- return Promise.resolve([]);
- }).then(siblings => {
- const args = siblings.map(s => s.occurrences);
+ api.get(uri.formatApiLink("tag-siblings", tag.names[0]), {
+ noProgress: true,
+ })
+ .then(
+ (response) => {
+ return Promise.resolve(response.results);
+ },
+ (response) => {
+ return Promise.resolve([]);
+ }
+ )
+ .then((siblings) => {
+ const args = siblings.map((s) => s.occurrences);
let maxSiblingOccurrences = Math.max(1, ...args);
for (let sibling of siblings) {
this._suggestions.set(
sibling.tag.names[0],
- sibling.occurrences * 4.9 / maxSiblingOccurrences);
+ (sibling.occurrences * 4.9) / maxSiblingOccurrences
+ );
}
for (let suggestion of tag.suggestions || []) {
this._suggestions.set(suggestion, 5);
@@ -354,10 +395,10 @@ class TagInputControl extends events.EventTarget {
}
_refreshSuggestionsPopup() {
- if (!this._suggestionsNode.classList.contains('shown')) {
+ if (!this._suggestionsNode.classList.contains("shown")) {
return;
}
- const listNode = this._suggestionsNode.querySelector('ul');
+ const listNode = this._suggestionsNode.querySelector("ul");
listNode.scrollTop = 0;
while (listNode.firstChild) {
listNode.removeChild(listNode.firstChild);
@@ -369,35 +410,36 @@ class TagInputControl extends events.EventTarget {
continue;
}
- const addLinkNode = document.createElement('a');
+ const addLinkNode = document.createElement("a");
addLinkNode.textContent = tagName;
- addLinkNode.classList.add('add-tag');
- addLinkNode.setAttribute('href', '');
- Tag.get(tagName).then(tag => {
+ addLinkNode.classList.add("add-tag");
+ addLinkNode.setAttribute("href", "");
+ Tag.get(tagName).then((tag) => {
addLinkNode.classList.add(
- misc.makeCssName(tag.category, 'tag'));
+ misc.makeCssName(tag.category, "tag")
+ );
});
- addLinkNode.addEventListener('click', e => {
+ addLinkNode.addEventListener("click", (e) => {
e.preventDefault();
listNode.removeChild(listItemNode);
this.addTagByName(tagName, SOURCE_SUGGESTION);
});
- const weightNode = document.createElement('span');
- weightNode.classList.add('tag-weight');
- weightNode.setAttribute('data-pseudo-content', weight);
+ const weightNode = document.createElement("span");
+ weightNode.classList.add("tag-weight");
+ weightNode.setAttribute("data-pseudo-content", weight);
- const removalLinkNode = document.createElement('a');
- removalLinkNode.classList.add('remove-tag');
- removalLinkNode.setAttribute('href', '');
- removalLinkNode.setAttribute('data-pseudo-content', '×');
- removalLinkNode.addEventListener('click', e => {
+ const removalLinkNode = document.createElement("a");
+ removalLinkNode.classList.add("remove-tag");
+ removalLinkNode.setAttribute("href", "");
+ removalLinkNode.setAttribute("data-pseudo-content", "×");
+ removalLinkNode.addEventListener("click", (e) => {
e.preventDefault();
listNode.removeChild(listItemNode);
this._suggestions.ban(tagName);
});
- const listItemNode = document.createElement('li');
+ const listItemNode = document.createElement("li");
listItemNode.appendChild(removalLinkNode);
listItemNode.appendChild(weightNode);
listItemNode.appendChild(addLinkNode);
@@ -407,19 +449,19 @@ class TagInputControl extends events.EventTarget {
_closeSuggestionsPopup() {
this._suggestions.clear();
- this._suggestionsNode.classList.remove('shown');
+ this._suggestionsNode.classList.remove("shown");
}
_removeSuggestionsPopupOpacity() {
- this._suggestionsNode.classList.remove('translucent');
+ this._suggestionsNode.classList.remove("translucent");
}
_toggleSuggestionsPopupOpacity() {
- this._suggestionsNode.classList.toggle('translucent');
+ this._suggestionsNode.classList.toggle("translucent");
}
_openSuggestionsPopup() {
- this._suggestionsNode.classList.add('shown');
+ this._suggestionsNode.classList.add("shown");
this._refreshSuggestionsPopup();
}