aboutsummaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/.eslintrc.yml283
-rw-r--r--client/.prettierrc.yml4
-rw-r--r--client/js/api.js250
-rw-r--r--client/js/config.js4
-rw-r--r--client/js/controllers/auth_controller.js42
-rw-r--r--client/js/controllers/base_post_controller.js16
-rw-r--r--client/js/controllers/comments_controller.js75
-rw-r--r--client/js/controllers/help_controller.js18
-rw-r--r--client/js/controllers/home_controller.js31
-rw-r--r--client/js/controllers/not_found_controller.js14
-rw-r--r--client/js/controllers/page_controller.js8
-rw-r--r--client/js/controllers/password_reset_controller.js68
-rw-r--r--client/js/controllers/pool_categories_controller.js78
-rw-r--r--client/js/controllers/pool_controller.js183
-rw-r--r--client/js/controllers/pool_create_controller.js75
-rw-r--r--client/js/controllers/pool_list_controller.js99
-rw-r--r--client/js/controllers/post_detail_controller.js115
-rw-r--r--client/js/controllers/post_list_controller.js110
-rw-r--r--client/js/controllers/post_main_controller.js304
-rw-r--r--client/js/controllers/post_upload_controller.js190
-rw-r--r--client/js/controllers/settings_controller.js20
-rw-r--r--client/js/controllers/snapshots_controller.js51
-rw-r--r--client/js/controllers/tag_categories_controller.js76
-rw-r--r--client/js/controllers/tag_controller.js180
-rw-r--r--client/js/controllers/tag_list_controller.js76
-rw-r--r--client/js/controllers/top_navigation_controller.js63
-rw-r--r--client/js/controllers/user_controller.js356
-rw-r--r--client/js/controllers/user_list_controller.js63
-rw-r--r--client/js/controllers/user_registration_controller.js73
-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
-rw-r--r--client/js/events.js24
-rw-r--r--client/js/main.js163
-rw-r--r--client/js/models/abstract_list.js46
-rw-r--r--client/js/models/comment.js76
-rw-r--r--client/js/models/comment_list.js11
-rw-r--r--client/js/models/info.js28
-rw-r--r--client/js/models/note.js10
-rw-r--r--client/js/models/note_list.js11
-rw-r--r--client/js/models/point.js12
-rw-r--r--client/js/models/point_list.js8
-rw-r--r--client/js/models/pool.js92
-rw-r--r--client/js/models/pool_category.js61
-rw-r--r--client/js/models/pool_category_list.js46
-rw-r--r--client/js/models/pool_list.js34
-rw-r--r--client/js/models/post.js291
-rw-r--r--client/js/models/post_list.js52
-rw-r--r--client/js/models/settings.js22
-rw-r--r--client/js/models/snapshot.js6
-rw-r--r--client/js/models/snapshot_list.js33
-rw-r--r--client/js/models/tag.js96
-rw-r--r--client/js/models/tag_category.js61
-rw-r--r--client/js/models/tag_category_list.js46
-rw-r--r--client/js/models/tag_list.js42
-rw-r--r--client/js/models/top_navigation.js54
-rw-r--r--client/js/models/user.js68
-rw-r--r--client/js/models/user_list.js34
-rw-r--r--client/js/models/user_token.js74
-rw-r--r--client/js/pools.js15
-rw-r--r--client/js/router.js103
-rw-r--r--client/js/tags.js15
-rw-r--r--client/js/templates.js4
-rw-r--r--client/js/util/keyboard.js8
-rw-r--r--client/js/util/markdown.js83
-rw-r--r--client/js/util/misc.js110
-rw-r--r--client/js/util/optimized_resize.js10
-rw-r--r--client/js/util/polyfill.js28
-rw-r--r--client/js/util/progress.js4
-rw-r--r--client/js/util/search.js14
-rw-r--r--client/js/util/touch.js65
-rw-r--r--client/js/util/uri.js35
-rw-r--r--client/js/util/views.js454
-rw-r--r--client/js/views/comments_page_view.js22
-rw-r--r--client/js/views/empty_view.js9
-rw-r--r--client/js/views/endless_page_view.js126
-rw-r--r--client/js/views/help_view.js80
-rw-r--r--client/js/views/home_view.js83
-rw-r--r--client/js/views/login_view.js61
-rw-r--r--client/js/views/manual_page_view.js123
-rw-r--r--client/js/views/not_found_view.js10
-rw-r--r--client/js/views/password_reset_view.js41
-rw-r--r--client/js/views/pool_categories_view.js82
-rw-r--r--client/js/views/pool_create_view.js82
-rw-r--r--client/js/views/pool_delete_view.js24
-rw-r--r--client/js/views/pool_edit_view.js95
-rw-r--r--client/js/views/pool_merge_view.js46
-rw-r--r--client/js/views/pool_summary_view.js6
-rw-r--r--client/js/views/pool_view.js64
-rw-r--r--client/js/views/pools_header_view.js45
-rw-r--r--client/js/views/pools_page_view.js6
-rw-r--r--client/js/views/post_detail_view.js40
-rw-r--r--client/js/views/post_main_view.js98
-rw-r--r--client/js/views/post_merge_view.js104
-rw-r--r--client/js/views/post_upload_view.js226
-rw-r--r--client/js/views/posts_header_view.js164
-rw-r--r--client/js/views/posts_page_view.js71
-rw-r--r--client/js/views/registration_view.js49
-rw-r--r--client/js/views/settings_view.js50
-rw-r--r--client/js/views/snapshots_page_view.js104
-rw-r--r--client/js/views/tag_categories_view.js82
-rw-r--r--client/js/views/tag_delete_view.js24
-rw-r--r--client/js/views/tag_edit_view.js105
-rw-r--r--client/js/views/tag_merge_view.js47
-rw-r--r--client/js/views/tag_summary_view.js6
-rw-r--r--client/js/views/tag_view.js64
-rw-r--r--client/js/views/tags_header_view.js45
-rw-r--r--client/js/views/tags_page_view.js6
-rw-r--r--client/js/views/top_navigation_view.js34
-rw-r--r--client/js/views/user_delete_view.js25
-rw-r--r--client/js/views/user_edit_view.js98
-rw-r--r--client/js/views/user_summary_view.js6
-rw-r--r--client/js/views/user_tokens_view.js103
-rw-r--r--client/js/views/user_view.js64
-rw-r--r--client/js/views/users_header_view.js30
-rw-r--r--client/js/views/users_page_view.js6
126 files changed, 5538 insertions, 4681 deletions
diff --git a/client/.eslintrc.yml b/client/.eslintrc.yml
index a176248..a9d703f 100644
--- a/client/.eslintrc.yml
+++ b/client/.eslintrc.yml
@@ -2,7 +2,7 @@ env:
browser: true
commonjs: true
es6: true
-extends: 'eslint:recommended'
+extends: 'prettier'
globals:
Atomics: readonly
SharedArrayBuffer: readonly
@@ -10,284 +10,3 @@ ignorePatterns:
- build.js
parserOptions:
ecmaVersion: 11
-rules:
- accessor-pairs: error
- array-bracket-newline: error
- array-bracket-spacing:
- - error
- - never
- array-callback-return: error
- array-element-newline: 'off'
- arrow-body-style: 'off'
- arrow-parens:
- - error
- - as-needed
- arrow-spacing:
- - error
- - after: true
- before: true
- block-scoped-var: error
- block-spacing: error
- brace-style:
- - error
- - 1tbs
- callback-return: 'off'
- camelcase: error
- class-methods-use-this: 'off'
- comma-dangle: 'off'
- comma-spacing:
- - error
- - after: true
- before: false
- comma-style:
- - error
- - last
- complexity: 'off'
- computed-property-spacing:
- - error
- - never
- consistent-return: 'off'
- consistent-this: 'off'
- curly: error
- default-case: error
- default-case-last: error
- default-param-last: error
- dot-location:
- - error
- - property
- dot-notation:
- - error
- - allowKeywords: true
- eol-last: error
- eqeqeq: error
- func-call-spacing: error
- func-name-matching: error
- func-names: error
- func-style:
- - error
- - declaration
- - allowArrowFunctions: true
- function-call-argument-newline:
- - error
- - consistent
- function-paren-newline: 'off'
- generator-star-spacing: error
- global-require: 'off'
- grouped-accessor-pairs: 'off'
- guard-for-in: error
- handle-callback-err: error
- id-blacklist: error
- id-length: 'off'
- id-match: error
- implicit-arrow-linebreak:
- - error
- - beside
- indent:
- - error
- - 4
- indent-legacy: 'off'
- init-declarations: error
- jsx-quotes: error
- key-spacing: error
- keyword-spacing:
- - error
- - after: true
- before: true
- line-comment-position: 'off'
- linebreak-style:
- - error
- - unix
- lines-around-comment: error
- lines-around-directive: error
- lines-between-class-members:
- - error
- - always
- max-classes-per-file: 'off'
- max-depth: error
- max-len: 'off'
- max-lines: 'off'
- max-lines-per-function: 'off'
- max-nested-callbacks: error
- max-params: 'off'
- max-statements: 'off'
- max-statements-per-line: error
- multiline-comment-style:
- - error
- - separate-lines
- multiline-ternary: 'off'
- new-cap: error
- new-parens: error
- newline-after-var: 'off'
- newline-before-return: 'off'
- newline-per-chained-call: 'off'
- no-alert: 'off'
- no-array-constructor: error
- no-await-in-loop: error
- no-bitwise: 'off'
- no-buffer-constructor: 'off'
- no-caller: error
- no-catch-shadow: error
- no-confusing-arrow: error
- no-console: error
- no-constructor-return: error
- no-continue: 'off'
- no-div-regex: 'off'
- no-duplicate-imports: error
- no-else-return: 'off'
- no-empty-function: 'off'
- no-eq-null: error
- no-eval: error
- no-extend-native: error
- no-extra-bind: error
- no-extra-label: error
- no-extra-parens: 'off'
- no-floating-decimal: error
- no-implicit-globals: error
- no-implied-eval: error
- no-inline-comments: 'off'
- no-invalid-this: error
- no-iterator: error
- no-label-var: error
- no-labels: error
- no-lone-blocks: error
- no-lonely-if: error
- no-loop-func: 'off'
- no-loss-of-precision: error
- no-magic-numbers: 'off'
- no-mixed-operators: error
- no-mixed-requires: error
- no-multi-assign: error
- no-multi-spaces:
- - error
- - ignoreEOLComments: true
- no-multi-str: error
- no-multiple-empty-lines: error
- no-native-reassign: error
- no-negated-condition: 'off'
- no-negated-in-lhs: error
- no-nested-ternary: error
- no-new: 'off'
- no-new-func: error
- no-new-object: error
- no-new-require: error
- no-new-wrappers: error
- no-octal-escape: error
- no-param-reassign: 'off'
- no-path-concat: error
- no-plusplus: 'off'
- no-process-env: error
- no-process-exit: error
- no-proto: error
- no-restricted-exports: error
- no-restricted-globals: error
- no-restricted-imports: error
- no-restricted-modules: error
- no-restricted-properties: error
- no-restricted-syntax: error
- no-return-assign: error
- no-return-await: error
- no-script-url: error
- no-self-compare: error
- no-sequences: error
- no-shadow: 'off'
- no-spaced-func: error
- no-sync: error
- no-tabs: error
- no-template-curly-in-string: error
- no-ternary: 'off'
- no-throw-literal: 'off'
- no-trailing-spaces: error
- no-undef-init: error
- no-undefined: 'off'
- no-underscore-dangle: 'off'
- no-unmodified-loop-condition: error
- no-unneeded-ternary: error
- no-unused-expressions: error
- no-unused-vars: 'off'
- no-use-before-define: 'off'
- no-useless-backreference: error
- no-useless-call: error
- no-useless-computed-key: error
- no-useless-concat: error
- no-useless-constructor: error
- no-useless-escape: 'off'
- no-useless-rename: error
- no-useless-return: error
- no-var: 'off'
- no-void: error
- no-warning-comments: warn
- no-whitespace-before-property: error
- nonblock-statement-body-position: error
- object-curly-newline: error
- object-curly-spacing:
- - error
- - never
- object-shorthand: 'off'
- one-var: 'off'
- one-var-declaration-per-line: error
- operator-assignment:
- - error
- - always
- operator-linebreak: 'off'
- padded-blocks: 'off'
- padding-line-between-statements: error
- prefer-arrow-callback: error
- prefer-const: 'off'
- prefer-destructuring: 'off'
- prefer-exponentiation-operator: 'off'
- prefer-named-capture-group: 'off'
- prefer-numeric-literals: error
- prefer-object-spread: 'off'
- prefer-promise-reject-errors: 'off'
- prefer-reflect: 'off'
- prefer-regex-literals: warn
- prefer-rest-params: 'off'
- prefer-spread: 'off'
- prefer-template: 'off'
- quote-props: 'off'
- quotes: 'off'
- radix:
- - error
- - as-needed
- require-atomic-updates: error
- require-await: error
- require-jsdoc: 'off'
- require-unicode-regexp: 'off'
- rest-spread-spacing: error
- semi: 'off'
- semi-spacing:
- - error
- - after: true
- before: false
- semi-style:
- - error
- - last
- sort-imports: error
- sort-keys: 'off'
- sort-vars: error
- space-before-blocks: error
- space-before-function-paren: 'off'
- space-in-parens:
- - error
- - never
- space-infix-ops: error
- space-unary-ops: error
- spaced-comment:
- - error
- - always
- strict: error
- switch-colon-spacing: error
- symbol-description: error
- template-curly-spacing:
- - error
- - never
- template-tag-spacing: error
- unicode-bom:
- - error
- - never
- valid-jsdoc: error
- vars-on-top: error
- wrap-iife: error
- wrap-regex: error
- yield-star-spacing: error
- yoda: 'off'
diff --git a/client/.prettierrc.yml b/client/.prettierrc.yml
new file mode 100644
index 0000000..925bde8
--- /dev/null
+++ b/client/.prettierrc.yml
@@ -0,0 +1,4 @@
+parser: babel
+printWidth: 79
+tabWidth: 4
+quoteProps: consistent
diff --git a/client/js/api.js b/client/js/api.js
index befe02f..5bde6d8 100644
--- a/client/js/api.js
+++ b/client/js/api.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const cookies = require('js-cookie');
-const request = require('superagent');
-const events = require('./events.js');
-const progress = require('./util/progress.js');
-const uri = require('./util/uri.js');
+const cookies = require("js-cookie");
+const request = require("superagent");
+const events = require("./events.js");
+const progress = require("./util/progress.js");
+const uri = require("./util/uri.js");
let fileTokens = {};
let remoteConfig = null;
@@ -18,22 +18,22 @@ class Api extends events.EventTarget {
this.token = null;
this.cache = {};
this.allRanks = [
- 'anonymous',
- 'restricted',
- 'regular',
- 'power',
- 'moderator',
- 'administrator',
- 'nobody',
+ "anonymous",
+ "restricted",
+ "regular",
+ "power",
+ "moderator",
+ "administrator",
+ "nobody",
];
this.rankNames = new Map([
- ['anonymous', 'Anonymous'],
- ['restricted', 'Restricted user'],
- ['regular', 'Regular user'],
- ['power', 'Power user'],
- ['moderator', 'Moderator'],
- ['administrator', 'Administrator'],
- ['nobody', 'Nobody'],
+ ["anonymous", "Anonymous"],
+ ["restricted", "Restricted user"],
+ ["regular", "Regular user"],
+ ["power", "Power user"],
+ ["moderator", "Moderator"],
+ ["administrator", "Administrator"],
+ ["nobody", "Nobody"],
]);
}
@@ -43,11 +43,12 @@ class Api extends events.EventTarget {
resolve(this.cache[url]);
});
}
- return this._wrappedRequest(url, request.get, {}, {}, options)
- .then(response => {
+ return this._wrappedRequest(url, request.get, {}, {}, options).then(
+ (response) => {
this.cache[url] = response;
return Promise.resolve(response);
- });
+ }
+ );
}
post(url, data, files, options) {
@@ -67,10 +68,9 @@ class Api extends events.EventTarget {
fetchConfig() {
if (remoteConfig === null) {
- return this.get(uri.formatApiLink('info'))
- .then(response => {
- remoteConfig = response.config;
- });
+ return this.get(uri.formatApiLink("info")).then((response) => {
+ remoteConfig = response.config;
+ });
} else {
return Promise.resolve();
}
@@ -115,7 +115,8 @@ class Api extends events.EventTarget {
continue;
}
const rankIndex = this.allRanks.indexOf(
- remoteConfig.privileges[p]);
+ remoteConfig.privileges[p]
+ );
if (minViableRank === null || rankIndex < minViableRank) {
minViableRank = rankIndex;
}
@@ -123,17 +124,16 @@ class Api extends events.EventTarget {
if (minViableRank === null) {
throw `Bad privilege name: ${lookup}`;
}
- let myRank = this.user !== null ?
- this.allRanks.indexOf(this.user.rank) :
- 0;
+ let myRank =
+ this.user !== null ? this.allRanks.indexOf(this.user.rank) : 0;
return myRank >= minViableRank;
}
loginFromCookies() {
- const auth = cookies.getJSON('auth');
- return auth && auth.user && auth.token ?
- this.loginWithToken(auth.user, auth.token, true) :
- Promise.resolve();
+ const auth = cookies.getJSON("auth");
+ return auth && auth.user && auth.token
+ ? this.loginWithToken(auth.user, auth.token, true)
+ : Promise.resolve();
}
loginWithToken(userName, token, doRemember) {
@@ -141,63 +141,74 @@ class Api extends events.EventTarget {
return new Promise((resolve, reject) => {
this.userName = userName;
this.token = token;
- this.get('/user/' + userName + '?bump-login=true')
- .then(response => {
+ this.get("/user/" + userName + "?bump-login=true").then(
+ (response) => {
const options = {};
if (doRemember) {
options.expires = 365;
}
cookies.set(
- 'auth',
- {'user': userName, 'token': token},
- options);
+ "auth",
+ { user: userName, token: token },
+ options
+ );
this.user = response;
resolve();
- this.dispatchEvent(new CustomEvent('login'));
- }, error => {
+ this.dispatchEvent(new CustomEvent("login"));
+ },
+ (error) => {
reject(error);
this.logout();
- });
+ }
+ );
});
}
createToken(userName, options) {
let userTokenRequest = {
enabled: true,
- note: 'Web Login Token'
+ note: "Web Login Token",
};
- if (typeof options.expires !== 'undefined') {
- userTokenRequest.expirationTime = new Date().addDays(options.expires).toISOString()
+ if (typeof options.expires !== "undefined") {
+ userTokenRequest.expirationTime = new Date()
+ .addDays(options.expires)
+ .toISOString();
}
return new Promise((resolve, reject) => {
- this.post('/user-token/' + userName, userTokenRequest)
- .then(response => {
+ this.post("/user-token/" + userName, userTokenRequest).then(
+ (response) => {
cookies.set(
- 'auth',
- {'user': userName, 'token': response.token},
- options);
+ "auth",
+ { user: userName, token: response.token },
+ options
+ );
this.userName = userName;
this.token = response.token;
this.userPassword = null;
- }, error => {
+ },
+ (error) => {
reject(error);
- });
+ }
+ );
});
}
deleteToken(userName, userToken) {
return new Promise((resolve, reject) => {
- this.delete('/user-token/' + userName + '/' + userToken, {})
- .then(response => {
+ this.delete("/user-token/" + userName + "/" + userToken, {}).then(
+ (response) => {
const options = {};
cookies.set(
- 'auth',
- {'user': userName, 'token': null},
- options);
+ "auth",
+ { user: userName, token: null },
+ options
+ );
resolve();
- }, error => {
+ },
+ (error) => {
reject(error);
- });
+ }
+ );
});
}
@@ -206,8 +217,8 @@ class Api extends events.EventTarget {
return new Promise((resolve, reject) => {
this.userName = userName;
this.userPassword = userPassword;
- this.get('/user/' + userName + '?bump-login=true')
- .then(response => {
+ this.get("/user/" + userName + "?bump-login=true").then(
+ (response) => {
const options = {};
if (doRemember) {
options.expires = 365;
@@ -215,22 +226,26 @@ class Api extends events.EventTarget {
this.createToken(this.userName, options);
this.user = response;
resolve();
- this.dispatchEvent(new CustomEvent('login'));
- }, error => {
+ this.dispatchEvent(new CustomEvent("login"));
+ },
+ (error) => {
reject(error);
this.logout();
- });
+ }
+ );
});
}
logout() {
let self = this;
- this.deleteToken(this.userName, this.token)
- .then(response => {
+ this.deleteToken(this.userName, this.token).then(
+ (response) => {
self._logout();
- }, error => {
+ },
+ (error) => {
self._logout();
- });
+ }
+ );
}
_logout() {
@@ -238,17 +253,19 @@ class Api extends events.EventTarget {
this.userName = null;
this.userPassword = null;
this.token = null;
- this.dispatchEvent(new CustomEvent('logout'));
+ this.dispatchEvent(new CustomEvent("logout"));
}
forget() {
- cookies.remove('auth');
+ cookies.remove("auth");
}
isLoggedIn(user) {
if (user) {
- return this.userName !== null &&
- this.userName.toLowerCase() === user.name.toLowerCase();
+ return (
+ this.userName !== null &&
+ this.userName.toLowerCase() === user.name.toLowerCase()
+ );
} else {
return this.userName !== null;
}
@@ -259,8 +276,7 @@ class Api extends events.EventTarget {
}
_getFullUrl(url) {
- const fullUrl =
- ('api/' + url).replace(/([^:])\/+/g, '$1/');
+ const fullUrl = ("api/" + url).replace(/([^:])\/+/g, "$1/");
const matches = fullUrl.match(/^([^?]*)\??(.*)$/);
const baseUrl = matches[1];
const request = matches[2];
@@ -285,7 +301,7 @@ class Api extends events.EventTarget {
const file = files[key];
const fileId = this._getFileId(file);
if (fileTokens[fileId]) {
- data[key + 'Token'] = fileTokens[fileId];
+ data[key + "Token"] = fileTokens[fileId];
} else {
promise = promise
.then(() => {
@@ -293,33 +309,40 @@ class Api extends events.EventTarget {
abortFunction = () => uploadPromise.abort();
return uploadPromise;
})
- .then(token => {
+ .then((token) => {
abortFunction = () => {};
fileTokens[fileId] = token;
- data[key + 'Token'] = token;
+ data[key + "Token"] = token;
return Promise.resolve();
});
}
}
}
- promise = promise.then(
- () => {
+ promise = promise
+ .then(() => {
let requestPromise = this._rawRequest(
- url, requestFactory, data, {}, options);
+ url,
+ requestFactory,
+ data,
+ {},
+ options
+ );
abortFunction = () => requestPromise.abort();
return requestPromise;
})
- .catch(error => {
- if (error.response && error.response.name ===
- 'MissingOrExpiredRequiredFileError') {
+ .catch((error) => {
+ if (
+ error.response &&
+ error.response.name === "MissingOrExpiredRequiredFileError"
+ ) {
for (let key of Object.keys(files)) {
const file = files[key];
const fileId = this._getFileId(file);
fileTokens[fileId] = null;
}
error.message =
- 'The uploaded file has expired; ' +
- 'please resend the form to reupload.';
+ "The uploaded file has expired; " +
+ "please resend the form to reupload.";
}
return Promise.reject(error);
});
@@ -331,13 +354,17 @@ class Api extends events.EventTarget {
let abortFunction = () => {};
let returnedPromise = new Promise((resolve, reject) => {
let uploadPromise = this._rawRequest(
- 'uploads', request.post, {}, {content: file}, options);
+ "uploads",
+ request.post,
+ {},
+ { content: file },
+ options
+ );
abortFunction = () => uploadPromise.abort();
- return uploadPromise.then(
- response => {
- abortFunction = () => {};
- return resolve(response.token);
- }, reject);
+ return uploadPromise.then((response) => {
+ abortFunction = () => {};
+ return resolve(response.token);
+ }, reject);
});
returnedPromise.abort = () => abortFunction();
return returnedPromise;
@@ -352,7 +379,7 @@ class Api extends events.EventTarget {
let returnedPromise = new Promise((resolve, reject) => {
let req = requestFactory(fullUrl);
- req.set('Accept', 'application/json');
+ req.set("Accept", "application/json");
if (query) {
req.query(query);
@@ -362,7 +389,7 @@ class Api extends events.EventTarget {
for (let key of Object.keys(files)) {
const value = files[key];
if (value.constructor === String) {
- data[key + 'Url'] = value;
+ data[key + "Url"] = value;
} else {
req.attach(key, value || new Blob());
}
@@ -371,9 +398,9 @@ class Api extends events.EventTarget {
if (data) {
if (files && Object.keys(files).length) {
- req.attach('metadata', new Blob([JSON.stringify(data)]));
+ req.attach("metadata", new Blob([JSON.stringify(data)]));
} else {
- req.set('Content-Type', 'application/json');
+ req.set("Content-Type", "application/json");
req.send(data);
}
}
@@ -382,19 +409,28 @@ class Api extends events.EventTarget {
if (this.userName && this.token) {
req.auth = null;
// eslint-disable-next-line no-undef
- req.set('Authorization', 'Token ' + new Buffer(
- this.userName + ":" + this.token).toString('base64'))
+ req.set(
+ "Authorization",
+ "Token " +
+ new Buffer(
+ this.userName + ":" + this.token
+ ).toString("base64")
+ );
} else if (this.userName && this.userPassword) {
req.auth(
this.userName,
- encodeURIComponent(this.userPassword)
- .replace(/%([0-9A-F]{2})/g, (match, p1) => {
- return String.fromCharCode('0x' + p1);
- }));
+ encodeURIComponent(this.userPassword).replace(
+ /%([0-9A-F]{2})/g,
+ (match, p1) => {
+ return String.fromCharCode("0x" + p1);
+ }
+ )
+ );
}
} catch (e) {
reject(
- new Error('Authentication error (malformed credentials)'));
+ new Error("Authentication error (malformed credentials)")
+ );
}
if (!options.noProgress) {
@@ -402,10 +438,11 @@ class Api extends events.EventTarget {
}
abortFunction = () => {
- req.abort(); // does *NOT* call the callback passed in .end()
+ req.abort(); // does *NOT* call the callback passed in .end()
progress.done();
reject(
- new Error('The request was aborted due to user cancel.'));
+ new Error("The request was aborted due to user cancel.")
+ );
};
req.end((error, response) => {
@@ -414,7 +451,8 @@ class Api extends events.EventTarget {
if (error) {
if (response && response.body) {
error = new Error(
- response.body.description || 'Unknown error');
+ response.body.description || "Unknown error"
+ );
error.response = response.body;
}
reject(error);
diff --git a/client/js/config.js b/client/js/config.js
index 4524be6..da8fb8f 100644
--- a/client/js/config.js
+++ b/client/js/config.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
-const config = require('./.config.autogen.json');
+const config = require("./.config.autogen.json");
module.exports = config;
diff --git a/client/js/controllers/auth_controller.js b/client/js/controllers/auth_controller.js
index a6ec97d..e01fb9b 100644
--- a/client/js/controllers/auth_controller.js
+++ b/client/js/controllers/auth_controller.js
@@ -1,38 +1,40 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const tags = require('../tags.js');
-const pools = require('../pools.js');
-const uri = require('../util/uri.js');
-const topNavigation = require('../models/top_navigation.js');
-const LoginView = require('../views/login_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const tags = require("../tags.js");
+const pools = require("../pools.js");
+const uri = require("../util/uri.js");
+const topNavigation = require("../models/top_navigation.js");
+const LoginView = require("../views/login_view.js");
class LoginController {
constructor() {
api.forget();
- topNavigation.activate('login');
- topNavigation.setTitle('Login');
+ topNavigation.activate("login");
+ topNavigation.setTitle("Login");
this._loginView = new LoginView();
- this._loginView.addEventListener('submit', e => this._evtLogin(e));
+ this._loginView.addEventListener("submit", (e) => this._evtLogin(e));
}
_evtLogin(e) {
this._loginView.clearMessages();
this._loginView.disableForm();
api.forget();
- api.login(e.detail.name, e.detail.password, e.detail.remember)
- .then(() => {
+ api.login(e.detail.name, e.detail.password, e.detail.remember).then(
+ () => {
const ctx = router.show(uri.formatClientLink());
- ctx.controller.showSuccess('Logged in');
+ ctx.controller.showSuccess("Logged in");
// reload tag category color map, this is required when `tag_categories:list` has a permission other than anonymous
tags.refreshCategoryColorMap();
pools.refreshCategoryColorMap();
- }, error => {
+ },
+ (error) => {
this._loginView.showError(error.message);
this._loginView.enableForm();
- });
+ }
+ );
}
}
@@ -41,15 +43,15 @@ class LogoutController {
api.forget();
api.logout();
const ctx = router.show(uri.formatClientLink());
- ctx.controller.showSuccess('Logged out');
+ ctx.controller.showSuccess("Logged out");
}
}
-module.exports = router => {
- router.enter(['login'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["login"], (ctx, next) => {
ctx.controller = new LoginController();
});
- router.enter(['logout'], (ctx, next) => {
+ router.enter(["logout"], (ctx, next) => {
ctx.controller = new LogoutController();
});
};
diff --git a/client/js/controllers/base_post_controller.js b/client/js/controllers/base_post_controller.js
index b86aea7..7a21449 100644
--- a/client/js/controllers/base_post_controller.js
+++ b/client/js/controllers/base_post_controller.js
@@ -1,19 +1,19 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const topNavigation = require('../models/top_navigation.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const topNavigation = require("../models/top_navigation.js");
+const EmptyView = require("../views/empty_view.js");
class BasePostController {
constructor(ctx) {
- if (!api.hasPrivilege('posts:view')) {
+ if (!api.hasPrivilege("posts:view")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view posts.');
+ this._view.showError("You don't have privileges to view posts.");
return;
}
- topNavigation.activate('posts');
- topNavigation.setTitle('Post #' + ctx.parameters.id.toString());
+ topNavigation.activate("posts");
+ topNavigation.setTitle("Post #" + ctx.parameters.id.toString());
}
}
diff --git a/client/js/controllers/comments_controller.js b/client/js/controllers/comments_controller.js
index 67e44ac..d54059e 100644
--- a/client/js/controllers/comments_controller.js
+++ b/client/js/controllers/comments_controller.js
@@ -1,51 +1,55 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const PostList = require('../models/post_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PageController = require('../controllers/page_controller.js');
-const CommentsPageView = require('../views/comments_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const PostList = require("../models/post_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PageController = require("../controllers/page_controller.js");
+const CommentsPageView = require("../views/comments_page_view.js");
+const EmptyView = require("../views/empty_view.js");
-const fields = ['id', 'comments', 'commentCount', 'thumbnailUrl'];
+const fields = ["id", "comments", "commentCount", "thumbnailUrl"];
class CommentsController {
constructor(ctx) {
- if (!api.hasPrivilege('comments:list')) {
+ if (!api.hasPrivilege("comments:list")) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to view comments.');
+ "You don't have privileges to view comments."
+ );
return;
}
- topNavigation.activate('comments');
- topNavigation.setTitle('Listing comments');
+ topNavigation.activate("comments");
+ topNavigation.setTitle("Listing comments");
this._pageController = new PageController();
this._pageController.run({
parameters: ctx.parameters,
defaultLimit: 10,
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('comments', parameters);
+ const parameters = Object.assign({}, ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("comments", parameters);
},
requestPage: (offset, limit) => {
return PostList.search(
- 'sort:comment-date comment-count-min:1',
+ "sort:comment-date comment-count-min:1",
offset,
limit,
- fields);
+ fields
+ );
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
Object.assign(pageCtx, {
- canViewPosts: api.hasPrivilege('posts:view'),
+ canViewPosts: api.hasPrivilege("posts:view"),
});
const view = new CommentsPageView(pageCtx);
- view.addEventListener('submit', e => this._evtUpdate(e));
- view.addEventListener('score', e => this._evtScore(e));
- view.addEventListener('delete', e => this._evtDelete(e));
+ view.addEventListener("submit", (e) => this._evtUpdate(e));
+ view.addEventListener("score", (e) => this._evtScore(e));
+ view.addEventListener("delete", (e) => this._evtDelete(e));
return view;
},
});
@@ -54,26 +58,27 @@ class CommentsController {
_evtUpdate(e) {
// TODO: disable form
e.detail.comment.text = e.detail.text;
- e.detail.comment.save()
- .catch(error => {
- e.detail.target.showError(error.message);
- // TODO: enable form
- });
+ e.detail.comment.save().catch((error) => {
+ e.detail.target.showError(error.message);
+ // TODO: enable form
+ });
}
_evtScore(e) {
- e.detail.comment.setScore(e.detail.score)
- .catch(error => window.alert(error.message));
+ e.detail.comment
+ .setScore(e.detail.score)
+ .catch((error) => window.alert(error.message));
}
_evtDelete(e) {
- e.detail.comment.delete()
- .catch(error => window.alert(error.message));
+ e.detail.comment
+ .delete()
+ .catch((error) => window.alert(error.message));
}
}
-module.exports = router => {
- router.enter(['comments'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["comments"], (ctx, next) => {
new CommentsController(ctx);
});
-}
+};
diff --git a/client/js/controllers/help_controller.js b/client/js/controllers/help_controller.js
index 8e65346..c290a6b 100644
--- a/client/js/controllers/help_controller.js
+++ b/client/js/controllers/help_controller.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const topNavigation = require('../models/top_navigation.js');
-const HelpView = require('../views/help_view.js');
+const topNavigation = require("../models/top_navigation.js");
+const HelpView = require("../views/help_view.js");
class HelpController {
constructor(section, subsection) {
- topNavigation.activate('help');
- topNavigation.setTitle('Help');
+ topNavigation.activate("help");
+ topNavigation.setTitle("Help");
this._helpView = new HelpView(section, subsection);
}
}
-module.exports = router => {
- router.enter(['help'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["help"], (ctx, next) => {
new HelpController();
});
- router.enter(['help', ':section'], (ctx, next) => {
+ router.enter(["help", ":section"], (ctx, next) => {
new HelpController(ctx.parameters.section);
});
- router.enter(['help', ':section', ':subsection'], (ctx, next) => {
+ router.enter(["help", ":section", ":subsection"], (ctx, next) => {
new HelpController(ctx.parameters.section, ctx.parameters.subsection);
});
};
diff --git a/client/js/controllers/home_controller.js b/client/js/controllers/home_controller.js
index 590da67..cf56e27 100644
--- a/client/js/controllers/home_controller.js
+++ b/client/js/controllers/home_controller.js
@@ -1,26 +1,26 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const config = require('../config.js');
-const Info = require('../models/info.js');
-const topNavigation = require('../models/top_navigation.js');
-const HomeView = require('../views/home_view.js');
+const api = require("../api.js");
+const config = require("../config.js");
+const Info = require("../models/info.js");
+const topNavigation = require("../models/top_navigation.js");
+const HomeView = require("../views/home_view.js");
class HomeController {
constructor() {
- topNavigation.activate('home');
- topNavigation.setTitle('Home');
+ topNavigation.activate("home");
+ topNavigation.setTitle("Home");
this._homeView = new HomeView({
name: api.getName(),
version: config.meta.version,
buildDate: config.meta.buildDate,
- canListSnapshots: api.hasPrivilege('snapshots:list'),
- canListPosts: api.hasPrivilege('posts:list'),
+ canListSnapshots: api.hasPrivilege("snapshots:list"),
+ canListPosts: api.hasPrivilege("posts:list"),
});
- Info.get()
- .then(info => {
+ Info.get().then(
+ (info) => {
this._homeView.setStats({
diskUsage: info.diskUsage,
postCount: info.postCount,
@@ -31,7 +31,8 @@ class HomeController {
featuringTime: info.featuringTime,
});
},
- error => this._homeView.showError(error.message));
+ (error) => this._homeView.showError(error.message)
+ );
}
showSuccess(message) {
@@ -43,8 +44,8 @@ class HomeController {
}
}
-module.exports = router => {
+module.exports = (router) => {
router.enter([], (ctx, next) => {
ctx.controller = new HomeController();
});
-}
+};
diff --git a/client/js/controllers/not_found_controller.js b/client/js/controllers/not_found_controller.js
index 8ceeef0..c99e308 100644
--- a/client/js/controllers/not_found_controller.js
+++ b/client/js/controllers/not_found_controller.js
@@ -1,18 +1,18 @@
-'use strict';
+"use strict";
-const topNavigation = require('../models/top_navigation.js');
-const NotFoundView = require('../views/not_found_view.js');
+const topNavigation = require("../models/top_navigation.js");
+const NotFoundView = require("../views/not_found_view.js");
class NotFoundController {
constructor(path) {
- topNavigation.activate('');
- topNavigation.setTitle('Not found');
+ topNavigation.activate("");
+ topNavigation.setTitle("Not found");
this._notFoundView = new NotFoundView(path);
}
}
-module.exports = router => {
+module.exports = (router) => {
router.enter(null, (ctx, next) => {
ctx.controller = new NotFoundController(ctx.canonicalPath);
});
-}
+};
diff --git a/client/js/controllers/page_controller.js b/client/js/controllers/page_controller.js
index ae55804..d3ee7e9 100644
--- a/client/js/controllers/page_controller.js
+++ b/client/js/controllers/page_controller.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const settings = require('../models/settings.js');
-const EndlessPageView = require('../views/endless_page_view.js');
-const ManualPageView = require('../views/manual_page_view.js');
+const settings = require("../models/settings.js");
+const EndlessPageView = require("../views/endless_page_view.js");
+const ManualPageView = require("../views/manual_page_view.js");
class PageController {
constructor(ctx) {
diff --git a/client/js/controllers/password_reset_controller.js b/client/js/controllers/password_reset_controller.js
index e0a9801..aa66c03 100644
--- a/client/js/controllers/password_reset_controller.js
+++ b/client/js/controllers/password_reset_controller.js
@@ -1,19 +1,20 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const topNavigation = require('../models/top_navigation.js');
-const PasswordResetView = require('../views/password_reset_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const topNavigation = require("../models/top_navigation.js");
+const PasswordResetView = require("../views/password_reset_view.js");
class PasswordResetController {
constructor() {
- topNavigation.activate('login');
- topNavigation.setTitle('Password reminder');
+ topNavigation.activate("login");
+ topNavigation.setTitle("Password reminder");
this._passwordResetView = new PasswordResetView();
- this._passwordResetView.addEventListener(
- 'submit', e => this._evtReset(e));
+ this._passwordResetView.addEventListener("submit", (e) =>
+ this._evtReset(e)
+ );
}
_evtReset(e) {
@@ -21,15 +22,20 @@ class PasswordResetController {
this._passwordResetView.disableForm();
api.forget();
api.logout();
- api.get(uri.formatApiLink('password-reset', e.detail.userNameOrEmail))
- .then(() => {
+ api.get(
+ uri.formatApiLink("password-reset", e.detail.userNameOrEmail)
+ ).then(
+ () => {
this._passwordResetView.showSuccess(
- 'E-mail has been sent. To finish the procedure, ' +
- 'please click the link it contains.');
- }, error => {
+ "E-mail has been sent. To finish the procedure, " +
+ "please click the link it contains."
+ );
+ },
+ (error) => {
this._passwordResetView.showError(error.message);
this._passwordResetView.enableForm();
- });
+ }
+ );
}
}
@@ -38,26 +44,30 @@ class PasswordResetFinishController {
api.forget();
api.logout();
let password = null;
- api.post(uri.formatApiLink('password-reset', name), {token: token})
- .then(response => {
+ api.post(uri.formatApiLink("password-reset", name), { token: token })
+ .then((response) => {
password = response.password;
return api.login(name, password, false);
- }).then(() => {
- const ctx = router.show(uri.formatClientLink());
- ctx.controller.showSuccess('New password: ' + password);
- }, error => {
- const ctx = router.show(uri.formatClientLink());
- ctx.controller.showError(error.message);
- });
+ })
+ .then(
+ () => {
+ const ctx = router.show(uri.formatClientLink());
+ ctx.controller.showSuccess("New password: " + password);
+ },
+ (error) => {
+ const ctx = router.show(uri.formatClientLink());
+ ctx.controller.showError(error.message);
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['password-reset'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["password-reset"], (ctx, next) => {
ctx.controller = new PasswordResetController();
});
- router.enter(['password-reset', ':descriptor'], (ctx, next) => {
- const [name, token] = ctx.parameters.descriptor.split(':', 2);
+ router.enter(["password-reset", ":descriptor"], (ctx, next) => {
+ const [name, token] = ctx.parameters.descriptor.split(":", 2);
ctx.controller = new PasswordResetFinishController(name, token);
});
};
diff --git a/client/js/controllers/pool_categories_controller.js b/client/js/controllers/pool_categories_controller.js
index 4c2c3b7..4db725c 100644
--- a/client/js/controllers/pool_categories_controller.js
+++ b/client/js/controllers/pool_categories_controller.js
@@ -1,57 +1,69 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const pools = require('../pools.js');
-const PoolCategoryList = require('../models/pool_category_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PoolCategoriesView = require('../views/pool_categories_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const pools = require("../pools.js");
+const PoolCategoryList = require("../models/pool_category_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PoolCategoriesView = require("../views/pool_categories_view.js");
+const EmptyView = require("../views/empty_view.js");
class PoolCategoriesController {
constructor() {
- if (!api.hasPrivilege('poolCategories:list')) {
+ if (!api.hasPrivilege("poolCategories:list")) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to view pool categories.');
+ "You don't have privileges to view pool categories."
+ );
return;
}
- topNavigation.activate('pools');
- topNavigation.setTitle('Listing pools');
- PoolCategoryList.get().then(response => {
- this._poolCategories = response.results;
- this._view = new PoolCategoriesView({
- poolCategories: this._poolCategories,
- canEditName: api.hasPrivilege('poolCategories:edit:name'),
- canEditColor: api.hasPrivilege('poolCategories:edit:color'),
- canDelete: api.hasPrivilege('poolCategories:delete'),
- canCreate: api.hasPrivilege('poolCategories:create'),
- canSetDefault: api.hasPrivilege('poolCategories:setDefault'),
- });
- this._view.addEventListener('submit', e => this._evtSubmit(e));
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ topNavigation.activate("pools");
+ topNavigation.setTitle("Listing pools");
+ PoolCategoryList.get().then(
+ (response) => {
+ this._poolCategories = response.results;
+ this._view = new PoolCategoriesView({
+ poolCategories: this._poolCategories,
+ canEditName: api.hasPrivilege("poolCategories:edit:name"),
+ canEditColor: api.hasPrivilege(
+ "poolCategories:edit:color"
+ ),
+ canDelete: api.hasPrivilege("poolCategories:delete"),
+ canCreate: api.hasPrivilege("poolCategories:create"),
+ canSetDefault: api.hasPrivilege(
+ "poolCategories:setDefault"
+ ),
+ });
+ this._view.addEventListener("submit", (e) =>
+ this._evtSubmit(e)
+ );
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
_evtSubmit(e) {
this._view.clearMessages();
this._view.disableForm();
- this._poolCategories.save()
- .then(() => {
+ this._poolCategories.save().then(
+ () => {
pools.refreshCategoryColorMap();
this._view.enableForm();
- this._view.showSuccess('Changes saved.');
- }, error => {
+ this._view.showSuccess("Changes saved.");
+ },
+ (error) => {
this._view.enableForm();
this._view.showError(error.message);
- });
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['pool-categories'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["pool-categories"], (ctx, next) => {
ctx.controller = new PoolCategoriesController(ctx, next);
});
};
diff --git a/client/js/controllers/pool_controller.js b/client/js/controllers/pool_controller.js
index a06ba5c..6844171 100644
--- a/client/js/controllers/pool_controller.js
+++ b/client/js/controllers/pool_controller.js
@@ -1,63 +1,76 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const Pool = require('../models/pool.js');
-const Post = require('../models/post.js');
-const PoolCategoryList = require('../models/pool_category_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PoolView = require('../views/pool_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const Pool = require("../models/pool.js");
+const Post = require("../models/post.js");
+const PoolCategoryList = require("../models/pool_category_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PoolView = require("../views/pool_view.js");
+const EmptyView = require("../views/empty_view.js");
class PoolController {
constructor(ctx, section) {
- if (!api.hasPrivilege('pools:view')) {
+ if (!api.hasPrivilege("pools:view")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view pools.');
+ this._view.showError("You don't have privileges to view pools.");
return;
}
Promise.all([
PoolCategoryList.get(),
- Pool.get(ctx.parameters.id)
- ]).then(responses => {
- const [poolCategoriesResponse, pool] = responses;
+ Pool.get(ctx.parameters.id),
+ ]).then(
+ (responses) => {
+ const [poolCategoriesResponse, pool] = responses;
- topNavigation.activate('pools');
- topNavigation.setTitle('Pool #' + pool.names[0]);
+ topNavigation.activate("pools");
+ topNavigation.setTitle("Pool #" + pool.names[0]);
- this._name = ctx.parameters.name;
- pool.addEventListener('change', e => this._evtSaved(e, section));
+ this._name = ctx.parameters.name;
+ pool.addEventListener("change", (e) =>
+ this._evtSaved(e, section)
+ );
- const categories = {};
- for (let category of poolCategoriesResponse.results) {
- categories[category.name] = category.name;
- }
+ const categories = {};
+ for (let category of poolCategoriesResponse.results) {
+ categories[category.name] = category.name;
+ }
- this._view = new PoolView({
- pool: pool,
- section: section,
- canEditAnything: api.hasPrivilege('pools:edit'),
- canEditNames: api.hasPrivilege('pools:edit:names'),
- canEditCategory: api.hasPrivilege('pools:edit:category'),
- canEditDescription: api.hasPrivilege('pools:edit:description'),
- canEditPosts: api.hasPrivilege('pools:edit:posts'),
- canMerge: api.hasPrivilege('pools:merge'),
- canDelete: api.hasPrivilege('pools:delete'),
- categories: categories,
- escapeColons: uri.escapeColons,
- });
+ this._view = new PoolView({
+ pool: pool,
+ section: section,
+ canEditAnything: api.hasPrivilege("pools:edit"),
+ canEditNames: api.hasPrivilege("pools:edit:names"),
+ canEditCategory: api.hasPrivilege("pools:edit:category"),
+ canEditDescription: api.hasPrivilege(
+ "pools:edit:description"
+ ),
+ canEditPosts: api.hasPrivilege("pools:edit:posts"),
+ canMerge: api.hasPrivilege("pools:merge"),
+ canDelete: api.hasPrivilege("pools:delete"),
+ categories: categories,
+ escapeColons: uri.escapeColons,
+ });
- this._view.addEventListener('change', e => this._evtChange(e));
- this._view.addEventListener('submit', e => this._evtUpdate(e));
- this._view.addEventListener('merge', e => this._evtMerge(e));
- this._view.addEventListener('delete', e => this._evtDelete(e));
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ this._view.addEventListener("change", (e) =>
+ this._evtChange(e)
+ );
+ this._view.addEventListener("submit", (e) =>
+ this._evtUpdate(e)
+ );
+ this._view.addEventListener("merge", (e) => this._evtMerge(e));
+ this._view.addEventListener("delete", (e) =>
+ this._evtDelete(e)
+ );
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
_evtChange(e) {
@@ -67,7 +80,11 @@ class PoolController {
_evtSaved(e, section) {
misc.disableExitConfirmation();
if (this._name !== e.detail.pool.names[0]) {
- router.replace(uri.formatClientLink('pool', e.detail.pool.id, section), null, false);
+ router.replace(
+ uri.formatClientLink("pool", e.detail.pool.id, section),
+ null,
+ false
+ );
}
}
@@ -86,62 +103,74 @@ class PoolController {
if (e.detail.posts !== undefined) {
e.detail.pool.posts.clear();
for (let postId of e.detail.posts) {
- e.detail.pool.posts.add(Post.fromResponse({id: parseInt(postId)}));
+ e.detail.pool.posts.add(
+ Post.fromResponse({ id: parseInt(postId) })
+ );
}
}
- e.detail.pool.save().then(() => {
- this._view.showSuccess('Pool saved.');
- this._view.enableForm();
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ e.detail.pool.save().then(
+ () => {
+ this._view.showSuccess("Pool saved.");
+ this._view.enableForm();
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
_evtMerge(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.pool
- .merge(e.detail.targetPoolId, e.detail.addAlias)
- .then(() => {
- this._view.showSuccess('Pool merged.');
+ e.detail.pool.merge(e.detail.targetPoolId, e.detail.addAlias).then(
+ () => {
+ this._view.showSuccess("Pool merged.");
this._view.enableForm();
router.replace(
uri.formatClientLink(
- 'pool', e.detail.targetPoolId, 'merge'),
+ "pool",
+ e.detail.targetPoolId,
+ "merge"
+ ),
null,
- false);
- }, error => {
+ false
+ );
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
_evtDelete(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.pool.delete()
- .then(() => {
- const ctx = router.show(uri.formatClientLink('pools'));
- ctx.controller.showSuccess('Pool deleted.');
- }, error => {
+ e.detail.pool.delete().then(
+ () => {
+ const ctx = router.show(uri.formatClientLink("pools"));
+ ctx.controller.showSuccess("Pool deleted.");
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['pool', ':id', 'edit'], (ctx, next) => {
- ctx.controller = new PoolController(ctx, 'edit');
+module.exports = (router) => {
+ router.enter(["pool", ":id", "edit"], (ctx, next) => {
+ ctx.controller = new PoolController(ctx, "edit");
});
- router.enter(['pool', ':id', 'merge'], (ctx, next) => {
- ctx.controller = new PoolController(ctx, 'merge');
+ router.enter(["pool", ":id", "merge"], (ctx, next) => {
+ ctx.controller = new PoolController(ctx, "merge");
});
- router.enter(['pool', ':id', 'delete'], (ctx, next) => {
- ctx.controller = new PoolController(ctx, 'delete');
+ router.enter(["pool", ":id", "delete"], (ctx, next) => {
+ ctx.controller = new PoolController(ctx, "delete");
});
- router.enter(['pool', ':id'], (ctx, next) => {
- ctx.controller = new PoolController(ctx, 'summary');
+ router.enter(["pool", ":id"], (ctx, next) => {
+ ctx.controller = new PoolController(ctx, "summary");
});
};
diff --git a/client/js/controllers/pool_create_controller.js b/client/js/controllers/pool_create_controller.js
index 2b8e7e6..7140aac 100644
--- a/client/js/controllers/pool_create_controller.js
+++ b/client/js/controllers/pool_create_controller.js
@@ -1,58 +1,65 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const PoolCategoryList = require('../models/pool_category_list.js');
-const PoolCreateView = require('../views/pool_create_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const PoolCategoryList = require("../models/pool_category_list.js");
+const PoolCreateView = require("../views/pool_create_view.js");
+const EmptyView = require("../views/empty_view.js");
class PoolCreateController {
constructor(ctx) {
- if (!api.hasPrivilege('pools:create')) {
+ if (!api.hasPrivilege("pools:create")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to create pools.');
+ this._view.showError("You don't have privileges to create pools.");
return;
}
- PoolCategoryList.get().then(poolCategoriesResponse => {
- const categories = {};
- for (let category of poolCategoriesResponse.results) {
- categories[category.name] = category.name;
- }
+ PoolCategoryList.get().then(
+ (poolCategoriesResponse) => {
+ const categories = {};
+ for (let category of poolCategoriesResponse.results) {
+ categories[category.name] = category.name;
+ }
- this._view = new PoolCreateView({
- canCreate: api.hasPrivilege('pools:create'),
- categories: categories,
- escapeColons: uri.escapeColons,
- });
+ this._view = new PoolCreateView({
+ canCreate: api.hasPrivilege("pools:create"),
+ categories: categories,
+ escapeColons: uri.escapeColons,
+ });
- this._view.addEventListener('submit', e => this._evtCreate(e));
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ this._view.addEventListener("submit", (e) =>
+ this._evtCreate(e)
+ );
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
_evtCreate(e) {
this._view.clearMessages();
this._view.disableForm();
- api.post(uri.formatApiLink('pool'), e.detail)
- .then(() => {
+ api.post(uri.formatApiLink("pool"), e.detail).then(
+ () => {
this._view.clearMessages();
misc.disableExitConfirmation();
- const ctx = router.show(uri.formatClientLink('pools'));
- ctx.controller.showSuccess('Pool created.');
- }, error => {
+ const ctx = router.show(uri.formatClientLink("pools"));
+ ctx.controller.showSuccess("Pool created.");
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['pool', 'create'], (ctx, next) => {
- ctx.controller = new PoolCreateController(ctx, 'create');
+module.exports = (router) => {
+ router.enter(["pool", "create"], (ctx, next) => {
+ ctx.controller = new PoolCreateController(ctx, "create");
});
};
diff --git a/client/js/controllers/pool_list_controller.js b/client/js/controllers/pool_list_controller.js
index dff649f..91d655c 100644
--- a/client/js/controllers/pool_list_controller.js
+++ b/client/js/controllers/pool_list_controller.js
@@ -1,47 +1,51 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const PoolList = require('../models/pool_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PageController = require('../controllers/page_controller.js');
-const PoolsHeaderView = require('../views/pools_header_view.js');
-const PoolsPageView = require('../views/pools_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const PoolList = require("../models/pool_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PageController = require("../controllers/page_controller.js");
+const PoolsHeaderView = require("../views/pools_header_view.js");
+const PoolsPageView = require("../views/pools_page_view.js");
+const EmptyView = require("../views/empty_view.js");
const fields = [
- 'id',
- 'names',
- 'posts',
- 'creationTime',
- 'postCount',
- 'category'
+ "id",
+ "names",
+ "posts",
+ "creationTime",
+ "postCount",
+ "category",
];
class PoolListController {
constructor(ctx) {
this._pageController = new PageController();
- if (!api.hasPrivilege('pools:list')) {
+ if (!api.hasPrivilege("pools:list")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view pools.');
+ this._view.showError("You don't have privileges to view pools.");
return;
}
this._ctx = ctx;
- topNavigation.activate('pools');
- topNavigation.setTitle('Listing pools');
+ topNavigation.activate("pools");
+ topNavigation.setTitle("Listing pools");
this._headerView = new PoolsHeaderView({
hostNode: this._pageController.view.pageHeaderHolderNode,
parameters: ctx.parameters,
- canCreate: api.hasPrivilege('pools:create'),
- canEditPoolCategories: api.hasPrivilege('poolCategories:edit'),
+ canCreate: api.hasPrivilege("pools:create"),
+ canEditPoolCategories: api.hasPrivilege("poolCategories:edit"),
});
this._headerView.addEventListener(
- 'submit', e => this._evtSubmit(e), 'navigate', e => this._evtNavigate(e));
+ "submit",
+ (e) => this._evtSubmit(e),
+ "navigate",
+ (e) => this._evtNavigate(e)
+ );
this._syncPageController();
}
@@ -57,24 +61,27 @@ class PoolListController {
_evtSubmit(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.pool.save()
- .then(() => {
- this._installView(e.detail.pool, 'edit');
- this._view.showSuccess('Pool created.');
+ e.detail.pool.save().then(
+ () => {
+ this._installView(e.detail.pool, "edit");
+ this._view.showSuccess("Pool created.");
router.replace(
- uri.formatClientLink(
- 'pool', e.detail.pool.id, 'edit'),
+ uri.formatClientLink("pool", e.detail.pool.id, "edit"),
null,
- false);
- }, error => {
+ false
+ );
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
_evtNavigate(e) {
router.showNoDispatch(
- uri.formatClientLink('pools', e.detail.parameters));
+ uri.formatClientLink("pools", e.detail.parameters)
+ );
Object.assign(this._ctx.parameters, e.detail.parameters);
this._syncPageController();
}
@@ -84,25 +91,29 @@ class PoolListController {
parameters: this._ctx.parameters,
defaultLimit: 50,
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, this._ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('pools', parameters);
+ const parameters = Object.assign({}, this._ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("pools", parameters);
},
requestPage: (offset, limit) => {
return PoolList.search(
- this._ctx.parameters.query, offset, limit, fields);
+ this._ctx.parameters.query,
+ offset,
+ limit,
+ fields
+ );
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
return new PoolsPageView(pageCtx);
},
});
}
}
-module.exports = router => {
- router.enter(
- ['pools'],
- (ctx, next) => {
- ctx.controller = new PoolListController(ctx);
- });
+module.exports = (router) => {
+ router.enter(["pools"], (ctx, next) => {
+ ctx.controller = new PoolListController(ctx);
+ });
};
diff --git a/client/js/controllers/post_detail_controller.js b/client/js/controllers/post_detail_controller.js
index bd9c2e6..9bab1ce 100644
--- a/client/js/controllers/post_detail_controller.js
+++ b/client/js/controllers/post_detail_controller.js
@@ -1,28 +1,33 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const settings = require('../models/settings.js');
-const Post = require('../models/post.js');
-const PostList = require('../models/post_list.js');
-const PostDetailView = require('../views/post_detail_view.js');
-const BasePostController = require('./base_post_controller.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const settings = require("../models/settings.js");
+const Post = require("../models/post.js");
+const PostList = require("../models/post_list.js");
+const PostDetailView = require("../views/post_detail_view.js");
+const BasePostController = require("./base_post_controller.js");
+const EmptyView = require("../views/empty_view.js");
class PostDetailController extends BasePostController {
constructor(ctx, section) {
super(ctx);
- Post.get(ctx.parameters.id).then(post => {
- this._id = ctx.parameters.id;
- post.addEventListener('change', e => this._evtSaved(e, section));
- this._installView(post, section);
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ Post.get(ctx.parameters.id).then(
+ (post) => {
+ this._id = ctx.parameters.id;
+ post.addEventListener("change", (e) =>
+ this._evtSaved(e, section)
+ );
+ this._installView(post, section);
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
showSuccess(message) {
@@ -33,58 +38,68 @@ class PostDetailController extends BasePostController {
this._view = new PostDetailView({
post: post,
section: section,
- canMerge: api.hasPrivilege('posts:merge'),
+ canMerge: api.hasPrivilege("posts:merge"),
});
- this._view.addEventListener('select', e => this._evtSelect(e));
- this._view.addEventListener('merge', e => this._evtMerge(e));
+ this._view.addEventListener("select", (e) => this._evtSelect(e));
+ this._view.addEventListener("merge", (e) => this._evtMerge(e));
}
_evtSelect(e) {
this._view.clearMessages();
this._view.disableForm();
- Post.get(e.detail.postId).then(post => {
- this._view.selectPost(post);
- this._view.enableForm();
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ Post.get(e.detail.postId).then(
+ (post) => {
+ this._view.selectPost(post);
+ this._view.enableForm();
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
_evtSaved(e, section) {
misc.disableExitConfirmation();
if (this._id !== e.detail.post.id) {
router.replace(
- uri.formatClientLink('post', e.detail.post.id, section),
+ uri.formatClientLink("post", e.detail.post.id, section),
null,
- false);
+ false
+ );
}
}
_evtMerge(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.post.merge(e.detail.targetPost.id, e.detail.useOldContent)
- .then(() => {
- this._installView(e.detail.post, 'merge');
- this._view.showSuccess('Post merged.');
- router.replace(
- uri.formatClientLink(
- 'post', e.detail.targetPost.id, 'merge'),
- null,
- false);
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ e.detail.post
+ .merge(e.detail.targetPost.id, e.detail.useOldContent)
+ .then(
+ () => {
+ this._installView(e.detail.post, "merge");
+ this._view.showSuccess("Post merged.");
+ router.replace(
+ uri.formatClientLink(
+ "post",
+ e.detail.targetPost.id,
+ "merge"
+ ),
+ null,
+ false
+ );
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
}
-module.exports = router => {
- router.enter(
- ['post', ':id', 'merge'],
- (ctx, next) => {
- ctx.controller = new PostDetailController(ctx, 'merge');
- });
+module.exports = (router) => {
+ router.enter(["post", ":id", "merge"], (ctx, next) => {
+ ctx.controller = new PostDetailController(ctx, "merge");
+ });
};
diff --git a/client/js/controllers/post_list_controller.js b/client/js/controllers/post_list_controller.js
index 357386c..941ea9d 100644
--- a/client/js/controllers/post_list_controller.js
+++ b/client/js/controllers/post_list_controller.js
@@ -1,48 +1,56 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const settings = require('../models/settings.js');
-const uri = require('../util/uri.js');
-const PostList = require('../models/post_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PageController = require('../controllers/page_controller.js');
-const PostsHeaderView = require('../views/posts_header_view.js');
-const PostsPageView = require('../views/posts_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const settings = require("../models/settings.js");
+const uri = require("../util/uri.js");
+const PostList = require("../models/post_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PageController = require("../controllers/page_controller.js");
+const PostsHeaderView = require("../views/posts_header_view.js");
+const PostsPageView = require("../views/posts_page_view.js");
+const EmptyView = require("../views/empty_view.js");
const fields = [
- 'id', 'thumbnailUrl', 'type', 'safety',
- 'score', 'favoriteCount', 'commentCount', 'tags', 'version'
+ "id",
+ "thumbnailUrl",
+ "type",
+ "safety",
+ "score",
+ "favoriteCount",
+ "commentCount",
+ "tags",
+ "version",
];
class PostListController {
constructor(ctx) {
this._pageController = new PageController();
- if (!api.hasPrivilege('posts:list')) {
+ if (!api.hasPrivilege("posts:list")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view posts.');
+ this._view.showError("You don't have privileges to view posts.");
return;
}
this._ctx = ctx;
- topNavigation.activate('posts');
- topNavigation.setTitle('Listing posts');
+ topNavigation.activate("posts");
+ topNavigation.setTitle("Listing posts");
this._headerView = new PostsHeaderView({
hostNode: this._pageController.view.pageHeaderHolderNode,
parameters: ctx.parameters,
enableSafety: api.safetyEnabled(),
- canBulkEditTags: api.hasPrivilege('posts:bulk-edit:tags'),
- canBulkEditSafety: api.hasPrivilege('posts:bulk-edit:safety'),
+ canBulkEditTags: api.hasPrivilege("posts:bulk-edit:tags"),
+ canBulkEditSafety: api.hasPrivilege("posts:bulk-edit:safety"),
bulkEdit: {
- tags: this._bulkEditTags
+ tags: this._bulkEditTags,
},
});
- this._headerView.addEventListener(
- 'navigate', e => this._evtNavigate(e));
+ this._headerView.addEventListener("navigate", (e) =>
+ this._evtNavigate(e)
+ );
this._syncPageController();
}
@@ -52,33 +60,35 @@ class PostListController {
}
get _bulkEditTags() {
- return (this._ctx.parameters.tag || '').split(/\s+/).filter(s => s);
+ return (this._ctx.parameters.tag || "").split(/\s+/).filter((s) => s);
}
_evtNavigate(e) {
router.showNoDispatch(
- uri.formatClientLink('posts', e.detail.parameters));
+ uri.formatClientLink("posts", e.detail.parameters)
+ );
Object.assign(this._ctx.parameters, e.detail.parameters);
this._syncPageController();
}
_evtTag(e) {
Promise.all(
- this._bulkEditTags.map(tag => e.detail.post.tags.addByName(tag)))
+ this._bulkEditTags.map((tag) => e.detail.post.tags.addByName(tag))
+ )
.then(e.detail.post.save())
- .catch(error => window.alert(error.message));
+ .catch((error) => window.alert(error.message));
}
_evtUntag(e) {
for (let tag of this._bulkEditTags) {
e.detail.post.tags.removeByName(tag);
}
- e.detail.post.save().catch(error => window.alert(error.message));
+ e.detail.post.save().catch((error) => window.alert(error.message));
}
_evtChangeSafety(e) {
e.detail.post.safety = e.detail.safety;
- e.detail.post.save().catch(error => window.alert(error.message));
+ e.detail.post.save().catch((error) => window.alert(error.message));
}
_syncPageController() {
@@ -86,39 +96,45 @@ class PostListController {
parameters: this._ctx.parameters,
defaultLimit: parseInt(settings.get().postsPerPage),
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, this._ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('posts', parameters);
+ const parameters = Object.assign({}, this._ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("posts", parameters);
},
requestPage: (offset, limit) => {
return PostList.search(
- this._ctx.parameters.query, offset, limit, fields);
+ this._ctx.parameters.query,
+ offset,
+ limit,
+ fields
+ );
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
Object.assign(pageCtx, {
- canViewPosts: api.hasPrivilege('posts:view'),
- canBulkEditTags: api.hasPrivilege('posts:bulk-edit:tags'),
- canBulkEditSafety:
- api.hasPrivilege('posts:bulk-edit:safety'),
+ canViewPosts: api.hasPrivilege("posts:view"),
+ canBulkEditTags: api.hasPrivilege("posts:bulk-edit:tags"),
+ canBulkEditSafety: api.hasPrivilege(
+ "posts:bulk-edit:safety"
+ ),
bulkEdit: {
tags: this._bulkEditTags,
},
});
const view = new PostsPageView(pageCtx);
- view.addEventListener('tag', e => this._evtTag(e));
- view.addEventListener('untag', e => this._evtUntag(e));
- view.addEventListener(
- 'changeSafety', e => this._evtChangeSafety(e));
+ view.addEventListener("tag", (e) => this._evtTag(e));
+ view.addEventListener("untag", (e) => this._evtUntag(e));
+ view.addEventListener("changeSafety", (e) =>
+ this._evtChangeSafety(e)
+ );
return view;
},
});
}
}
-module.exports = router => {
- router.enter(
- ['posts'],
- (ctx, next) => {
- ctx.controller = new PostListController(ctx);
- });
+module.exports = (router) => {
+ router.enter(["posts"], (ctx, next) => {
+ ctx.controller = new PostListController(ctx);
+ });
};
diff --git a/client/js/controllers/post_main_controller.js b/client/js/controllers/post_main_controller.js
index 924e918..95cfdb5 100644
--- a/client/js/controllers/post_main_controller.js
+++ b/client/js/controllers/post_main_controller.js
@@ -1,16 +1,16 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
-const settings = require('../models/settings.js');
-const Comment = require('../models/comment.js');
-const Post = require('../models/post.js');
-const PostList = require('../models/post_list.js');
-const PostMainView = require('../views/post_main_view.js');
-const BasePostController = require('./base_post_controller.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
+const settings = require("../models/settings.js");
+const Comment = require("../models/comment.js");
+const Post = require("../models/post.js");
+const PostList = require("../models/post_list.js");
+const PostMainView = require("../views/post_main_view.js");
+const BasePostController = require("./base_post_controller.js");
+const EmptyView = require("../views/empty_view.js");
class PostMainController extends BasePostController {
constructor(ctx, editMode) {
@@ -21,74 +21,107 @@ class PostMainController extends BasePostController {
Post.get(ctx.parameters.id),
PostList.getAround(
ctx.parameters.id,
- parameters ? parameters.query : null),
- ]).then(responses => {
- const [post, aroundResponse] = responses;
+ parameters ? parameters.query : null
+ ),
+ ]).then(
+ (responses) => {
+ const [post, aroundResponse] = responses;
- // remove junk from query, but save it into history so that it can
- // be still accessed after history navigation / page refresh
- if (parameters.query) {
- ctx.state.parameters = parameters;
- const url = editMode ?
- uri.formatClientLink('post', ctx.parameters.id, 'edit') :
- uri.formatClientLink('post', ctx.parameters.id);
- router.replace(url, ctx.state, false);
- }
+ // remove junk from query, but save it into history so that it can
+ // be still accessed after history navigation / page refresh
+ if (parameters.query) {
+ ctx.state.parameters = parameters;
+ const url = editMode
+ ? uri.formatClientLink(
+ "post",
+ ctx.parameters.id,
+ "edit"
+ )
+ : uri.formatClientLink("post", ctx.parameters.id);
+ router.replace(url, ctx.state, false);
+ }
- this._post = post;
- this._view = new PostMainView({
- post: post,
- editMode: editMode,
- prevPostId: aroundResponse.prev ? aroundResponse.prev.id : null,
- nextPostId: aroundResponse.next ? aroundResponse.next.id : null,
- canEditPosts: api.hasPrivilege('posts:edit'),
- canDeletePosts: api.hasPrivilege('posts:delete'),
- canFeaturePosts: api.hasPrivilege('posts:feature'),
- canListComments: api.hasPrivilege('comments:list'),
- canCreateComments: api.hasPrivilege('comments:create'),
- parameters: parameters,
- });
+ this._post = post;
+ this._view = new PostMainView({
+ post: post,
+ editMode: editMode,
+ prevPostId: aroundResponse.prev
+ ? aroundResponse.prev.id
+ : null,
+ nextPostId: aroundResponse.next
+ ? aroundResponse.next.id
+ : null,
+ canEditPosts: api.hasPrivilege("posts:edit"),
+ canDeletePosts: api.hasPrivilege("posts:delete"),
+ canFeaturePosts: api.hasPrivilege("posts:feature"),
+ canListComments: api.hasPrivilege("comments:list"),
+ canCreateComments: api.hasPrivilege("comments:create"),
+ parameters: parameters,
+ });
- if (this._view.sidebarControl) {
- this._view.sidebarControl.addEventListener(
- 'favorite', e => this._evtFavoritePost(e));
- this._view.sidebarControl.addEventListener(
- 'unfavorite', e => this._evtUnfavoritePost(e));
- this._view.sidebarControl.addEventListener(
- 'score', e => this._evtScorePost(e));
- this._view.sidebarControl.addEventListener(
- 'fitModeChange', e => this._evtFitModeChange(e));
- this._view.sidebarControl.addEventListener(
- 'change', e => this._evtPostChange(e));
- this._view.sidebarControl.addEventListener(
- 'submit', e => this._evtUpdatePost(e));
- this._view.sidebarControl.addEventListener(
- 'feature', e => this._evtFeaturePost(e));
- this._view.sidebarControl.addEventListener(
- 'delete', e => this._evtDeletePost(e));
- this._view.sidebarControl.addEventListener(
- 'merge', e => this._evtMergePost(e));
- }
+ if (this._view.sidebarControl) {
+ this._view.sidebarControl.addEventListener(
+ "favorite",
+ (e) => this._evtFavoritePost(e)
+ );
+ this._view.sidebarControl.addEventListener(
+ "unfavorite",
+ (e) => this._evtUnfavoritePost(e)
+ );
+ this._view.sidebarControl.addEventListener("score", (e) =>
+ this._evtScorePost(e)
+ );
+ this._view.sidebarControl.addEventListener(
+ "fitModeChange",
+ (e) => this._evtFitModeChange(e)
+ );
+ this._view.sidebarControl.addEventListener("change", (e) =>
+ this._evtPostChange(e)
+ );
+ this._view.sidebarControl.addEventListener("submit", (e) =>
+ this._evtUpdatePost(e)
+ );
+ this._view.sidebarControl.addEventListener(
+ "feature",
+ (e) => this._evtFeaturePost(e)
+ );
+ this._view.sidebarControl.addEventListener("delete", (e) =>
+ this._evtDeletePost(e)
+ );
+ this._view.sidebarControl.addEventListener("merge", (e) =>
+ this._evtMergePost(e)
+ );
+ }
- if (this._view.commentControl) {
- this._view.commentControl.addEventListener(
- 'change', e => this._evtCommentChange(e));
- this._view.commentControl.addEventListener(
- 'submit', e => this._evtCreateComment(e));
- }
+ if (this._view.commentControl) {
+ this._view.commentControl.addEventListener("change", (e) =>
+ this._evtCommentChange(e)
+ );
+ this._view.commentControl.addEventListener("submit", (e) =>
+ this._evtCreateComment(e)
+ );
+ }
- if (this._view.commentListControl) {
- this._view.commentListControl.addEventListener(
- 'submit', e => this._evtUpdateComment(e));
- this._view.commentListControl.addEventListener(
- 'score', e => this._evtScoreComment(e));
- this._view.commentListControl.addEventListener(
- 'delete', e => this._evtDeleteComment(e));
+ if (this._view.commentListControl) {
+ this._view.commentListControl.addEventListener(
+ "submit",
+ (e) => this._evtUpdateComment(e)
+ );
+ this._view.commentListControl.addEventListener(
+ "score",
+ (e) => this._evtScoreComment(e)
+ );
+ this._view.commentListControl.addEventListener(
+ "delete",
+ (e) => this._evtDeleteComment(e)
+ );
+ }
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
}
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ );
}
_evtFitModeChange(e) {
@@ -100,32 +133,36 @@ class PostMainController extends BasePostController {
_evtFeaturePost(e) {
this._view.sidebarControl.disableForm();
this._view.sidebarControl.clearMessages();
- e.detail.post.feature()
- .then(() => {
- this._view.sidebarControl.showSuccess('Post featured.');
+ e.detail.post.feature().then(
+ () => {
+ this._view.sidebarControl.showSuccess("Post featured.");
this._view.sidebarControl.enableForm();
- }, error => {
+ },
+ (error) => {
this._view.sidebarControl.showError(error.message);
this._view.sidebarControl.enableForm();
- });
+ }
+ );
}
_evtMergePost(e) {
- router.show(uri.formatClientLink('post', e.detail.post.id, 'merge'));
+ router.show(uri.formatClientLink("post", e.detail.post.id, "merge"));
}
_evtDeletePost(e) {
this._view.sidebarControl.disableForm();
this._view.sidebarControl.clearMessages();
- e.detail.post.delete()
- .then(() => {
+ e.detail.post.delete().then(
+ () => {
misc.disableExitConfirmation();
- const ctx = router.show(uri.formatClientLink('posts'));
- ctx.controller.showSuccess('Post deleted.');
- }, error => {
+ const ctx = router.show(uri.formatClientLink("posts"));
+ ctx.controller.showSuccess("Post deleted.");
+ },
+ (error) => {
this._view.sidebarControl.showError(error.message);
this._view.sidebarControl.enableForm();
- });
+ }
+ );
}
_evtUpdatePost(e) {
@@ -150,15 +187,17 @@ class PostMainController extends BasePostController {
if (e.detail.source !== undefined) {
post.source = e.detail.source;
}
- post.save()
- .then(() => {
- this._view.sidebarControl.showSuccess('Post saved.');
+ post.save().then(
+ () => {
+ this._view.sidebarControl.showSuccess("Post saved.");
this._view.sidebarControl.enableForm();
misc.disableExitConfirmation();
- }, error => {
+ },
+ (error) => {
this._view.sidebarControl.showError(error.message);
this._view.sidebarControl.enableForm();
- });
+ }
+ );
}
_evtPostChange(e) {
@@ -173,79 +212,82 @@ class PostMainController extends BasePostController {
this._view.commentControl.disableForm();
const comment = Comment.create(this._post.id);
comment.text = e.detail.text;
- comment.save()
- .then(() => {
+ comment.save().then(
+ () => {
this._post.comments.add(comment);
this._view.commentControl.exitEditMode();
this._view.commentControl.enableForm();
misc.disableExitConfirmation();
- }, error => {
+ },
+ (error) => {
this._view.commentControl.showError(error.message);
this._view.commentControl.enableForm();
- });
+ }
+ );
}
_evtUpdateComment(e) {
// TODO: disable form
e.detail.comment.text = e.detail.text;
- e.detail.comment.save()
- .catch(error => {
- e.detail.target.showError(error.message);
- // TODO: enable form
- });
+ e.detail.comment.save().catch((error) => {
+ e.detail.target.showError(error.message);
+ // TODO: enable form
+ });
}
_evtScoreComment(e) {
- e.detail.comment.setScore(e.detail.score)
- .catch(error => window.alert(error.message));
+ e.detail.comment
+ .setScore(e.detail.score)
+ .catch((error) => window.alert(error.message));
}
_evtDeleteComment(e) {
- e.detail.comment.delete()
- .catch(error => window.alert(error.message));
+ e.detail.comment
+ .delete()
+ .catch((error) => window.alert(error.message));
}
_evtScorePost(e) {
- if (!api.hasPrivilege('posts:score')) {
+ if (!api.hasPrivilege("posts:score")) {
return;
}
- e.detail.post.setScore(e.detail.score)
- .catch(error => window.alert(error.message));
+ e.detail.post
+ .setScore(e.detail.score)
+ .catch((error) => window.alert(error.message));
}
_evtFavoritePost(e) {
- if (!api.hasPrivilege('posts:favorite')) {
+ if (!api.hasPrivilege("posts:favorite")) {
return;
}
- e.detail.post.addToFavorites()
- .catch(error => window.alert(error.message));
+ e.detail.post
+ .addToFavorites()
+ .catch((error) => window.alert(error.message));
}
_evtUnfavoritePost(e) {
- if (!api.hasPrivilege('posts:favorite')) {
+ if (!api.hasPrivilege("posts:favorite")) {
return;
}
- e.detail.post.removeFromFavorites()
- .catch(error => window.alert(error.message));
+ e.detail.post
+ .removeFromFavorites()
+ .catch((error) => window.alert(error.message));
}
}
-module.exports = router => {
- router.enter(['post', ':id', 'edit'],
- (ctx, next) => {
- // restore parameters from history state
- if (ctx.state.parameters) {
- Object.assign(ctx.parameters, ctx.state.parameters);
- }
- ctx.controller = new PostMainController(ctx, true);
- });
- router.enter(
- ['post', ':id'],
- (ctx, next) => {
- // restore parameters from history state
- if (ctx.state.parameters) {
- Object.assign(ctx.parameters, ctx.state.parameters);
- }
- ctx.controller = new PostMainController(ctx, false);
- });
+module.exports = (router) => {
+ router.enter(["post", ":id", "edit"], (ctx, next) => {
+ // restore parameters from history state
+ if (ctx.state.parameters) {
+ Object.assign(ctx.parameters, ctx.state.parameters);
+ }
+ ctx.controller = new PostMainController(ctx, true);
+ });
+ router.enter(["post", ":id"], (ctx, next) => {
+ // restore parameters from history state
+ if (ctx.state.parameters) {
+ Object.assign(ctx.parameters, ctx.state.parameters);
+ }
+ ctx.controller = new PostMainController(ctx, false);
+ });
};
diff --git a/client/js/controllers/post_upload_controller.js b/client/js/controllers/post_upload_controller.js
index f16aaf0..d317be5 100644
--- a/client/js/controllers/post_upload_controller.js
+++ b/client/js/controllers/post_upload_controller.js
@@ -1,40 +1,40 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const router = require('../router.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
-const progress = require('../util/progress.js');
-const topNavigation = require('../models/top_navigation.js');
-const Post = require('../models/post.js');
-const Tag = require('../models/tag.js');
-const PostUploadView = require('../views/post_upload_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const router = require("../router.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
+const progress = require("../util/progress.js");
+const topNavigation = require("../models/top_navigation.js");
+const Post = require("../models/post.js");
+const Tag = require("../models/tag.js");
+const PostUploadView = require("../views/post_upload_view.js");
+const EmptyView = require("../views/empty_view.js");
const genericErrorMessage =
- 'One of the posts needs your attention; ' +
+ "One of the posts needs your attention; " +
'click "resume upload" when you\'re ready.';
class PostUploadController {
constructor() {
this._lastCancellablePromise = null;
- if (!api.hasPrivilege('posts:create')) {
+ if (!api.hasPrivilege("posts:create")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to upload posts.');
+ this._view.showError("You don't have privileges to upload posts.");
return;
}
- topNavigation.activate('upload');
- topNavigation.setTitle('Upload');
+ topNavigation.activate("upload");
+ topNavigation.setTitle("Upload");
this._view = new PostUploadView({
- canUploadAnonymously: api.hasPrivilege('posts:create:anonymous'),
- canViewPosts: api.hasPrivilege('posts:view'),
+ canUploadAnonymously: api.hasPrivilege("posts:create:anonymous"),
+ canViewPosts: api.hasPrivilege("posts:view"),
enableSafety: api.safetyEnabled(),
});
- this._view.addEventListener('change', e => this._evtChange(e));
- this._view.addEventListener('submit', e => this._evtSubmit(e));
- this._view.addEventListener('cancel', e => this._evtCancel(e));
+ this._view.addEventListener("change", (e) => this._evtChange(e));
+ this._view.addEventListener("submit", (e) => this._evtSubmit(e));
+ this._view.addEventListener("cancel", (e) => this._evtCancel(e));
}
_evtChange(e) {
@@ -56,87 +56,109 @@ class PostUploadController {
this._view.disableForm();
this._view.clearMessages();
- e.detail.uploadables.reduce(
- (promise, uploadable) => promise.then(() => this._uploadSinglePost(
- uploadable, e.detail.skipDuplicates)),
- Promise.resolve())
- .then(() => {
- this._view.clearMessages();
- misc.disableExitConfirmation();
- const ctx = router.show(uri.formatClientLink('posts'));
- ctx.controller.showSuccess('Posts uploaded.');
- }, error => {
- if (error.uploadable) {
- if (error.similarPosts) {
- error.uploadable.lookalikes = error.similarPosts;
- this._view.updateUploadable(error.uploadable);
- this._view.showInfo(genericErrorMessage);
- this._view.showInfo(
- error.message, error.uploadable);
+ e.detail.uploadables
+ .reduce(
+ (promise, uploadable) =>
+ promise.then(() =>
+ this._uploadSinglePost(
+ uploadable,
+ e.detail.skipDuplicates
+ )
+ ),
+ Promise.resolve()
+ )
+ .then(
+ () => {
+ this._view.clearMessages();
+ misc.disableExitConfirmation();
+ const ctx = router.show(uri.formatClientLink("posts"));
+ ctx.controller.showSuccess("Posts uploaded.");
+ },
+ (error) => {
+ if (error.uploadable) {
+ if (error.similarPosts) {
+ error.uploadable.lookalikes = error.similarPosts;
+ this._view.updateUploadable(error.uploadable);
+ this._view.showInfo(genericErrorMessage);
+ this._view.showInfo(
+ error.message,
+ error.uploadable
+ );
+ } else {
+ this._view.showError(genericErrorMessage);
+ this._view.showError(
+ error.message,
+ error.uploadable
+ );
+ }
} else {
- this._view.showError(genericErrorMessage);
- this._view.showError(
- error.message, error.uploadable);
+ this._view.showError(error.message);
}
- } else {
- this._view.showError(error.message);
+ this._view.enableForm();
}
- this._view.enableForm();
- });
+ );
}
_uploadSinglePost(uploadable, skipDuplicates) {
progress.start();
let reverseSearchPromise = Promise.resolve();
if (!uploadable.lookalikesConfirmed) {
- reverseSearchPromise =
- Post.reverseSearch(uploadable.url || uploadable.file);
+ reverseSearchPromise = Post.reverseSearch(
+ uploadable.url || uploadable.file
+ );
}
this._lastCancellablePromise = reverseSearchPromise;
- return reverseSearchPromise.then(searchResult => {
- if (searchResult) {
- // notify about exact duplicate
- if (searchResult.exactPost) {
- if (skipDuplicates) {
- this._view.removeUploadable(uploadable);
- return Promise.resolve();
- } else {
- let error = new Error('Post already uploaded ' +
- `(@${searchResult.exactPost.id})`);
+ return reverseSearchPromise
+ .then((searchResult) => {
+ if (searchResult) {
+ // notify about exact duplicate
+ if (searchResult.exactPost) {
+ if (skipDuplicates) {
+ this._view.removeUploadable(uploadable);
+ return Promise.resolve();
+ } else {
+ let error = new Error(
+ "Post already uploaded " +
+ `(@${searchResult.exactPost.id})`
+ );
+ error.uploadable = uploadable;
+ return Promise.reject(error);
+ }
+ }
+
+ // notify about similar posts
+ if (searchResult.similarPosts.length) {
+ let error = new Error(
+ `Found ${searchResult.similarPosts.length} similar ` +
+ "posts.\nYou can resume or discard this upload."
+ );
error.uploadable = uploadable;
+ error.similarPosts = searchResult.similarPosts;
return Promise.reject(error);
}
}
- // notify about similar posts
- if (searchResult.similarPosts.length) {
- let error = new Error(
- `Found ${searchResult.similarPosts.length} similar ` +
- 'posts.\nYou can resume or discard this upload.');
- error.uploadable = uploadable;
- error.similarPosts = searchResult.similarPosts;
- return Promise.reject(error);
- }
- }
-
- // no duplicates, proceed with saving
- let post = this._uploadableToPost(uploadable);
- let savePromise = post.save(uploadable.anonymous)
- .then(() => {
+ // no duplicates, proceed with saving
+ let post = this._uploadableToPost(uploadable);
+ let savePromise = post.save(uploadable.anonymous).then(() => {
this._view.removeUploadable(uploadable);
return Promise.resolve();
});
- this._lastCancellablePromise = savePromise;
- return savePromise;
- }).then(result => {
- progress.done();
- return Promise.resolve(result);
- }, error => {
- error.uploadable = uploadable;
- progress.done();
- return Promise.reject(error);
- });
+ this._lastCancellablePromise = savePromise;
+ return savePromise;
+ })
+ .then(
+ (result) => {
+ progress.done();
+ return Promise.resolve(result);
+ },
+ (error) => {
+ error.uploadable = uploadable;
+ progress.done();
+ return Promise.reject(error);
+ }
+ );
}
_uploadableToPost(uploadable) {
@@ -159,8 +181,8 @@ class PostUploadController {
}
}
-module.exports = router => {
- router.enter(['upload'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["upload"], (ctx, next) => {
ctx.controller = new PostUploadController();
});
};
diff --git a/client/js/controllers/settings_controller.js b/client/js/controllers/settings_controller.js
index 7765143..8cf2c1c 100644
--- a/client/js/controllers/settings_controller.js
+++ b/client/js/controllers/settings_controller.js
@@ -1,28 +1,28 @@
-'use strict';
+"use strict";
-const settings = require('../models/settings.js');
-const topNavigation = require('../models/top_navigation.js');
-const SettingsView = require('../views/settings_view.js');
+const settings = require("../models/settings.js");
+const topNavigation = require("../models/top_navigation.js");
+const SettingsView = require("../views/settings_view.js");
class SettingsController {
constructor() {
- topNavigation.activate('settings');
- topNavigation.setTitle('Browsing settings');
+ topNavigation.activate("settings");
+ topNavigation.setTitle("Browsing settings");
this._view = new SettingsView({
settings: settings.get(),
});
- this._view.addEventListener('submit', e => this._evtSubmit(e));
+ this._view.addEventListener("submit", (e) => this._evtSubmit(e));
}
_evtSubmit(e) {
this._view.clearMessages();
settings.save(e.detail);
- this._view.showSuccess('Settings saved.');
+ this._view.showSuccess("Settings saved.");
}
}
-module.exports = router => {
- router.enter(['settings'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["settings"], (ctx, next) => {
ctx.controller = new SettingsController();
});
};
diff --git a/client/js/controllers/snapshots_controller.js b/client/js/controllers/snapshots_controller.js
index 0e9b773..120b6cb 100644
--- a/client/js/controllers/snapshots_controller.js
+++ b/client/js/controllers/snapshots_controller.js
@@ -1,41 +1,43 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const SnapshotList = require('../models/snapshot_list.js');
-const PageController = require('../controllers/page_controller.js');
-const topNavigation = require('../models/top_navigation.js');
-const SnapshotsPageView = require('../views/snapshots_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const SnapshotList = require("../models/snapshot_list.js");
+const PageController = require("../controllers/page_controller.js");
+const topNavigation = require("../models/top_navigation.js");
+const SnapshotsPageView = require("../views/snapshots_page_view.js");
+const EmptyView = require("../views/empty_view.js");
class SnapshotsController {
constructor(ctx) {
- if (!api.hasPrivilege('snapshots:list')) {
+ if (!api.hasPrivilege("snapshots:list")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view history.');
+ this._view.showError("You don't have privileges to view history.");
return;
}
- topNavigation.activate('');
- topNavigation.setTitle('History');
+ topNavigation.activate("");
+ topNavigation.setTitle("History");
this._pageController = new PageController();
this._pageController.run({
parameters: ctx.parameters,
defaultLimit: 25,
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('history', parameters);
+ const parameters = Object.assign({}, ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("history", parameters);
},
requestPage: (offset, limit) => {
- return SnapshotList.search('', offset, limit);
+ return SnapshotList.search("", offset, limit);
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
Object.assign(pageCtx, {
- canViewPosts: api.hasPrivilege('posts:view'),
- canViewUsers: api.hasPrivilege('users:view'),
- canViewTags: api.hasPrivilege('tags:view'),
+ canViewPosts: api.hasPrivilege("posts:view"),
+ canViewUsers: api.hasPrivilege("users:view"),
+ canViewTags: api.hasPrivilege("tags:view"),
});
return new SnapshotsPageView(pageCtx);
},
@@ -43,9 +45,8 @@ class SnapshotsController {
}
}
-module.exports = router => {
- router.enter(['history'],
- (ctx, next) => {
- ctx.controller = new SnapshotsController(ctx);
- });
+module.exports = (router) => {
+ router.enter(["history"], (ctx, next) => {
+ ctx.controller = new SnapshotsController(ctx);
+ });
};
diff --git a/client/js/controllers/tag_categories_controller.js b/client/js/controllers/tag_categories_controller.js
index 49600cf..2470edb 100644
--- a/client/js/controllers/tag_categories_controller.js
+++ b/client/js/controllers/tag_categories_controller.js
@@ -1,57 +1,67 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const tags = require('../tags.js');
-const TagCategoryList = require('../models/tag_category_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const TagCategoriesView = require('../views/tag_categories_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const tags = require("../tags.js");
+const TagCategoryList = require("../models/tag_category_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const TagCategoriesView = require("../views/tag_categories_view.js");
+const EmptyView = require("../views/empty_view.js");
class TagCategoriesController {
constructor() {
- if (!api.hasPrivilege('tagCategories:list')) {
+ if (!api.hasPrivilege("tagCategories:list")) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to view tag categories.');
+ "You don't have privileges to view tag categories."
+ );
return;
}
- topNavigation.activate('tags');
- topNavigation.setTitle('Listing tags');
- TagCategoryList.get().then(response => {
- this._tagCategories = response.results;
- this._view = new TagCategoriesView({
- tagCategories: this._tagCategories,
- canEditName: api.hasPrivilege('tagCategories:edit:name'),
- canEditColor: api.hasPrivilege('tagCategories:edit:color'),
- canDelete: api.hasPrivilege('tagCategories:delete'),
- canCreate: api.hasPrivilege('tagCategories:create'),
- canSetDefault: api.hasPrivilege('tagCategories:setDefault'),
- });
- this._view.addEventListener('submit', e => this._evtSubmit(e));
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ topNavigation.activate("tags");
+ topNavigation.setTitle("Listing tags");
+ TagCategoryList.get().then(
+ (response) => {
+ this._tagCategories = response.results;
+ this._view = new TagCategoriesView({
+ tagCategories: this._tagCategories,
+ canEditName: api.hasPrivilege("tagCategories:edit:name"),
+ canEditColor: api.hasPrivilege("tagCategories:edit:color"),
+ canDelete: api.hasPrivilege("tagCategories:delete"),
+ canCreate: api.hasPrivilege("tagCategories:create"),
+ canSetDefault: api.hasPrivilege(
+ "tagCategories:setDefault"
+ ),
+ });
+ this._view.addEventListener("submit", (e) =>
+ this._evtSubmit(e)
+ );
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
_evtSubmit(e) {
this._view.clearMessages();
this._view.disableForm();
- this._tagCategories.save()
- .then(() => {
+ this._tagCategories.save().then(
+ () => {
tags.refreshCategoryColorMap();
this._view.enableForm();
- this._view.showSuccess('Changes saved.');
- }, error => {
+ this._view.showSuccess("Changes saved.");
+ },
+ (error) => {
this._view.enableForm();
this._view.showError(error.message);
- });
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['tag-categories'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["tag-categories"], (ctx, next) => {
ctx.controller = new TagCategoriesController(ctx, next);
});
};
diff --git a/client/js/controllers/tag_controller.js b/client/js/controllers/tag_controller.js
index 71405dc..0928b3f 100644
--- a/client/js/controllers/tag_controller.js
+++ b/client/js/controllers/tag_controller.js
@@ -1,63 +1,80 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const uri = require('../util/uri.js');
-const Tag = require('../models/tag.js');
-const TagCategoryList = require('../models/tag_category_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const TagView = require('../views/tag_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const uri = require("../util/uri.js");
+const Tag = require("../models/tag.js");
+const TagCategoryList = require("../models/tag_category_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const TagView = require("../views/tag_view.js");
+const EmptyView = require("../views/empty_view.js");
class TagController {
constructor(ctx, section) {
- if (!api.hasPrivilege('tags:view')) {
+ if (!api.hasPrivilege("tags:view")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view tags.');
+ this._view.showError("You don't have privileges to view tags.");
return;
}
Promise.all([
TagCategoryList.get(),
Tag.get(ctx.parameters.name),
- ]).then(responses => {
- const [tagCategoriesResponse, tag] = responses;
+ ]).then(
+ (responses) => {
+ const [tagCategoriesResponse, tag] = responses;
- topNavigation.activate('tags');
- topNavigation.setTitle('Tag #' + tag.names[0]);
+ topNavigation.activate("tags");
+ topNavigation.setTitle("Tag #" + tag.names[0]);
- this._name = ctx.parameters.name;
- tag.addEventListener('change', e => this._evtSaved(e, section));
+ this._name = ctx.parameters.name;
+ tag.addEventListener("change", (e) =>
+ this._evtSaved(e, section)
+ );
- const categories = {};
- for (let category of tagCategoriesResponse.results) {
- categories[category.name] = category.name;
- }
+ const categories = {};
+ for (let category of tagCategoriesResponse.results) {
+ categories[category.name] = category.name;
+ }
- this._view = new TagView({
- tag: tag,
- section: section,
- canEditAnything: api.hasPrivilege('tags:edit'),
- canEditNames: api.hasPrivilege('tags:edit:names'),
- canEditCategory: api.hasPrivilege('tags:edit:category'),
- canEditImplications: api.hasPrivilege('tags:edit:implications'),
- canEditSuggestions: api.hasPrivilege('tags:edit:suggestions'),
- canEditDescription: api.hasPrivilege('tags:edit:description'),
- canMerge: api.hasPrivilege('tags:merge'),
- canDelete: api.hasPrivilege('tags:delete'),
- categories: categories,
- escapeColons: uri.escapeColons,
- });
+ this._view = new TagView({
+ tag: tag,
+ section: section,
+ canEditAnything: api.hasPrivilege("tags:edit"),
+ canEditNames: api.hasPrivilege("tags:edit:names"),
+ canEditCategory: api.hasPrivilege("tags:edit:category"),
+ canEditImplications: api.hasPrivilege(
+ "tags:edit:implications"
+ ),
+ canEditSuggestions: api.hasPrivilege(
+ "tags:edit:suggestions"
+ ),
+ canEditDescription: api.hasPrivilege(
+ "tags:edit:description"
+ ),
+ canMerge: api.hasPrivilege("tags:merge"),
+ canDelete: api.hasPrivilege("tags:delete"),
+ categories: categories,
+ escapeColons: uri.escapeColons,
+ });
- this._view.addEventListener('change', e => this._evtChange(e));
- this._view.addEventListener('submit', e => this._evtUpdate(e));
- this._view.addEventListener('merge', e => this._evtMerge(e));
- this._view.addEventListener('delete', e => this._evtDelete(e));
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ this._view.addEventListener("change", (e) =>
+ this._evtChange(e)
+ );
+ this._view.addEventListener("submit", (e) =>
+ this._evtUpdate(e)
+ );
+ this._view.addEventListener("merge", (e) => this._evtMerge(e));
+ this._view.addEventListener("delete", (e) =>
+ this._evtDelete(e)
+ );
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
+ }
+ );
}
_evtChange(e) {
@@ -68,9 +85,10 @@ class TagController {
misc.disableExitConfirmation();
if (this._name !== e.detail.tag.names[0]) {
router.replace(
- uri.formatClientLink('tag', e.detail.tag.names[0], section),
+ uri.formatClientLink("tag", e.detail.tag.names[0], section),
null,
- false);
+ false
+ );
}
}
@@ -86,59 +104,69 @@ class TagController {
if (e.detail.description !== undefined) {
e.detail.tag.description = e.detail.description;
}
- e.detail.tag.save().then(() => {
- this._view.showSuccess('Tag saved.');
- this._view.enableForm();
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ e.detail.tag.save().then(
+ () => {
+ this._view.showSuccess("Tag saved.");
+ this._view.enableForm();
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
_evtMerge(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.tag
- .merge(e.detail.targetTagName, e.detail.addAlias)
- .then(() => {
- this._view.showSuccess('Tag merged.');
+ e.detail.tag.merge(e.detail.targetTagName, e.detail.addAlias).then(
+ () => {
+ this._view.showSuccess("Tag merged.");
this._view.enableForm();
router.replace(
uri.formatClientLink(
- 'tag', e.detail.targetTagName, 'merge'),
+ "tag",
+ e.detail.targetTagName,
+ "merge"
+ ),
null,
- false);
- }, error => {
+ false
+ );
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
_evtDelete(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.tag.delete()
- .then(() => {
- const ctx = router.show(uri.formatClientLink('tags'));
- ctx.controller.showSuccess('Tag deleted.');
- }, error => {
+ e.detail.tag.delete().then(
+ () => {
+ const ctx = router.show(uri.formatClientLink("tags"));
+ ctx.controller.showSuccess("Tag deleted.");
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['tag', ':name', 'edit'], (ctx, next) => {
- ctx.controller = new TagController(ctx, 'edit');
+module.exports = (router) => {
+ router.enter(["tag", ":name", "edit"], (ctx, next) => {
+ ctx.controller = new TagController(ctx, "edit");
});
- router.enter(['tag', ':name', 'merge'], (ctx, next) => {
- ctx.controller = new TagController(ctx, 'merge');
+ router.enter(["tag", ":name", "merge"], (ctx, next) => {
+ ctx.controller = new TagController(ctx, "merge");
});
- router.enter(['tag', ':name', 'delete'], (ctx, next) => {
- ctx.controller = new TagController(ctx, 'delete');
+ router.enter(["tag", ":name", "delete"], (ctx, next) => {
+ ctx.controller = new TagController(ctx, "delete");
});
- router.enter(['tag', ':name'], (ctx, next) => {
- ctx.controller = new TagController(ctx, 'summary');
+ router.enter(["tag", ":name"], (ctx, next) => {
+ ctx.controller = new TagController(ctx, "summary");
});
};
diff --git a/client/js/controllers/tag_list_controller.js b/client/js/controllers/tag_list_controller.js
index 34ff8b2..010c556 100644
--- a/client/js/controllers/tag_list_controller.js
+++ b/client/js/controllers/tag_list_controller.js
@@ -1,46 +1,47 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const TagList = require('../models/tag_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PageController = require('../controllers/page_controller.js');
-const TagsHeaderView = require('../views/tags_header_view.js');
-const TagsPageView = require('../views/tags_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const TagList = require("../models/tag_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PageController = require("../controllers/page_controller.js");
+const TagsHeaderView = require("../views/tags_header_view.js");
+const TagsPageView = require("../views/tags_page_view.js");
+const EmptyView = require("../views/empty_view.js");
const fields = [
- 'names',
- 'suggestions',
- 'implications',
- 'creationTime',
- 'usages',
- 'category'
+ "names",
+ "suggestions",
+ "implications",
+ "creationTime",
+ "usages",
+ "category",
];
class TagListController {
constructor(ctx) {
this._pageController = new PageController();
- if (!api.hasPrivilege('tags:list')) {
+ if (!api.hasPrivilege("tags:list")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view tags.');
+ this._view.showError("You don't have privileges to view tags.");
return;
}
this._ctx = ctx;
- topNavigation.activate('tags');
- topNavigation.setTitle('Listing tags');
+ topNavigation.activate("tags");
+ topNavigation.setTitle("Listing tags");
this._headerView = new TagsHeaderView({
hostNode: this._pageController.view.pageHeaderHolderNode,
parameters: ctx.parameters,
- canEditTagCategories: api.hasPrivilege('tagCategories:edit'),
+ canEditTagCategories: api.hasPrivilege("tagCategories:edit"),
});
- this._headerView.addEventListener(
- 'navigate', e => this._evtNavigate(e));
+ this._headerView.addEventListener("navigate", (e) =>
+ this._evtNavigate(e)
+ );
this._syncPageController();
}
@@ -55,7 +56,8 @@ class TagListController {
_evtNavigate(e) {
router.showNoDispatch(
- uri.formatClientLink('tags', e.detail.parameters));
+ uri.formatClientLink("tags", e.detail.parameters)
+ );
Object.assign(this._ctx.parameters, e.detail.parameters);
this._syncPageController();
}
@@ -65,25 +67,29 @@ class TagListController {
parameters: this._ctx.parameters,
defaultLimit: 50,
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, this._ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('tags', parameters);
+ const parameters = Object.assign({}, this._ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("tags", parameters);
},
requestPage: (offset, limit) => {
return TagList.search(
- this._ctx.parameters.query, offset, limit, fields);
+ this._ctx.parameters.query,
+ offset,
+ limit,
+ fields
+ );
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
return new TagsPageView(pageCtx);
},
});
}
}
-module.exports = router => {
- router.enter(
- ['tags'],
- (ctx, next) => {
- ctx.controller = new TagListController(ctx);
- });
+module.exports = (router) => {
+ router.enter(["tags"], (ctx, next) => {
+ ctx.controller = new TagListController(ctx);
+ });
};
diff --git a/client/js/controllers/top_navigation_controller.js b/client/js/controllers/top_navigation_controller.js
index 9cd70c1..d9bb276 100644
--- a/client/js/controllers/top_navigation_controller.js
+++ b/client/js/controllers/top_navigation_controller.js
@@ -1,19 +1,20 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const topNavigation = require('../models/top_navigation.js');
-const TopNavigationView = require('../views/top_navigation_view.js');
+const api = require("../api.js");
+const topNavigation = require("../models/top_navigation.js");
+const TopNavigationView = require("../views/top_navigation_view.js");
class TopNavigationController {
constructor() {
api.fetchConfig().then(() => {
this._topNavigationView = new TopNavigationView();
- topNavigation.addEventListener(
- 'activate', e => this._evtActivate(e));
+ topNavigation.addEventListener("activate", (e) =>
+ this._evtActivate(e)
+ );
- api.addEventListener('login', e => this._evtAuthChange(e));
- api.addEventListener('logout', e => this._evtAuthChange(e));
+ api.addEventListener("login", (e) => this._evtAuthChange(e));
+ api.addEventListener("logout", (e) => this._evtAuthChange(e));
this._render();
});
@@ -28,37 +29,38 @@ class TopNavigationController {
}
_updateNavigationFromPrivileges() {
- topNavigation.get('account').url = 'user/' + api.userName;
- topNavigation.get('account').imageUrl =
- api.user ? api.user.avatarUrl : null;
+ topNavigation.get("account").url = "user/" + api.userName;
+ topNavigation.get("account").imageUrl = api.user
+ ? api.user.avatarUrl
+ : null;
topNavigation.showAll();
- if (!api.hasPrivilege('posts:list')) {
- topNavigation.hide('posts');
+ if (!api.hasPrivilege("posts:list")) {
+ topNavigation.hide("posts");
}
- if (!api.hasPrivilege('posts:create')) {
- topNavigation.hide('upload');
+ if (!api.hasPrivilege("posts:create")) {
+ topNavigation.hide("upload");
}
- if (!api.hasPrivilege('comments:list')) {
- topNavigation.hide('comments');
+ if (!api.hasPrivilege("comments:list")) {
+ topNavigation.hide("comments");
}
- if (!api.hasPrivilege('tags:list')) {
- topNavigation.hide('tags');
+ if (!api.hasPrivilege("tags:list")) {
+ topNavigation.hide("tags");
}
- if (!api.hasPrivilege('users:list')) {
- topNavigation.hide('users');
+ if (!api.hasPrivilege("users:list")) {
+ topNavigation.hide("users");
}
if (api.isLoggedIn()) {
- if (!api.hasPrivilege('users:create:any')) {
- topNavigation.hide('register');
+ if (!api.hasPrivilege("users:create:any")) {
+ topNavigation.hide("register");
}
- topNavigation.hide('login');
+ topNavigation.hide("login");
} else {
- if (!api.hasPrivilege('users:create:self')) {
- topNavigation.hide('register');
+ if (!api.hasPrivilege("users:create:self")) {
+ topNavigation.hide("register");
}
- topNavigation.hide('account');
- topNavigation.hide('logout');
+ topNavigation.hide("account");
+ topNavigation.hide("logout");
}
}
@@ -66,10 +68,11 @@ class TopNavigationController {
this._updateNavigationFromPrivileges();
this._topNavigationView.render({
items: topNavigation.getAll(),
- name: api.getName()
+ name: api.getName(),
});
this._topNavigationView.activate(
- topNavigation.activeItem ? topNavigation.activeItem.key : '');
+ topNavigation.activeItem ? topNavigation.activeItem.key : ""
+ );
}
}
diff --git a/client/js/controllers/user_controller.js b/client/js/controllers/user_controller.js
index e192d87..326736b 100644
--- a/client/js/controllers/user_controller.js
+++ b/client/js/controllers/user_controller.js
@@ -1,23 +1,25 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const User = require('../models/user.js');
-const UserToken = require('../models/user_token.js');
-const topNavigation = require('../models/top_navigation.js');
-const UserView = require('../views/user_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const User = require("../models/user.js");
+const UserToken = require("../models/user_token.js");
+const topNavigation = require("../models/top_navigation.js");
+const UserView = require("../views/user_view.js");
+const EmptyView = require("../views/empty_view.js");
class UserController {
constructor(ctx, section) {
const userName = ctx.parameters.name;
- if (!api.hasPrivilege('users:view') &&
- !api.isLoggedIn({name: userName})) {
+ if (
+ !api.hasPrivilege("users:view") &&
+ !api.isLoggedIn({ name: userName })
+ ) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view users.');
+ this._view.showError("You don't have privileges to view users.");
return;
}
@@ -25,100 +27,129 @@ class UserController {
this._errorMessages = [];
let userTokenPromise = Promise.resolve([]);
- if (section === 'list-tokens') {
- userTokenPromise = UserToken.get(userName)
- .then(userTokens => {
- return userTokens.map(token => {
- token.isCurrentAuthToken = api.isCurrentAuthToken(token);
+ if (section === "list-tokens") {
+ userTokenPromise = UserToken.get(userName).then(
+ (userTokens) => {
+ return userTokens.map((token) => {
+ token.isCurrentAuthToken = api.isCurrentAuthToken(
+ token
+ );
return token;
});
- }, error => {
+ },
+ (error) => {
return [];
- });
+ }
+ );
}
- topNavigation.setTitle('User ' + userName);
- Promise.all([
- userTokenPromise,
- User.get(userName)
- ]).then(responses => {
- const [userTokens, user] = responses;
- const isLoggedIn = api.isLoggedIn(user);
- const infix = isLoggedIn ? 'self' : 'any';
+ topNavigation.setTitle("User " + userName);
+ Promise.all([userTokenPromise, User.get(userName)]).then(
+ (responses) => {
+ const [userTokens, user] = responses;
+ const isLoggedIn = api.isLoggedIn(user);
+ const infix = isLoggedIn ? "self" : "any";
- this._name = userName;
- user.addEventListener('change', e => this._evtSaved(e, section));
+ this._name = userName;
+ user.addEventListener("change", (e) =>
+ this._evtSaved(e, section)
+ );
- const myRankIndex = api.user ?
- api.allRanks.indexOf(api.user.rank) :
- 0;
- let ranks = {};
- for (let [rankIdx, rankIdentifier] of api.allRanks.entries()) {
- if (rankIdentifier === 'anonymous') {
- continue;
+ const myRankIndex = api.user
+ ? api.allRanks.indexOf(api.user.rank)
+ : 0;
+ let ranks = {};
+ for (let [rankIdx, rankIdentifier] of api.allRanks.entries()) {
+ if (rankIdentifier === "anonymous") {
+ continue;
+ }
+ if (rankIdx > myRankIndex) {
+ continue;
+ }
+ ranks[rankIdentifier] = api.rankNames.get(rankIdentifier);
}
- if (rankIdx > myRankIndex) {
- continue;
- }
- ranks[rankIdentifier] = api.rankNames.get(rankIdentifier);
- }
- if (isLoggedIn) {
- topNavigation.activate('account');
- } else {
- topNavigation.activate('users');
- }
+ if (isLoggedIn) {
+ topNavigation.activate("account");
+ } else {
+ topNavigation.activate("users");
+ }
- this._view = new UserView({
- user: user,
- section: section,
- isLoggedIn: isLoggedIn,
- canEditName: api.hasPrivilege(`users:edit:${infix}:name`),
- canEditPassword: api.hasPrivilege(`users:edit:${infix}:pass`),
- canEditEmail: api.hasPrivilege(`users:edit:${infix}:email`),
- canEditRank: api.hasPrivilege(`users:edit:${infix}:rank`),
- canEditAvatar: api.hasPrivilege(`users:edit:${infix}:avatar`),
- canEditAnything: api.hasPrivilege(`users:edit:${infix}`),
- canListTokens: api.hasPrivilege(`userTokens:list:${infix}`),
- canCreateToken: api.hasPrivilege(`userTokens:create:${infix}`),
- canEditToken: api.hasPrivilege(`userTokens:edit:${infix}`),
- canDeleteToken: api.hasPrivilege(`userTokens:delete:${infix}`),
- canDelete: api.hasPrivilege(`users:delete:${infix}`),
- ranks: ranks,
- tokens: userTokens,
- });
- this._view.addEventListener('change', e => this._evtChange(e));
- this._view.addEventListener('submit', e => this._evtUpdate(e));
- this._view.addEventListener('delete', e => this._evtDelete(e));
- this._view.addEventListener('create-token', e => this._evtCreateToken(e));
- this._view.addEventListener('delete-token', e => this._evtDeleteToken(e));
- this._view.addEventListener('update-token', e => this._evtUpdateToken(e));
+ this._view = new UserView({
+ user: user,
+ section: section,
+ isLoggedIn: isLoggedIn,
+ canEditName: api.hasPrivilege(`users:edit:${infix}:name`),
+ canEditPassword: api.hasPrivilege(
+ `users:edit:${infix}:pass`
+ ),
+ canEditEmail: api.hasPrivilege(
+ `users:edit:${infix}:email`
+ ),
+ canEditRank: api.hasPrivilege(`users:edit:${infix}:rank`),
+ canEditAvatar: api.hasPrivilege(
+ `users:edit:${infix}:avatar`
+ ),
+ canEditAnything: api.hasPrivilege(`users:edit:${infix}`),
+ canListTokens: api.hasPrivilege(
+ `userTokens:list:${infix}`
+ ),
+ canCreateToken: api.hasPrivilege(
+ `userTokens:create:${infix}`
+ ),
+ canEditToken: api.hasPrivilege(`userTokens:edit:${infix}`),
+ canDeleteToken: api.hasPrivilege(
+ `userTokens:delete:${infix}`
+ ),
+ canDelete: api.hasPrivilege(`users:delete:${infix}`),
+ ranks: ranks,
+ tokens: userTokens,
+ });
+ this._view.addEventListener("change", (e) =>
+ this._evtChange(e)
+ );
+ this._view.addEventListener("submit", (e) =>
+ this._evtUpdate(e)
+ );
+ this._view.addEventListener("delete", (e) =>
+ this._evtDelete(e)
+ );
+ this._view.addEventListener("create-token", (e) =>
+ this._evtCreateToken(e)
+ );
+ this._view.addEventListener("delete-token", (e) =>
+ this._evtDeleteToken(e)
+ );
+ this._view.addEventListener("update-token", (e) =>
+ this._evtUpdateToken(e)
+ );
- for (let message of this._successMessages) {
- this.showSuccess(message);
- }
+ for (let message of this._successMessages) {
+ this.showSuccess(message);
+ }
- for (let message of this._errorMessages) {
- this.showError(message);
+ for (let message of this._errorMessages) {
+ this.showError(message);
+ }
+ },
+ (error) => {
+ this._view = new EmptyView();
+ this._view.showError(error.message);
}
-
- }, error => {
- this._view = new EmptyView();
- this._view.showError(error.message);
- });
+ );
}
showSuccess(message) {
- if (typeof this._view === 'undefined') {
- this._successMessages.push(message)
+ if (typeof this._view === "undefined") {
+ this._successMessages.push(message);
} else {
this._view.showSuccess(message);
}
}
showError(message) {
- if (typeof this._view === 'undefined') {
- this._errorMessages.push(message)
+ if (typeof this._view === "undefined") {
+ this._errorMessages.push(message);
} else {
this._view.showError(message);
}
@@ -132,9 +163,10 @@ class UserController {
misc.disableExitConfirmation();
if (this._name !== e.detail.user.name) {
router.replace(
- uri.formatClientLink('user', e.detail.user.name, section),
+ uri.formatClientLink("user", e.detail.user.name, section),
null,
- false);
+ false
+ );
}
}
@@ -142,7 +174,7 @@ class UserController {
this._view.clearMessages();
this._view.disableForm();
const isLoggedIn = api.isLoggedIn(e.detail.user);
- const infix = isLoggedIn ? 'self' : 'any';
+ const infix = isLoggedIn ? "self" : "any";
if (e.detail.name !== undefined) {
e.detail.user.name = e.detail.name;
@@ -165,72 +197,105 @@ class UserController {
}
}
- e.detail.user.save().then(() => {
- return isLoggedIn ?
- api.login(
- e.detail.name || api.userName,
- e.detail.password || api.userPassword,
- false) :
- Promise.resolve();
- }).then(() => {
- this._view.showSuccess('Settings updated.');
- this._view.enableForm();
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ e.detail.user
+ .save()
+ .then(() => {
+ return isLoggedIn
+ ? api.login(
+ e.detail.name || api.userName,
+ e.detail.password || api.userPassword,
+ false
+ )
+ : Promise.resolve();
+ })
+ .then(
+ () => {
+ this._view.showSuccess("Settings updated.");
+ this._view.enableForm();
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
_evtDelete(e) {
this._view.clearMessages();
this._view.disableForm();
const isLoggedIn = api.isLoggedIn(e.detail.user);
- e.detail.user.delete()
- .then(() => {
+ e.detail.user.delete().then(
+ () => {
if (isLoggedIn) {
api.forget();
api.logout();
}
- if (api.hasPrivilege('users:list')) {
- const ctx = router.show(uri.formatClientLink('users'));
- ctx.controller.showSuccess('Account deleted.');
+ if (api.hasPrivilege("users:list")) {
+ const ctx = router.show(uri.formatClientLink("users"));
+ ctx.controller.showSuccess("Account deleted.");
} else {
const ctx = router.show(uri.formatClientLink());
- ctx.controller.showSuccess('Account deleted.');
+ ctx.controller.showSuccess("Account deleted.");
}
- }, error => {
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
_evtCreateToken(e) {
this._view.clearMessages();
this._view.disableForm();
- UserToken.create(e.detail.user.name, e.detail.note, e.detail.expirationTime)
- .then(response => {
- const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
- ctx.controller.showSuccess('Token ' + response.token + ' created.');
- }, error => {
+ UserToken.create(
+ e.detail.user.name,
+ e.detail.note,
+ e.detail.expirationTime
+ ).then(
+ (response) => {
+ const ctx = router.show(
+ uri.formatClientLink(
+ "user",
+ e.detail.user.name,
+ "list-tokens"
+ )
+ );
+ ctx.controller.showSuccess(
+ "Token " + response.token + " created."
+ );
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
_evtDeleteToken(e) {
this._view.clearMessages();
this._view.disableForm();
if (api.isCurrentAuthToken(e.detail.userToken)) {
- router.show(uri.formatClientLink('logout'));
+ router.show(uri.formatClientLink("logout"));
} else {
- e.detail.userToken.delete(e.detail.user.name)
- .then(() => {
- const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
- ctx.controller.showSuccess('Token ' + e.detail.userToken.token + ' deleted.');
- }, error => {
+ e.detail.userToken.delete(e.detail.user.name).then(
+ () => {
+ const ctx = router.show(
+ uri.formatClientLink(
+ "user",
+ e.detail.user.name,
+ "list-tokens"
+ )
+ );
+ ctx.controller.showSuccess(
+ "Token " + e.detail.userToken.token + " deleted."
+ );
+ },
+ (error) => {
this._view.showError(error.message);
this._view.enableForm();
- });
+ }
+ );
}
}
@@ -242,27 +307,38 @@ class UserController {
e.detail.userToken.note = e.detail.note;
}
- e.detail.userToken.save(e.detail.user.name).then(response => {
- const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
- ctx.controller.showSuccess('Token ' + response.token + ' updated.');
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ e.detail.userToken.save(e.detail.user.name).then(
+ (response) => {
+ const ctx = router.show(
+ uri.formatClientLink(
+ "user",
+ e.detail.user.name,
+ "list-tokens"
+ )
+ );
+ ctx.controller.showSuccess(
+ "Token " + response.token + " updated."
+ );
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['user', ':name'], (ctx, next) => {
- ctx.controller = new UserController(ctx, 'summary');
+module.exports = (router) => {
+ router.enter(["user", ":name"], (ctx, next) => {
+ ctx.controller = new UserController(ctx, "summary");
});
- router.enter(['user', ':name', 'edit'], (ctx, next) => {
- ctx.controller = new UserController(ctx, 'edit');
+ router.enter(["user", ":name", "edit"], (ctx, next) => {
+ ctx.controller = new UserController(ctx, "edit");
});
- router.enter(['user', ':name', 'list-tokens'], (ctx, next) => {
- ctx.controller = new UserController(ctx, 'list-tokens');
+ router.enter(["user", ":name", "list-tokens"], (ctx, next) => {
+ ctx.controller = new UserController(ctx, "list-tokens");
});
- router.enter(['user', ':name', 'delete'], (ctx, next) => {
- ctx.controller = new UserController(ctx, 'delete');
+ router.enter(["user", ":name", "delete"], (ctx, next) => {
+ ctx.controller = new UserController(ctx, "delete");
});
};
diff --git a/client/js/controllers/user_list_controller.js b/client/js/controllers/user_list_controller.js
index 9860de4..d6c4fe5 100644
--- a/client/js/controllers/user_list_controller.js
+++ b/client/js/controllers/user_list_controller.js
@@ -1,27 +1,27 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const router = require('../router.js');
-const uri = require('../util/uri.js');
-const UserList = require('../models/user_list.js');
-const topNavigation = require('../models/top_navigation.js');
-const PageController = require('../controllers/page_controller.js');
-const UsersHeaderView = require('../views/users_header_view.js');
-const UsersPageView = require('../views/users_page_view.js');
-const EmptyView = require('../views/empty_view.js');
+const api = require("../api.js");
+const router = require("../router.js");
+const uri = require("../util/uri.js");
+const UserList = require("../models/user_list.js");
+const topNavigation = require("../models/top_navigation.js");
+const PageController = require("../controllers/page_controller.js");
+const UsersHeaderView = require("../views/users_header_view.js");
+const UsersPageView = require("../views/users_page_view.js");
+const EmptyView = require("../views/empty_view.js");
class UserListController {
constructor(ctx) {
this._pageController = new PageController();
- if (!api.hasPrivilege('users:list')) {
+ if (!api.hasPrivilege("users:list")) {
this._view = new EmptyView();
- this._view.showError('You don\'t have privileges to view users.');
+ this._view.showError("You don't have privileges to view users.");
return;
}
- topNavigation.activate('users');
- topNavigation.setTitle('Listing users');
+ topNavigation.activate("users");
+ topNavigation.setTitle("Listing users");
this._ctx = ctx;
@@ -29,8 +29,9 @@ class UserListController {
hostNode: this._pageController.view.pageHeaderHolderNode,
parameters: ctx.parameters,
});
- this._headerView.addEventListener(
- 'navigate', e => this._evtNavigate(e));
+ this._headerView.addEventListener("navigate", (e) =>
+ this._evtNavigate(e)
+ );
this._syncPageController();
}
@@ -41,7 +42,8 @@ class UserListController {
_evtNavigate(e) {
router.showNoDispatch(
- uri.formatClientLink('users', e.detail.parameters));
+ uri.formatClientLink("users", e.detail.parameters)
+ );
Object.assign(this._ctx.parameters, e.detail.parameters);
this._syncPageController();
}
@@ -51,17 +53,22 @@ class UserListController {
parameters: this._ctx.parameters,
defaultLimit: 30,
getClientUrlForPage: (offset, limit) => {
- const parameters = Object.assign(
- {}, this._ctx.parameters, {offset: offset, limit: limit});
- return uri.formatClientLink('users', parameters);
+ const parameters = Object.assign({}, this._ctx.parameters, {
+ offset: offset,
+ limit: limit,
+ });
+ return uri.formatClientLink("users", parameters);
},
requestPage: (offset, limit) => {
return UserList.search(
- this._ctx.parameters.query, offset, limit);
+ this._ctx.parameters.query,
+ offset,
+ limit
+ );
},
- pageRenderer: pageCtx => {
+ pageRenderer: (pageCtx) => {
Object.assign(pageCtx, {
- canViewUsers: api.hasPrivilege('users:view'),
+ canViewUsers: api.hasPrivilege("users:view"),
});
return new UsersPageView(pageCtx);
},
@@ -69,10 +76,8 @@ class UserListController {
}
}
-module.exports = router => {
- router.enter(
- ['users'],
- (ctx, next) => {
- ctx.controller = new UserListController(ctx);
- });
+module.exports = (router) => {
+ router.enter(["users"], (ctx, next) => {
+ ctx.controller = new UserListController(ctx);
+ });
};
diff --git a/client/js/controllers/user_registration_controller.js b/client/js/controllers/user_registration_controller.js
index 78b9402..89cfd8c 100644
--- a/client/js/controllers/user_registration_controller.js
+++ b/client/js/controllers/user_registration_controller.js
@@ -1,25 +1,25 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const User = require('../models/user.js');
-const topNavigation = require('../models/top_navigation.js');
-const RegistrationView = require('../views/registration_view.js');
-const EmptyView = require('../views/empty_view.js');
+const router = require("../router.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const User = require("../models/user.js");
+const topNavigation = require("../models/top_navigation.js");
+const RegistrationView = require("../views/registration_view.js");
+const EmptyView = require("../views/empty_view.js");
class UserRegistrationController {
constructor() {
- if (!api.hasPrivilege('users:create:self')) {
+ if (!api.hasPrivilege("users:create:self")) {
this._view = new EmptyView();
- this._view.showError('Registration is closed.');
+ this._view.showError("Registration is closed.");
return;
}
- topNavigation.activate('register');
- topNavigation.setTitle('Registration');
+ topNavigation.activate("register");
+ topNavigation.setTitle("Registration");
this._view = new RegistrationView();
- this._view.addEventListener('submit', e => this._evtRegister(e));
+ this._view.addEventListener("submit", (e) => this._evtRegister(e));
}
_evtRegister(e) {
@@ -30,30 +30,35 @@ class UserRegistrationController {
user.email = e.detail.email;
user.password = e.detail.password;
const isLoggedIn = api.isLoggedIn();
- user.save().then(() => {
- if (isLoggedIn) {
- return Promise.resolve();
- } else {
- api.forget();
- return api.login(e.detail.name, e.detail.password, false);
- }
- }).then(() => {
- if (isLoggedIn) {
- const ctx = router.show(uri.formatClientLink('users'));
- ctx.controller.showSuccess('User added!');
- } else {
- const ctx = router.show(uri.formatClientLink());
- ctx.controller.showSuccess('Welcome aboard!');
- }
- }, error => {
- this._view.showError(error.message);
- this._view.enableForm();
- });
+ user.save()
+ .then(() => {
+ if (isLoggedIn) {
+ return Promise.resolve();
+ } else {
+ api.forget();
+ return api.login(e.detail.name, e.detail.password, false);
+ }
+ })
+ .then(
+ () => {
+ if (isLoggedIn) {
+ const ctx = router.show(uri.formatClientLink("users"));
+ ctx.controller.showSuccess("User added!");
+ } else {
+ const ctx = router.show(uri.formatClientLink());
+ ctx.controller.showSuccess("Welcome aboard!");
+ }
+ },
+ (error) => {
+ this._view.showError(error.message);
+ this._view.enableForm();
+ }
+ );
}
}
-module.exports = router => {
- router.enter(['register'], (ctx, next) => {
+module.exports = (router) => {
+ router.enter(["register"], (ctx, next) => {
new UserRegistrationController();
});
};
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();
}
diff --git a/client/js/events.js b/client/js/events.js
index 945771a..7d6ffa6 100644
--- a/client/js/events.js
+++ b/client/js/events.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
class EventTarget {
constructor() {
this.eventTarget = document.createDocumentFragment();
for (let method of [
- 'addEventListener',
- 'dispatchEvent',
- 'removeEventListener'
+ "addEventListener",
+ "dispatchEvent",
+ "removeEventListener",
]) {
this[method] = this.eventTarget[method].bind(this.eventTarget);
}
@@ -20,17 +20,19 @@ function proxyEvent(source, target, sourceEventType, targetEventType) {
if (!targetEventType) {
targetEventType = sourceEventType;
}
- source.addEventListener(sourceEventType, e => {
- target.dispatchEvent(new CustomEvent(targetEventType, {
- detail: e.detail,
- }));
+ source.addEventListener(sourceEventType, (e) => {
+ target.dispatchEvent(
+ new CustomEvent(targetEventType, {
+ detail: e.detail,
+ })
+ );
});
}
module.exports = {
- Success: 'success',
- Error: 'error',
- Info: 'info',
+ Success: "success",
+ Error: "error",
+ Info: "info",
proxyEvent: proxyEvent,
EventTarget: EventTarget,
diff --git a/client/js/main.js b/client/js/main.js
index 8406c79..a6e6d6a 100644
--- a/client/js/main.js
+++ b/client/js/main.js
@@ -1,82 +1,101 @@
-'use strict';
+"use strict";
-require('./util/polyfill.js');
-const misc = require('./util/misc.js');
-const views = require('./util/views.js');
-const router = require('./router.js');
+require("./util/polyfill.js");
+const misc = require("./util/misc.js");
+const views = require("./util/views.js");
+const router = require("./router.js");
-history.scrollRestoration = 'manual';
+history.scrollRestoration = "manual";
-router.exit(
- null,
- (ctx, next) => {
- ctx.state.scrollX = window.scrollX;
- ctx.state.scrollY = window.scrollY;
- router.replace(router.url, ctx.state);
- if (misc.confirmPageExit()) {
- next();
- }
- });
-
-const mousetrap = require('mousetrap');
-router.enter(
- null,
- (ctx, next) => {
- mousetrap.reset();
+router.exit(null, (ctx, next) => {
+ ctx.state.scrollX = window.scrollX;
+ ctx.state.scrollY = window.scrollY;
+ router.replace(router.url, ctx.state);
+ if (misc.confirmPageExit()) {
next();
- });
+ }
+});
-const tags = require('./tags.js');
-const pools = require('./pools.js');
-const api = require('./api.js');
+const mousetrap = require("mousetrap");
+router.enter(null, (ctx, next) => {
+ mousetrap.reset();
+ next();
+});
-api.fetchConfig().then(() => {
- // register controller routes
- let controllers = [];
- controllers.push(require('./controllers/home_controller.js'));
- controllers.push(require('./controllers/help_controller.js'));
- controllers.push(require('./controllers/auth_controller.js'));
- controllers.push(require('./controllers/password_reset_controller.js'));
- controllers.push(require('./controllers/comments_controller.js'));
- controllers.push(require('./controllers/snapshots_controller.js'));
- controllers.push(require('./controllers/post_detail_controller.js'));
- controllers.push(require('./controllers/post_main_controller.js'));
- controllers.push(require('./controllers/post_list_controller.js'));
- controllers.push(require('./controllers/post_upload_controller.js'));
- controllers.push(require('./controllers/tag_controller.js'));
- controllers.push(require('./controllers/tag_list_controller.js'));
- controllers.push(require('./controllers/tag_categories_controller.js'));
- controllers.push(require('./controllers/pool_create_controller.js'));
- controllers.push(require('./controllers/pool_controller.js'));
- controllers.push(require('./controllers/pool_list_controller.js'));
- controllers.push(require('./controllers/pool_categories_controller.js'));
- controllers.push(require('./controllers/settings_controller.js'));
- controllers.push(require('./controllers/user_controller.js'));
- controllers.push(require('./controllers/user_list_controller.js'));
- controllers.push(require('./controllers/user_registration_controller.js'));
+const tags = require("./tags.js");
+const pools = require("./pools.js");
+const api = require("./api.js");
- // 404 controller needs to be registered last
- controllers.push(require('./controllers/not_found_controller.js'));
+api.fetchConfig()
+ .then(
+ () => {
+ // register controller routes
+ let controllers = [];
+ controllers.push(require("./controllers/home_controller.js"));
+ controllers.push(require("./controllers/help_controller.js"));
+ controllers.push(require("./controllers/auth_controller.js"));
+ controllers.push(
+ require("./controllers/password_reset_controller.js")
+ );
+ controllers.push(require("./controllers/comments_controller.js"));
+ controllers.push(require("./controllers/snapshots_controller.js"));
+ controllers.push(
+ require("./controllers/post_detail_controller.js")
+ );
+ controllers.push(require("./controllers/post_main_controller.js"));
+ controllers.push(require("./controllers/post_list_controller.js"));
+ controllers.push(
+ require("./controllers/post_upload_controller.js")
+ );
+ controllers.push(require("./controllers/tag_controller.js"));
+ controllers.push(require("./controllers/tag_list_controller.js"));
+ controllers.push(
+ require("./controllers/tag_categories_controller.js")
+ );
+ controllers.push(
+ require("./controllers/pool_create_controller.js")
+ );
+ controllers.push(require("./controllers/pool_controller.js"));
+ controllers.push(require("./controllers/pool_list_controller.js"));
+ controllers.push(
+ require("./controllers/pool_categories_controller.js")
+ );
+ controllers.push(require("./controllers/settings_controller.js"));
+ controllers.push(require("./controllers/user_controller.js"));
+ controllers.push(require("./controllers/user_list_controller.js"));
+ controllers.push(
+ require("./controllers/user_registration_controller.js")
+ );
- for (let controller of controllers) {
- controller(router);
- }
-}, error => {
- window.alert('Could not fetch basic configuration from server');
-}).then(() => {
- api.loginFromCookies().then(() => {
- tags.refreshCategoryColorMap();
- pools.refreshCategoryColorMap();
- router.start();
- }, error => {
- if (window.location.href.indexOf('login') !== -1) {
- api.forget();
- router.start();
- } else {
- const ctx = router.start('/');
- ctx.controller.showError(
- 'An error happened while trying to log you in: ' +
- error.message);
+ // 404 controller needs to be registered last
+ controllers.push(require("./controllers/not_found_controller.js"));
+
+ for (let controller of controllers) {
+ controller(router);
+ }
+ },
+ (error) => {
+ window.alert("Could not fetch basic configuration from server");
}
+ )
+ .then(() => {
+ api.loginFromCookies().then(
+ () => {
+ tags.refreshCategoryColorMap();
+ pools.refreshCategoryColorMap();
+ router.start();
+ },
+ (error) => {
+ if (window.location.href.indexOf("login") !== -1) {
+ api.forget();
+ router.start();
+ } else {
+ const ctx = router.start("/");
+ ctx.controller.showError(
+ "An error happened while trying to log you in: " +
+ error.message
+ );
+ }
+ }
+ );
});
-});
diff --git a/client/js/models/abstract_list.js b/client/js/models/abstract_list.js
index fb4dec8..7cf518c 100644
--- a/client/js/models/abstract_list.js
+++ b/client/js/models/abstract_list.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
+const events = require("../events.js");
class AbstractList extends events.EventTarget {
constructor() {
@@ -13,13 +13,15 @@ class AbstractList extends events.EventTarget {
for (let item of response) {
const addedItem = this._itemClass.fromResponse(item);
if (addedItem.addEventListener) {
- addedItem.addEventListener('delete', e => {
+ addedItem.addEventListener("delete", (e) => {
ret.remove(addedItem);
});
- addedItem.addEventListener('change', e => {
- ret.dispatchEvent(new CustomEvent('change', {
- detail: e.detail,
- }));
+ addedItem.addEventListener("change", (e) => {
+ ret.dispatchEvent(
+ new CustomEvent("change", {
+ detail: e.detail,
+ })
+ );
});
}
ret._list.push(addedItem);
@@ -29,28 +31,32 @@ class AbstractList extends events.EventTarget {
sync(plainList) {
this.clear();
- for (let item of (plainList || [])) {
+ for (let item of plainList || []) {
this.add(this.constructor._itemClass.fromResponse(item));
}
}
add(item) {
if (item.addEventListener) {
- item.addEventListener('delete', e => {
+ item.addEventListener("delete", (e) => {
this.remove(item);
});
- item.addEventListener('change', e => {
- this.dispatchEvent(new CustomEvent('change', {
- detail: e.detail,
- }));
+ item.addEventListener("change", (e) => {
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: e.detail,
+ })
+ );
});
}
this._list.push(item);
const detail = {};
detail[this.constructor._itemName] = item;
- this.dispatchEvent(new CustomEvent('add', {
- detail: detail,
- }));
+ this.dispatchEvent(
+ new CustomEvent("add", {
+ detail: detail,
+ })
+ );
}
clear() {
@@ -67,9 +73,11 @@ class AbstractList extends events.EventTarget {
this._list.splice(index, 1);
const detail = {};
detail[this.constructor._itemName] = itemToRemove;
- this.dispatchEvent(new CustomEvent('remove', {
- detail: detail,
- }));
+ this.dispatchEvent(
+ new CustomEvent("remove", {
+ detail: detail,
+ })
+ );
return;
}
}
diff --git a/client/js/models/comment.js b/client/js/models/comment.js
index e292ec4..4707a3a 100644
--- a/client/js/models/comment.js
+++ b/client/js/models/comment.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
class Comment extends events.EventTarget {
constructor() {
@@ -31,7 +31,7 @@ class Comment extends events.EventTarget {
}
get text() {
- return this._text || '';
+ return this._text || "";
}
get user() {
@@ -63,47 +63,57 @@ class Comment extends events.EventTarget {
version: this._version,
text: this._text,
};
- let promise = this._id ?
- api.put(uri.formatApiLink('comment', this.id), detail) :
- api.post(uri.formatApiLink('comments'),
- Object.assign({postId: this._postId}, detail));
+ let promise = this._id
+ ? api.put(uri.formatApiLink("comment", this.id), detail)
+ : api.post(
+ uri.formatApiLink("comments"),
+ Object.assign({ postId: this._postId }, detail)
+ );
- return promise.then(response => {
+ return promise.then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- comment: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ comment: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
delete() {
- return api.delete(
- uri.formatApiLink('comment', this.id),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- comment: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("comment", this.id), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ comment: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
setScore(score) {
- return api.put(
- uri.formatApiLink('comment', this.id, 'score'),
- {score: score})
- .then(response => {
+ return api
+ .put(uri.formatApiLink("comment", this.id, "score"), {
+ score: score,
+ })
+ .then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('changeScore', {
- detail: {
- comment: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("changeScore", {
+ detail: {
+ comment: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/comment_list.js b/client/js/models/comment_list.js
index a8e1150..bae2d7a 100644
--- a/client/js/models/comment_list.js
+++ b/client/js/models/comment_list.js
@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
-const AbstractList = require('./abstract_list.js');
-const Comment = require('./comment.js');
+const AbstractList = require("./abstract_list.js");
+const Comment = require("./comment.js");
-class CommentList extends AbstractList {
-}
+class CommentList extends AbstractList {}
CommentList._itemClass = Comment;
-CommentList._itemName = 'comment';
+CommentList._itemName = "comment";
module.exports = CommentList;
diff --git a/client/js/models/info.js b/client/js/models/info.js
index 35ba867..6b03b38 100644
--- a/client/js/models/info.js
+++ b/client/js/models/info.js
@@ -1,22 +1,20 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const Post = require('./post.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const Post = require("./post.js");
class Info {
static get() {
- return api.get(uri.formatApiLink('info'))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {
- featuredPost: response.featuredPost ?
- Post.fromResponse(response.featuredPost) :
- undefined
- }));
- });
+ return api.get(uri.formatApiLink("info")).then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ featuredPost: response.featuredPost
+ ? Post.fromResponse(response.featuredPost)
+ : undefined,
+ })
+ );
+ });
}
}
diff --git a/client/js/models/note.js b/client/js/models/note.js
index 1709d44..87c8b3b 100644
--- a/client/js/models/note.js
+++ b/client/js/models/note.js
@@ -1,13 +1,13 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const Point = require('./point.js');
-const PointList = require('./point_list.js');
+const events = require("../events.js");
+const Point = require("./point.js");
+const PointList = require("./point_list.js");
class Note extends events.EventTarget {
constructor() {
super();
- this._text = '…';
+ this._text = "…";
this._polygon = new PointList();
}
diff --git a/client/js/models/note_list.js b/client/js/models/note_list.js
index b54d7f3..10db435 100644
--- a/client/js/models/note_list.js
+++ b/client/js/models/note_list.js
@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
-const AbstractList = require('./abstract_list.js');
-const Note = require('./note.js');
+const AbstractList = require("./abstract_list.js");
+const Note = require("./note.js");
-class NoteList extends AbstractList {
-}
+class NoteList extends AbstractList {}
NoteList._itemClass = Note;
-NoteList._itemName = 'note';
+NoteList._itemName = "note";
module.exports = NoteList;
diff --git a/client/js/models/point.js b/client/js/models/point.js
index bbb05ec..70b4961 100644
--- a/client/js/models/point.js
+++ b/client/js/models/point.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
+const events = require("../events.js");
class Point extends events.EventTarget {
constructor(x, y) {
@@ -19,12 +19,16 @@ class Point extends events.EventTarget {
set x(value) {
this._x = value;
- this.dispatchEvent(new CustomEvent('change', {detail: {point: this}}));
+ this.dispatchEvent(
+ new CustomEvent("change", { detail: { point: this } })
+ );
}
set y(value) {
this._y = value;
- this.dispatchEvent(new CustomEvent('change', {detail: {point: this}}));
+ this.dispatchEvent(
+ new CustomEvent("change", { detail: { point: this } })
+ );
}
}
diff --git a/client/js/models/point_list.js b/client/js/models/point_list.js
index 166e664..3ecd7d7 100644
--- a/client/js/models/point_list.js
+++ b/client/js/models/point_list.js
@@ -1,7 +1,7 @@
-'use strict';
+"use strict";
-const AbstractList = require('./abstract_list.js');
-const Point = require('./point.js');
+const AbstractList = require("./abstract_list.js");
+const Point = require("./point.js");
class PointList extends AbstractList {
get firstPoint() {
@@ -18,6 +18,6 @@ class PointList extends AbstractList {
}
PointList._itemClass = Point;
-PointList._itemName = 'point';
+PointList._itemName = "point";
module.exports = PointList;
diff --git a/client/js/models/pool.js b/client/js/models/pool.js
index 8a86e12..51fa8a0 100644
--- a/client/js/models/pool.js
+++ b/client/js/models/pool.js
@@ -1,13 +1,13 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
-const misc = require('../util/misc.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
+const misc = require("../util/misc.js");
class Pool extends events.EventTarget {
constructor() {
- const PostList = require('./post_list.js');
+ const PostList = require("./post_list.js");
super();
this._orig = {};
@@ -70,14 +70,13 @@ class Pool extends events.EventTarget {
}
static get(id) {
- return api.get(uri.formatApiLink('pool', id))
- .then(response => {
- return Promise.resolve(Pool.fromResponse(response));
- });
+ return api.get(uri.formatApiLink("pool", id)).then((response) => {
+ return Promise.resolve(Pool.fromResponse(response));
+ });
}
save() {
- const detail = {version: this._version};
+ const detail = { version: this._version };
// send only changed fields to avoid user privilege violation
if (misc.arraysDiffer(this._names, this._orig._names, true)) {
@@ -90,62 +89,71 @@ class Pool extends events.EventTarget {
detail.description = this._description;
}
if (misc.arraysDiffer(this._posts, this._orig._posts)) {
- detail.posts = this._posts.map(post => post.id);
+ detail.posts = this._posts.map((post) => post.id);
}
- let promise = this._id ?
- api.put(uri.formatApiLink('pool', this._id), detail) :
- api.post(uri.formatApiLink('pools'), detail);
- return promise
- .then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
+ let promise = this._id
+ ? api.put(uri.formatApiLink("pool", this._id), detail)
+ : api.post(uri.formatApiLink("pools"), detail);
+ return promise.then((response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", {
detail: {
pool: this,
},
- }));
- return Promise.resolve();
- });
+ })
+ );
+ return Promise.resolve();
+ });
}
merge(targetId, addAlias) {
- return api.get(uri.formatApiLink('pool', targetId))
- .then(response => {
- return api.post(uri.formatApiLink('pool-merge'), {
+ return api
+ .get(uri.formatApiLink("pool", targetId))
+ .then((response) => {
+ return api.post(uri.formatApiLink("pool-merge"), {
removeVersion: this._version,
remove: this._id,
mergeToVersion: response.version,
mergeTo: targetId,
});
- }).then(response => {
+ })
+ .then((response) => {
if (!addAlias) {
return Promise.resolve(response);
}
- return api.put(uri.formatApiLink('pool', targetId), {
+ return api.put(uri.formatApiLink("pool", targetId), {
version: response.version,
names: response.names.concat(this._names),
});
- }).then(response => {
+ })
+ .then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- pool: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ pool: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
delete() {
- return api.delete(
- uri.formatApiLink('pool', this._id),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- pool: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("pool", this._id), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ pool: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/pool_category.js b/client/js/models/pool_category.js
index 1ce4b24..8c7df46 100644
--- a/client/js/models/pool_category.js
+++ b/client/js/models/pool_category.js
@@ -1,14 +1,14 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
class PoolCategory extends events.EventTarget {
constructor() {
super();
- this._name = '';
- this._color = '#000000';
+ this._name = "";
+ this._color = "#000000";
this._poolCount = 0;
this._isDefault = false;
this._origName = null;
@@ -50,7 +50,7 @@ class PoolCategory extends events.EventTarget {
}
save() {
- const detail = {version: this._version};
+ const detail = { version: this._version };
if (this.name !== this._origName) {
detail.name = this.name;
@@ -63,34 +63,39 @@ class PoolCategory extends events.EventTarget {
return Promise.resolve();
}
- let promise = this._origName ?
- api.put(
- uri.formatApiLink('pool-category', this._origName),
- detail) :
- api.post(uri.formatApiLink('pool-categories'), detail);
+ let promise = this._origName
+ ? api.put(
+ uri.formatApiLink("pool-category", this._origName),
+ detail
+ )
+ : api.post(uri.formatApiLink("pool-categories"), detail);
- return promise
- .then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
+ return promise.then((response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", {
detail: {
poolCategory: this,
},
- }));
- return Promise.resolve();
- });
+ })
+ );
+ return Promise.resolve();
+ });
}
delete() {
- return api.delete(
- uri.formatApiLink('pool-category', this._origName),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- poolCategory: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("pool-category", this._origName), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ poolCategory: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/pool_category_list.js b/client/js/models/pool_category_list.js
index 2699620..46b7838 100644
--- a/client/js/models/pool_category_list.js
+++ b/client/js/models/pool_category_list.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const PoolCategory = require('./pool_category.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const PoolCategory = require("./pool_category.js");
class PoolCategoryList extends AbstractList {
constructor() {
@@ -11,7 +11,7 @@ class PoolCategoryList extends AbstractList {
this._defaultCategory = null;
this._origDefaultCategory = null;
this._deletedCategories = [];
- this.addEventListener('remove', e => this._evtCategoryDeleted(e));
+ this.addEventListener("remove", (e) => this._evtCategoryDeleted(e));
}
static fromResponse(response) {
@@ -27,12 +27,16 @@ class PoolCategoryList extends AbstractList {
}
static get() {
- return api.get(uri.formatApiLink('pool-categories'))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: PoolCategoryList.fromResponse(response.results)}));
+ return api
+ .get(uri.formatApiLink("pool-categories"))
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: PoolCategoryList.fromResponse(
+ response.results
+ ),
+ })
+ );
});
}
@@ -57,16 +61,18 @@ class PoolCategoryList extends AbstractList {
promises.push(
api.put(
uri.formatApiLink(
- 'pool-category',
+ "pool-category",
this._defaultCategory.name,
- 'default')));
+ "default"
+ )
+ )
+ );
}
- return Promise.all(promises)
- .then(response => {
- this._deletedCategories = [];
- return Promise.resolve();
- });
+ return Promise.all(promises).then((response) => {
+ this._deletedCategories = [];
+ return Promise.resolve();
+ });
}
_evtCategoryDeleted(e) {
@@ -77,6 +83,6 @@ class PoolCategoryList extends AbstractList {
}
PoolCategoryList._itemClass = PoolCategory;
-PoolCategoryList._itemName = 'poolCategory';
+PoolCategoryList._itemName = "poolCategory";
module.exports = PoolCategoryList;
diff --git a/client/js/models/pool_list.js b/client/js/models/pool_list.js
index 8a3b858..a8839bb 100644
--- a/client/js/models/pool_list.js
+++ b/client/js/models/pool_list.js
@@ -1,25 +1,27 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const Pool = require('./pool.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const Pool = require("./pool.js");
class PoolList extends AbstractList {
static search(text, offset, limit, fields) {
- return api.get(
- uri.formatApiLink(
- 'pools', {
+ return api
+ .get(
+ uri.formatApiLink("pools", {
query: text,
offset: offset,
limit: limit,
- fields: fields.join(','),
- }))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: PoolList.fromResponse(response.results)}));
+ fields: fields.join(","),
+ })
+ )
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: PoolList.fromResponse(response.results),
+ })
+ );
});
}
@@ -42,6 +44,6 @@ class PoolList extends AbstractList {
}
PoolList._itemClass = Pool;
-PoolList._itemName = 'pool';
+PoolList._itemName = "pool";
module.exports = PoolList;
diff --git a/client/js/models/post.js b/client/js/models/post.js
index a11d3cb..e90d0b2 100644
--- a/client/js/models/post.js
+++ b/client/js/models/post.js
@@ -1,15 +1,15 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const tags = require('../tags.js');
-const events = require('../events.js');
-const TagList = require('./tag_list.js');
-const NoteList = require('./note_list.js');
-const CommentList = require('./comment_list.js');
-const PoolList = require('./pool_list.js');
-const Pool = require('./pool.js');
-const misc = require('../util/misc.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const tags = require("../tags.js");
+const events = require("../events.js");
+const TagList = require("./tag_list.js");
+const NoteList = require("./note_list.js");
+const CommentList = require("./comment_list.js");
+const PoolList = require("./pool_list.js");
+const Pool = require("./pool.js");
+const misc = require("../util/misc.js");
class Post extends events.EventTarget {
constructor() {
@@ -67,7 +67,7 @@ class Post extends events.EventTarget {
}
get sourceSplit() {
- return this._source.split('\n');
+ return this._source.split("\n");
}
get canvasWidth() {
@@ -83,11 +83,11 @@ class Post extends events.EventTarget {
}
get newContent() {
- throw 'Invalid operation';
+ throw "Invalid operation";
}
get newThumbnail() {
- throw 'Invalid operation';
+ throw "Invalid operation";
}
get flags() {
@@ -99,7 +99,7 @@ class Post extends events.EventTarget {
}
get tagNames() {
- return this._tags.map(tag => tag.names[0]);
+ return this._tags.map((tag) => tag.names[0]);
}
get notes() {
@@ -174,32 +174,31 @@ class Post extends events.EventTarget {
static reverseSearch(content) {
let apiPromise = api.post(
- uri.formatApiLink('posts', 'reverse-search'),
+ uri.formatApiLink("posts", "reverse-search"),
{},
- {content: content});
- let returnedPromise = apiPromise
- .then(response => {
- if (response.exactPost) {
- response.exactPost = Post.fromResponse(response.exactPost);
- }
- for (let item of response.similarPosts) {
- item.post = Post.fromResponse(item.post);
- }
- return Promise.resolve(response);
- });
+ { content: content }
+ );
+ let returnedPromise = apiPromise.then((response) => {
+ if (response.exactPost) {
+ response.exactPost = Post.fromResponse(response.exactPost);
+ }
+ for (let item of response.similarPosts) {
+ item.post = Post.fromResponse(item.post);
+ }
+ return Promise.resolve(response);
+ });
returnedPromise.abort = () => apiPromise.abort();
return returnedPromise;
}
static get(id) {
- return api.get(uri.formatApiLink('post', id))
- .then(response => {
- return Promise.resolve(Post.fromResponse(response));
- });
+ return api.get(uri.formatApiLink("post", id)).then((response) => {
+ return Promise.resolve(Post.fromResponse(response));
+ });
}
_savePoolPosts() {
- const difference = (a, b) => a.filter(post => !b.hasPoolId(post.id));
+ const difference = (a, b) => a.filter((post) => !b.hasPoolId(post.id));
// find the pools where the post was added or removed
const added = difference(this.pools, this._orig._pools);
@@ -209,7 +208,7 @@ class Post extends events.EventTarget {
// update each pool's list of posts
for (let pool of added) {
- let op = Pool.get(pool.id).then(response => {
+ let op = Pool.get(pool.id).then((response) => {
if (!response.posts.hasPostId(this._id)) {
response.posts.addById(this._id);
return response.save();
@@ -221,7 +220,7 @@ class Post extends events.EventTarget {
}
for (let pool of removed) {
- let op = Pool.get(pool.id).then(response => {
+ let op = Pool.get(pool.id).then((response) => {
if (response.posts.hasPostId(this._id)) {
response.posts.removeById(this._id);
return response.save();
@@ -237,7 +236,7 @@ class Post extends events.EventTarget {
save(anonymous) {
const files = {};
- const detail = {version: this._version};
+ const detail = { version: this._version };
// send only changed fields to avoid user privilege violation
if (anonymous === true) {
@@ -250,14 +249,14 @@ class Post extends events.EventTarget {
detail.flags = this._flags;
}
if (misc.arraysDiffer(this._tags, this._orig._tags)) {
- detail.tags = this._tags.map(tag => tag.names[0]);
+ detail.tags = this._tags.map((tag) => tag.names[0]);
}
if (misc.arraysDiffer(this._relations, this._orig._relations)) {
detail.relations = this._relations;
}
if (misc.arraysDiffer(this._notes, this._orig._notes)) {
- detail.notes = this._notes.map(note => ({
- polygon: note.polygon.map(point => [point.x, point.y]),
+ detail.notes = this._notes.map((note) => ({
+ polygon: note.polygon.map((point) => [point.x, point.y]),
text: note.text,
}));
}
@@ -271,154 +270,187 @@ class Post extends events.EventTarget {
detail.source = this._source;
}
- let apiPromise = this._id ?
- api.put(uri.formatApiLink('post', this.id), detail, files) :
- api.post(uri.formatApiLink('posts'), detail, files);
+ let apiPromise = this._id
+ ? api.put(uri.formatApiLink("post", this.id), detail, files)
+ : api.post(uri.formatApiLink("posts"), detail, files);
- return apiPromise.then(response => {
- if (misc.arraysDiffer(this._pools, this._orig._pools)) {
- return this._savePoolPosts()
- .then(() => Promise.resolve(response));
- }
- return Promise.resolve(response);
- }).then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(
- new CustomEvent('change', {detail: {post: this}}));
- if (this._newContent) {
- this.dispatchEvent(
- new CustomEvent('changeContent', {detail: {post: this}}));
- }
- if (this._newThumbnail) {
- this.dispatchEvent(
- new CustomEvent('changeThumbnail', {detail: {post: this}}));
- }
+ return apiPromise
+ .then((response) => {
+ if (misc.arraysDiffer(this._pools, this._orig._pools)) {
+ return this._savePoolPosts().then(() =>
+ Promise.resolve(response)
+ );
+ }
+ return Promise.resolve(response);
+ })
+ .then(
+ (response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", { detail: { post: this } })
+ );
+ if (this._newContent) {
+ this.dispatchEvent(
+ new CustomEvent("changeContent", {
+ detail: { post: this },
+ })
+ );
+ }
+ if (this._newThumbnail) {
+ this.dispatchEvent(
+ new CustomEvent("changeThumbnail", {
+ detail: { post: this },
+ })
+ );
+ }
- return Promise.resolve();
- }, error => {
- if (error.response &&
- error.response.name === 'PostAlreadyUploadedError') {
- error.message =
- `Post already uploaded (@${error.response.otherPostId})`;
- }
- return Promise.reject(error);
- });
+ return Promise.resolve();
+ },
+ (error) => {
+ if (
+ error.response &&
+ error.response.name === "PostAlreadyUploadedError"
+ ) {
+ error.message = `Post already uploaded (@${error.response.otherPostId})`;
+ }
+ return Promise.reject(error);
+ }
+ );
}
feature() {
- return api.post(
- uri.formatApiLink('featured-post'),
- {id: this._id})
- .then(response => {
+ return api
+ .post(uri.formatApiLink("featured-post"), { id: this._id })
+ .then((response) => {
return Promise.resolve();
});
}
delete() {
- return api.delete(
- uri.formatApiLink('post', this.id),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- post: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("post", this.id), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ post: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
merge(targetId, useOldContent) {
- return api.get(uri.formatApiLink('post', targetId))
- .then(response => {
- return api.post(uri.formatApiLink('post-merge'), {
+ return api
+ .get(uri.formatApiLink("post", targetId))
+ .then((response) => {
+ return api.post(uri.formatApiLink("post-merge"), {
removeVersion: this._version,
remove: this._id,
mergeToVersion: response.version,
mergeTo: targetId,
replaceContent: useOldContent,
});
- }).then(response => {
+ })
+ .then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- post: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ post: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
setScore(score) {
- return api.put(
- uri.formatApiLink('post', this.id, 'score'),
- {score: score})
- .then(response => {
+ return api
+ .put(uri.formatApiLink("post", this.id, "score"), { score: score })
+ .then((response) => {
const prevFavorite = this._ownFavorite;
this._updateFromResponse(response);
if (this._ownFavorite !== prevFavorite) {
- this.dispatchEvent(new CustomEvent('changeFavorite', {
+ this.dispatchEvent(
+ new CustomEvent("changeFavorite", {
+ detail: {
+ post: this,
+ },
+ })
+ );
+ }
+ this.dispatchEvent(
+ new CustomEvent("changeScore", {
detail: {
post: this,
},
- }));
- }
- this.dispatchEvent(new CustomEvent('changeScore', {
- detail: {
- post: this,
- },
- }));
+ })
+ );
return Promise.resolve();
});
}
addToFavorites() {
- return api.post(uri.formatApiLink('post', this.id, 'favorite'))
- .then(response => {
+ return api
+ .post(uri.formatApiLink("post", this.id, "favorite"))
+ .then((response) => {
const prevScore = this._ownScore;
this._updateFromResponse(response);
if (this._ownScore !== prevScore) {
- this.dispatchEvent(new CustomEvent('changeScore', {
+ this.dispatchEvent(
+ new CustomEvent("changeScore", {
+ detail: {
+ post: this,
+ },
+ })
+ );
+ }
+ this.dispatchEvent(
+ new CustomEvent("changeFavorite", {
detail: {
post: this,
},
- }));
- }
- this.dispatchEvent(new CustomEvent('changeFavorite', {
- detail: {
- post: this,
- },
- }));
+ })
+ );
return Promise.resolve();
});
}
removeFromFavorites() {
- return api.delete(uri.formatApiLink('post', this.id, 'favorite'))
- .then(response => {
+ return api
+ .delete(uri.formatApiLink("post", this.id, "favorite"))
+ .then((response) => {
const prevScore = this._ownScore;
this._updateFromResponse(response);
if (this._ownScore !== prevScore) {
- this.dispatchEvent(new CustomEvent('changeScore', {
+ this.dispatchEvent(
+ new CustomEvent("changeScore", {
+ detail: {
+ post: this,
+ },
+ })
+ );
+ }
+ this.dispatchEvent(
+ new CustomEvent("changeFavorite", {
detail: {
post: this,
},
- }));
- }
- this.dispatchEvent(new CustomEvent('changeFavorite', {
- detail: {
- post: this,
- },
- }));
+ })
+ );
return Promise.resolve();
});
}
mutateContentUrl() {
this._contentUrl =
- this._orig._contentUrl +
- '?bypass-cache=' +
- Math.round(Math.random() * 1000);
+ this._orig._contentUrl +
+ "?bypass-cache=" +
+ Math.round(Math.random() * 1000);
}
_updateFromResponse(response) {
@@ -431,15 +463,18 @@ class Post extends events.EventTarget {
_user: response.user,
_safety: response.safety,
_contentUrl: response.contentUrl,
- _fullContentUrl: new URL(response.contentUrl, document.getElementsByTagName('base')[0].href).href,
+ _fullContentUrl: new URL(
+ response.contentUrl,
+ document.getElementsByTagName("base")[0].href
+ ).href,
_thumbnailUrl: response.thumbnailUrl,
_source: response.source,
_canvasWidth: response.canvasWidth,
_canvasHeight: response.canvasHeight,
_fileSize: response.fileSize,
- _flags: [...response.flags || []],
- _relations: [...response.relations || []],
+ _flags: [...(response.flags || [])],
+ _relations: [...(response.relations || [])],
_score: response.score,
_commentCount: response.commentCount,
diff --git a/client/js/models/post_list.js b/client/js/models/post_list.js
index cd94e40..8c2c9d4 100644
--- a/client/js/models/post_list.js
+++ b/client/js/models/post_list.js
@@ -1,35 +1,37 @@
-'use strict';
+"use strict";
-const settings = require('../models/settings.js');
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const Post = require('./post.js');
+const settings = require("../models/settings.js");
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const Post = require("./post.js");
class PostList extends AbstractList {
static getAround(id, searchQuery) {
return api.get(
- uri.formatApiLink(
- 'post', id, 'around', {
- query: PostList._decorateSearchQuery(searchQuery || ''),
- fields: 'id',
- }));
+ uri.formatApiLink("post", id, "around", {
+ query: PostList._decorateSearchQuery(searchQuery || ""),
+ fields: "id",
+ })
+ );
}
static search(text, offset, limit, fields) {
- return api.get(
- uri.formatApiLink(
- 'posts', {
- query: PostList._decorateSearchQuery(text || ''),
+ return api
+ .get(
+ uri.formatApiLink("posts", {
+ query: PostList._decorateSearchQuery(text || ""),
offset: offset,
limit: limit,
- fields: fields.join(','),
- }))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: PostList.fromResponse(response.results)}));
+ fields: fields.join(","),
+ })
+ )
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: PostList.fromResponse(response.results),
+ })
+ );
});
}
@@ -43,7 +45,7 @@ class PostList extends AbstractList {
}
}
if (disabledSafety.length) {
- text = `-rating:${disabledSafety.join(',')} ${text}`;
+ text = `-rating:${disabledSafety.join(",")} ${text}`;
}
}
return text.trim();
@@ -63,7 +65,7 @@ class PostList extends AbstractList {
return;
}
- let post = Post.fromResponse({id: id});
+ let post = Post.fromResponse({ id: id });
this.add(post);
}
@@ -77,6 +79,6 @@ class PostList extends AbstractList {
}
PostList._itemClass = Post;
-PostList._itemName = 'post';
+PostList._itemName = "post";
module.exports = PostList;
diff --git a/client/js/models/settings.js b/client/js/models/settings.js
index 774aa0b..bd6ac5b 100644
--- a/client/js/models/settings.js
+++ b/client/js/models/settings.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
+const events = require("../events.js");
const defaultSettings = {
listPosts: {
@@ -12,7 +12,7 @@ const defaultSettings = {
endlessScroll: false,
keyboardShortcuts: true,
transparencyGrid: true,
- fitMode: 'fit-both',
+ fitMode: "fit-both",
tagSuggestions: true,
autoplayVideos: false,
postsPerPage: 42,
@@ -28,7 +28,7 @@ class Settings extends events.EventTarget {
_getFromLocalStorage() {
let ret = Object.assign({}, defaultSettings);
try {
- Object.assign(ret, JSON.parse(localStorage.getItem('settings')));
+ Object.assign(ret, JSON.parse(localStorage.getItem("settings")));
} catch (e) {
// continue regardless of error
}
@@ -37,14 +37,16 @@ class Settings extends events.EventTarget {
save(newSettings, silent) {
newSettings = Object.assign(this.cache, newSettings);
- localStorage.setItem('settings', JSON.stringify(newSettings));
+ localStorage.setItem("settings", JSON.stringify(newSettings));
this.cache = this._getFromLocalStorage();
if (silent !== true) {
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- settings: this.cache,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ settings: this.cache,
+ },
+ })
+ );
}
}
diff --git a/client/js/models/snapshot.js b/client/js/models/snapshot.js
index cf5a308..5f8e2ae 100644
--- a/client/js/models/snapshot.js
+++ b/client/js/models/snapshot.js
@@ -1,7 +1,7 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const events = require("../events.js");
class Snapshot extends events.EventTarget {
constructor() {
diff --git a/client/js/models/snapshot_list.js b/client/js/models/snapshot_list.js
index 475b89a..9ea1bdd 100644
--- a/client/js/models/snapshot_list.js
+++ b/client/js/models/snapshot_list.js
@@ -1,24 +1,31 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const Snapshot = require('./snapshot.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const Snapshot = require("./snapshot.js");
class SnapshotList extends AbstractList {
static search(text, offset, limit) {
- return api.get(uri.formatApiLink(
- 'snapshots', {query: text, offset: offset, limit: limit}))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: SnapshotList.fromResponse(response.results)}));
+ return api
+ .get(
+ uri.formatApiLink("snapshots", {
+ query: text,
+ offset: offset,
+ limit: limit,
+ })
+ )
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: SnapshotList.fromResponse(response.results),
+ })
+ );
});
}
}
SnapshotList._itemClass = Snapshot;
-SnapshotList._itemName = 'snapshot';
+SnapshotList._itemName = "snapshot";
module.exports = SnapshotList;
diff --git a/client/js/models/tag.js b/client/js/models/tag.js
index b99c63f..a5632c8 100644
--- a/client/js/models/tag.js
+++ b/client/js/models/tag.js
@@ -1,13 +1,13 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
-const misc = require('../util/misc.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
+const misc = require("../util/misc.js");
class Tag extends events.EventTarget {
constructor() {
- const TagList = require('./tag_list.js');
+ const TagList = require("./tag_list.js");
super();
this._orig = {};
@@ -71,14 +71,13 @@ class Tag extends events.EventTarget {
}
static get(name) {
- return api.get(uri.formatApiLink('tag', name))
- .then(response => {
- return Promise.resolve(Tag.fromResponse(response));
- });
+ return api.get(uri.formatApiLink("tag", name)).then((response) => {
+ return Promise.resolve(Tag.fromResponse(response));
+ });
}
save() {
- const detail = {version: this._version};
+ const detail = { version: this._version };
// send only changed fields to avoid user privilege violation
if (misc.arraysDiffer(this._names, this._orig._names, true)) {
@@ -92,66 +91,77 @@ class Tag extends events.EventTarget {
}
if (misc.arraysDiffer(this._implications, this._orig._implications)) {
detail.implications = this._implications.map(
- relation => relation.names[0]);
+ (relation) => relation.names[0]
+ );
}
if (misc.arraysDiffer(this._suggestions, this._orig._suggestions)) {
detail.suggestions = this._suggestions.map(
- relation => relation.names[0]);
+ (relation) => relation.names[0]
+ );
}
- let promise = this._origName ?
- api.put(uri.formatApiLink('tag', this._origName), detail) :
- api.post(uri.formatApiLink('tags'), detail);
- return promise
- .then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
+ let promise = this._origName
+ ? api.put(uri.formatApiLink("tag", this._origName), detail)
+ : api.post(uri.formatApiLink("tags"), detail);
+ return promise.then((response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", {
detail: {
tag: this,
},
- }));
- return Promise.resolve();
- });
+ })
+ );
+ return Promise.resolve();
+ });
}
merge(targetName, addAlias) {
- return api.get(uri.formatApiLink('tag', targetName))
- .then(response => {
- return api.post(uri.formatApiLink('tag-merge'), {
+ return api
+ .get(uri.formatApiLink("tag", targetName))
+ .then((response) => {
+ return api.post(uri.formatApiLink("tag-merge"), {
removeVersion: this._version,
remove: this._origName,
mergeToVersion: response.version,
mergeTo: targetName,
});
- }).then(response => {
+ })
+ .then((response) => {
if (!addAlias) {
return Promise.resolve(response);
}
- return api.put(uri.formatApiLink('tag', targetName), {
+ return api.put(uri.formatApiLink("tag", targetName), {
version: response.version,
names: response.names.concat(this._names),
});
- }).then(response => {
+ })
+ .then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- tag: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ tag: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
delete() {
- return api.delete(
- uri.formatApiLink('tag', this._origName),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- tag: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("tag", this._origName), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ tag: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/tag_category.js b/client/js/models/tag_category.js
index 42e54d8..a8d0e64 100644
--- a/client/js/models/tag_category.js
+++ b/client/js/models/tag_category.js
@@ -1,14 +1,14 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
class TagCategory extends events.EventTarget {
constructor() {
super();
- this._name = '';
- this._color = '#000000';
+ this._name = "";
+ this._color = "#000000";
this._tagCount = 0;
this._isDefault = false;
this._origName = null;
@@ -50,7 +50,7 @@ class TagCategory extends events.EventTarget {
}
save() {
- const detail = {version: this._version};
+ const detail = { version: this._version };
if (this.name !== this._origName) {
detail.name = this.name;
@@ -63,34 +63,39 @@ class TagCategory extends events.EventTarget {
return Promise.resolve();
}
- let promise = this._origName ?
- api.put(
- uri.formatApiLink('tag-category', this._origName),
- detail) :
- api.post(uri.formatApiLink('tag-categories'), detail);
+ let promise = this._origName
+ ? api.put(
+ uri.formatApiLink("tag-category", this._origName),
+ detail
+ )
+ : api.post(uri.formatApiLink("tag-categories"), detail);
- return promise
- .then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
+ return promise.then((response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", {
detail: {
tagCategory: this,
},
- }));
- return Promise.resolve();
- });
+ })
+ );
+ return Promise.resolve();
+ });
}
delete() {
- return api.delete(
- uri.formatApiLink('tag-category', this._origName),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- tagCategory: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("tag-category", this._origName), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ tagCategory: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/tag_category_list.js b/client/js/models/tag_category_list.js
index 6c1182f..2fc1522 100644
--- a/client/js/models/tag_category_list.js
+++ b/client/js/models/tag_category_list.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const TagCategory = require('./tag_category.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const TagCategory = require("./tag_category.js");
class TagCategoryList extends AbstractList {
constructor() {
@@ -11,7 +11,7 @@ class TagCategoryList extends AbstractList {
this._defaultCategory = null;
this._origDefaultCategory = null;
this._deletedCategories = [];
- this.addEventListener('remove', e => this._evtCategoryDeleted(e));
+ this.addEventListener("remove", (e) => this._evtCategoryDeleted(e));
}
static fromResponse(response) {
@@ -27,12 +27,16 @@ class TagCategoryList extends AbstractList {
}
static get() {
- return api.get(uri.formatApiLink('tag-categories'))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: TagCategoryList.fromResponse(response.results)}));
+ return api
+ .get(uri.formatApiLink("tag-categories"))
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: TagCategoryList.fromResponse(
+ response.results
+ ),
+ })
+ );
});
}
@@ -57,16 +61,18 @@ class TagCategoryList extends AbstractList {
promises.push(
api.put(
uri.formatApiLink(
- 'tag-category',
+ "tag-category",
this._defaultCategory.name,
- 'default')));
+ "default"
+ )
+ )
+ );
}
- return Promise.all(promises)
- .then(response => {
- this._deletedCategories = [];
- return Promise.resolve();
- });
+ return Promise.all(promises).then((response) => {
+ this._deletedCategories = [];
+ return Promise.resolve();
+ });
}
_evtCategoryDeleted(e) {
@@ -77,6 +83,6 @@ class TagCategoryList extends AbstractList {
}
TagCategoryList._itemClass = TagCategory;
-TagCategoryList._itemName = 'tagCategory';
+TagCategoryList._itemName = "tagCategory";
module.exports = TagCategoryList;
diff --git a/client/js/models/tag_list.js b/client/js/models/tag_list.js
index 31a34fa..7e6b643 100644
--- a/client/js/models/tag_list.js
+++ b/client/js/models/tag_list.js
@@ -1,25 +1,27 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const Tag = require('./tag.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const Tag = require("./tag.js");
class TagList extends AbstractList {
static search(text, offset, limit, fields) {
- return api.get(
- uri.formatApiLink(
- 'tags', {
+ return api
+ .get(
+ uri.formatApiLink("tags", {
query: text,
offset: offset,
limit: limit,
- fields: fields.join(','),
- }))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: TagList.fromResponse(response.results)}));
+ fields: fields.join(","),
+ })
+ )
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: TagList.fromResponse(response.results),
+ })
+ );
});
}
@@ -45,10 +47,12 @@ class TagList extends AbstractList {
this.add(tag);
if (addImplications !== false) {
- return Tag.get(tagName).then(actualTag => {
+ return Tag.get(tagName).then((actualTag) => {
return Promise.all(
- actualTag.implications.map(
- relation => this.addByName(relation.names[0], true)));
+ actualTag.implications.map((relation) =>
+ this.addByName(relation.names[0], true)
+ )
+ );
});
}
@@ -67,6 +71,6 @@ class TagList extends AbstractList {
}
TagList._itemClass = Tag;
-TagList._itemName = 'tag';
+TagList._itemName = "tag";
module.exports = TagList;
diff --git a/client/js/models/top_navigation.js b/client/js/models/top_navigation.js
index 91b8976..a469a03 100644
--- a/client/js/models/top_navigation.js
+++ b/client/js/models/top_navigation.js
@@ -1,7 +1,7 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
+const events = require("../events.js");
+const api = require("../api.js");
class TopNavigationItem {
constructor(accessKey, title, url, available, imageUrl) {
@@ -44,18 +44,20 @@ class TopNavigation extends events.EventTarget {
activate(key) {
this.activeItem = null;
- this.dispatchEvent(new CustomEvent('activate', {
- detail: {
- key: key,
- item: key ? this.get(key) : null,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("activate", {
+ detail: {
+ key: key,
+ item: key ? this.get(key) : null,
+ },
+ })
+ );
}
setTitle(title) {
api.fetchConfig().then(() => {
document.oldTitle = null;
- document.title = api.getName() + (title ? (' – ' + title) : '');
+ document.title = api.getName() + (title ? " – " + title : "");
});
}
@@ -76,24 +78,22 @@ class TopNavigation extends events.EventTarget {
function _makeTopNavigation() {
const ret = new TopNavigation();
- ret.add('home', new TopNavigationItem('H', 'Home', ''));
- ret.add('posts', new TopNavigationItem('P', 'Posts', 'posts'));
- ret.add('upload', new TopNavigationItem('U', 'Upload', 'upload'));
- ret.add('comments', new TopNavigationItem('C', 'Comments', 'comments'));
- ret.add('tags', new TopNavigationItem('T', 'Tags', 'tags'));
- ret.add('pools', new TopNavigationItem('O', 'Pools', 'pools'));
- ret.add('users', new TopNavigationItem('S', 'Users', 'users'));
- ret.add('account', new TopNavigationItem('A', 'Account', 'user/{me}'));
- ret.add('register', new TopNavigationItem('R', 'Register', 'register'));
- ret.add('login', new TopNavigationItem('L', 'Log in', 'login'));
- ret.add('logout', new TopNavigationItem('O', 'Logout', 'logout'));
- ret.add('help', new TopNavigationItem('E', 'Help', 'help'));
+ ret.add("home", new TopNavigationItem("H", "Home", ""));
+ ret.add("posts", new TopNavigationItem("P", "Posts", "posts"));
+ ret.add("upload", new TopNavigationItem("U", "Upload", "upload"));
+ ret.add("comments", new TopNavigationItem("C", "Comments", "comments"));
+ ret.add("tags", new TopNavigationItem("T", "Tags", "tags"));
+ ret.add("pools", new TopNavigationItem("O", "Pools", "pools"));
+ ret.add("users", new TopNavigationItem("S", "Users", "users"));
+ ret.add("account", new TopNavigationItem("A", "Account", "user/{me}"));
+ ret.add("register", new TopNavigationItem("R", "Register", "register"));
+ ret.add("login", new TopNavigationItem("L", "Log in", "login"));
+ ret.add("logout", new TopNavigationItem("O", "Logout", "logout"));
+ ret.add("help", new TopNavigationItem("E", "Help", "help"));
ret.add(
- 'settings',
- new TopNavigationItem(
- null,
- '<i class=\'fa fa-cog\'></i>',
- 'settings'));
+ "settings",
+ new TopNavigationItem(null, "<i class='fa fa-cog'></i>", "settings")
+ );
return ret;
}
diff --git a/client/js/models/user.js b/client/js/models/user.js
index 40fbb14..28dc3ef 100644
--- a/client/js/models/user.js
+++ b/client/js/models/user.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
class User extends events.EventTarget {
constructor() {
@@ -64,11 +64,11 @@ class User extends events.EventTarget {
}
get avatarContent() {
- throw 'Invalid operation';
+ throw "Invalid operation";
}
get password() {
- throw 'Invalid operation';
+ throw "Invalid operation";
}
set name(value) {
@@ -102,15 +102,14 @@ class User extends events.EventTarget {
}
static get(name) {
- return api.get(uri.formatApiLink('user', name))
- .then(response => {
- return Promise.resolve(User.fromResponse(response));
- });
+ return api.get(uri.formatApiLink("user", name)).then((response) => {
+ return Promise.resolve(User.fromResponse(response));
+ });
}
save() {
const files = [];
- const detail = {version: this._version};
+ const detail = { version: this._version };
const transient = this._orig._name;
if (this._name !== this._orig._name) {
@@ -133,33 +132,40 @@ class User extends events.EventTarget {
detail.password = this._password;
}
- let promise = this._orig._name ?
- api.put(
- uri.formatApiLink('user', this._orig._name), detail, files) :
- api.post(uri.formatApiLink('users'), detail, files);
+ let promise = this._orig._name
+ ? api.put(
+ uri.formatApiLink("user", this._orig._name),
+ detail,
+ files
+ )
+ : api.post(uri.formatApiLink("users"), detail, files);
- return promise
- .then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
+ return promise.then((response) => {
+ this._updateFromResponse(response);
+ this.dispatchEvent(
+ new CustomEvent("change", {
detail: {
user: this,
},
- }));
- return Promise.resolve();
- });
+ })
+ );
+ return Promise.resolve();
+ });
}
delete() {
- return api.delete(
- uri.formatApiLink('user', this._orig._name),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- user: this,
- },
- }));
+ return api
+ .delete(uri.formatApiLink("user", this._orig._name), {
+ version: this._version,
+ })
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ user: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/models/user_list.js b/client/js/models/user_list.js
index d44622c..c537f8f 100644
--- a/client/js/models/user_list.js
+++ b/client/js/models/user_list.js
@@ -1,25 +1,31 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const AbstractList = require('./abstract_list.js');
-const User = require('./user.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const AbstractList = require("./abstract_list.js");
+const User = require("./user.js");
class UserList extends AbstractList {
static search(text, offset, limit) {
- return api.get(
- uri.formatApiLink(
- 'users', {query: text, offset: offset, limit: limit}))
- .then(response => {
- return Promise.resolve(Object.assign(
- {},
- response,
- {results: UserList.fromResponse(response.results)}));
+ return api
+ .get(
+ uri.formatApiLink("users", {
+ query: text,
+ offset: offset,
+ limit: limit,
+ })
+ )
+ .then((response) => {
+ return Promise.resolve(
+ Object.assign({}, response, {
+ results: UserList.fromResponse(response.results),
+ })
+ );
});
}
}
UserList._itemClass = User;
-UserList._itemName = 'user';
+UserList._itemName = "user";
module.exports = UserList;
diff --git a/client/js/models/user_token.js b/client/js/models/user_token.js
index e49f5aa..c9d28a2 100644
--- a/client/js/models/user_token.js
+++ b/client/js/models/user_token.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const uri = require('../util/uri.js');
-const events = require('../events.js');
+const api = require("../api.js");
+const uri = require("../util/uri.js");
+const events = require("../events.js");
class UserToken extends events.EventTarget {
constructor() {
@@ -48,12 +48,12 @@ class UserToken extends events.EventTarget {
}
static fromResponse(response) {
- if (typeof response.results !== 'undefined') {
+ if (typeof response.results !== "undefined") {
let tokenList = [];
for (let responseToken of response.results) {
const token = new UserToken();
token._updateFromResponse(responseToken);
- tokenList.push(token)
+ tokenList.push(token);
}
return tokenList;
} else {
@@ -64,15 +64,16 @@ class UserToken extends events.EventTarget {
}
static get(userName) {
- return api.get(uri.formatApiLink('user-tokens', userName))
- .then(response => {
+ return api
+ .get(uri.formatApiLink("user-tokens", userName))
+ .then((response) => {
return Promise.resolve(UserToken.fromResponse(response));
});
}
static create(userName, note, expirationTime) {
let userTokenRequest = {
- enabled: true
+ enabled: true,
};
if (note) {
userTokenRequest.note = note;
@@ -80,43 +81,54 @@ class UserToken extends events.EventTarget {
if (expirationTime) {
userTokenRequest.expirationTime = expirationTime;
}
- return api.post(uri.formatApiLink('user-token', userName), userTokenRequest)
- .then(response => {
- return Promise.resolve(UserToken.fromResponse(response))
+ return api
+ .post(uri.formatApiLink("user-token", userName), userTokenRequest)
+ .then((response) => {
+ return Promise.resolve(UserToken.fromResponse(response));
});
}
save(userName) {
- const detail = {version: this._version};
+ const detail = { version: this._version };
if (this._note !== this._orig._note) {
detail.note = this._note;
}
- return api.put(
- uri.formatApiLink('user-token', userName, this._orig._token),
- detail)
- .then(response => {
+ return api
+ .put(
+ uri.formatApiLink("user-token", userName, this._orig._token),
+ detail
+ )
+ .then((response) => {
this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- userToken: this,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("change", {
+ detail: {
+ userToken: this,
+ },
+ })
+ );
return Promise.resolve(this);
});
}
delete(userName) {
- return api.delete(
- uri.formatApiLink('user-token', userName, this._orig._token),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- userToken: this,
- },
- }));
+ return api
+ .delete(
+ uri.formatApiLink("user-token", userName, this._orig._token),
+ {
+ version: this._version,
+ }
+ )
+ .then((response) => {
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ userToken: this,
+ },
+ })
+ );
return Promise.resolve();
});
}
diff --git a/client/js/pools.js b/client/js/pools.js
index 8484f0b..aa58d5e 100644
--- a/client/js/pools.js
+++ b/client/js/pools.js
@@ -1,22 +1,23 @@
-'use strict';
+"use strict";
-const misc = require('./util/misc.js');
-const PoolCategoryList = require('./models/pool_category_list.js');
+const misc = require("./util/misc.js");
+const PoolCategoryList = require("./models/pool_category_list.js");
let _stylesheet = null;
function refreshCategoryColorMap() {
- return PoolCategoryList.get().then(response => {
+ return PoolCategoryList.get().then((response) => {
if (_stylesheet) {
document.head.removeChild(_stylesheet);
}
- _stylesheet = document.createElement('style');
+ _stylesheet = document.createElement("style");
document.head.appendChild(_stylesheet);
for (let category of response.results) {
- const ruleName = misc.makeCssName(category.name, 'pool');
+ const ruleName = misc.makeCssName(category.name, "pool");
_stylesheet.sheet.insertRule(
`.${ruleName} { color: ${category.color} }`,
- _stylesheet.sheet.cssRules.length);
+ _stylesheet.sheet.cssRules.length
+ );
}
});
}
diff --git a/client/js/router.js b/client/js/router.js
index b5b4855..460a641 100644
--- a/client/js/router.js
+++ b/client/js/router.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
// modified page.js by visionmedia
// - changed regexes to components
@@ -10,13 +10,17 @@
// - rename .save() to .replaceState()
// - offer .url
-const clickEvent = document.ontouchstart ? 'touchstart' : 'click';
-const uri = require('./util/uri.js');
+const clickEvent = document.ontouchstart ? "touchstart" : "click";
+const uri = require("./util/uri.js");
let location = window.history.location || window.location;
function _getOrigin() {
- return location.protocol + '//' + location.hostname
- + (location.port ? (':' + location.port) : '');
+ return (
+ location.protocol +
+ "//" +
+ location.hostname +
+ (location.port ? ":" + location.port : "")
+ );
}
function _isSameOrigin(href) {
@@ -24,15 +28,16 @@ function _isSameOrigin(href) {
}
function _getBaseHref() {
- const bases = document.getElementsByTagName('base');
- return bases.length > 0 ?
- bases[0].href.replace(_getOrigin(), '').replace(/\/+$/, '') : '';
+ const bases = document.getElementsByTagName("base");
+ return bases.length > 0
+ ? bases[0].href.replace(_getOrigin(), "").replace(/\/+$/, "")
+ : "";
}
class Context {
constructor(path, state) {
const base = _getBaseHref();
- path = path.indexOf('/') !== 0 ? '/' + path : path;
+ path = path.indexOf("/") !== 0 ? "/" + path : path;
path = path.indexOf(base) !== 0 ? base + path : path;
this.canonicalPath = path;
@@ -55,7 +60,7 @@ class Context {
class Route {
constructor(path) {
- this.method = 'GET';
+ this.method = "GET";
this.path = path;
this.parameterNames = [];
@@ -64,16 +69,17 @@ class Route {
} else {
let parts = [];
for (let component of this.path) {
- if (component[0] === ':') {
- parts.push('([^/]+)');
+ if (component[0] === ":") {
+ parts.push("([^/]+)");
this.parameterNames.push(component.substr(1));
- } else { // assert [a-z]+
+ } else {
+ // assert [a-z]+
parts.push(component);
}
}
- let regexString = '^/' + parts.join('/');
- regexString += '(?:/*|/((?:(?:[a-z]+=[^/]+);)*(?:[a-z]+=[^/]+)))$';
- this.parameterNames.push('variable');
+ let regexString = "^/" + parts.join("/");
+ regexString += "(?:/*|/((?:(?:[a-z]+=[^/]+);)*(?:[a-z]+=[^/]+)))$";
+ this.parameterNames.push("variable");
this.regex = new RegExp(regexString);
}
}
@@ -88,7 +94,7 @@ class Route {
}
match(path, parameters) {
- const qsIndex = path.indexOf('?');
+ const qsIndex = path.indexOf("?");
const pathname = ~qsIndex ? path.slice(0, qsIndex) : path;
const match = this.regex.exec(pathname);
@@ -104,8 +110,8 @@ class Route {
continue;
}
- if (name === 'variable') {
- for (let word of (value || '').split(/;/)) {
+ if (name === "variable") {
+ for (let word of (value || "").split(/;/)) {
const [key, subvalue] = word.split(/=/, 2);
parameters[key] = uri.unescapeParam(subvalue);
}
@@ -148,7 +154,7 @@ class Router {
this._running = true;
this._onPopState = _onPopState(this);
this._onClick = _onClick(this);
- window.addEventListener('popstate', this._onPopState, false);
+ window.addEventListener("popstate", this._onPopState, false);
document.addEventListener(clickEvent, this._onClick, false);
const url = location.pathname + location.search + location.hash;
return this.replace(url, history.state, true);
@@ -160,7 +166,7 @@ class Router {
}
this._running = false;
document.removeEventListener(clickEvent, this._onClick, false);
- window.removeEventListener('popstate', this._onPopState, false);
+ window.removeEventListener("popstate", this._onPopState, false);
}
showNoDispatch(path, state) {
@@ -199,11 +205,11 @@ class Router {
middle();
next();
};
- const callChain = (this.ctx ? this._exits : [])
- .concat(
- [swap],
- this._callbacks,
- [this._unhandled, (ctx, next) => {}]);
+ const callChain = (this.ctx ? this._exits : []).concat(
+ [swap],
+ this._callbacks,
+ [this._unhandled, (ctx, next) => {}]
+ );
let i = 0;
let fn = () => {
@@ -226,20 +232,18 @@ class Router {
}
}
-const _onPopState = router => {
+const _onPopState = (router) => {
let loaded = false;
- if (document.readyState === 'complete') {
+ if (document.readyState === "complete") {
loaded = true;
} else {
- window.addEventListener(
- 'load',
- () => {
- setTimeout(() => {
- loaded = true;
- }, 0);
- });
+ window.addEventListener("load", () => {
+ setTimeout(() => {
+ loaded = true;
+ }, 0);
+ });
}
- return e => {
+ return (e) => {
if (!loaded) {
return;
}
@@ -247,16 +251,13 @@ const _onPopState = router => {
const path = e.state.path;
router.replace(path, e.state, true);
} else {
- router.show(
- location.pathname + location.hash,
- undefined,
- false);
+ router.show(location.pathname + location.hash, undefined, false);
}
};
};
-const _onClick = router => {
- return e => {
+const _onClick = (router) => {
+ return (e) => {
if (1 !== _which(e)) {
return;
}
@@ -268,23 +269,25 @@ const _onClick = router => {
}
let el = e.path ? e.path[0] : e.target;
- while (el && el.nodeName !== 'A') {
+ while (el && el.nodeName !== "A") {
el = el.parentNode;
}
- if (!el || el.nodeName !== 'A') {
+ if (!el || el.nodeName !== "A") {
return;
}
- if (el.hasAttribute('download') ||
- el.getAttribute('rel') === 'external') {
+ if (
+ el.hasAttribute("download") ||
+ el.getAttribute("rel") === "external"
+ ) {
return;
}
- const link = el.getAttribute('href');
- if (el.pathname === location.pathname && (el.hash || '#' === link)) {
+ const link = el.getAttribute("href");
+ if (el.pathname === location.pathname && (el.hash || "#" === link)) {
return;
}
- if (link && link.indexOf('mailto:') > -1) {
+ if (link && link.indexOf("mailto:") > -1) {
return;
}
if (el.target) {
@@ -295,7 +298,7 @@ const _onClick = router => {
}
const base = _getBaseHref();
- const orig = el.pathname + el.search + (el.hash || '');
+ const orig = el.pathname + el.search + (el.hash || "");
const path = !orig.indexOf(base) ? orig.slice(base.length) : orig;
if (base && orig === path) {
diff --git a/client/js/tags.js b/client/js/tags.js
index c037f6f..ecf9b66 100644
--- a/client/js/tags.js
+++ b/client/js/tags.js
@@ -1,22 +1,23 @@
-'use strict';
+"use strict";
-const misc = require('./util/misc.js');
-const TagCategoryList = require('./models/tag_category_list.js');
+const misc = require("./util/misc.js");
+const TagCategoryList = require("./models/tag_category_list.js");
let _stylesheet = null;
function refreshCategoryColorMap() {
- return TagCategoryList.get().then(response => {
+ return TagCategoryList.get().then((response) => {
if (_stylesheet) {
document.head.removeChild(_stylesheet);
}
- _stylesheet = document.createElement('style');
+ _stylesheet = document.createElement("style");
document.head.appendChild(_stylesheet);
for (let category of response.results) {
- const ruleName = misc.makeCssName(category.name, 'tag');
+ const ruleName = misc.makeCssName(category.name, "tag");
_stylesheet.sheet.insertRule(
`.${ruleName} { color: ${category.color} }`,
- _stylesheet.sheet.cssRules.length);
+ _stylesheet.sheet.cssRules.length
+ );
}
});
}
diff --git a/client/js/templates.js b/client/js/templates.js
index f378cbc..88bd568 100644
--- a/client/js/templates.js
+++ b/client/js/templates.js
@@ -1,3 +1,3 @@
-'use strict';
+"use strict";
-module.exports = require('./.templates.autogen.js');
+module.exports = require("./.templates.autogen.js");
diff --git a/client/js/util/keyboard.js b/client/js/util/keyboard.js
index 8ee6ee9..3fe3263 100644
--- a/client/js/util/keyboard.js
+++ b/client/js/util/keyboard.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const mousetrap = require('mousetrap');
-const settings = require('../models/settings.js');
+const mousetrap = require("mousetrap");
+const settings = require("../models/settings.js");
let paused = false;
const _originalStopCallback = mousetrap.prototype.stopCallback;
// eslint-disable-next-line func-names
-mousetrap.prototype.stopCallback = function(...args) {
+mousetrap.prototype.stopCallback = function (...args) {
var self = this;
if (paused) {
return true;
diff --git a/client/js/util/markdown.js b/client/js/util/markdown.js
index 210280e..792c938 100644
--- a/client/js/util/markdown.js
+++ b/client/js/util/markdown.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const marked = require('marked');
+const marked = require("marked");
class BaseMarkdownWrapper {
preprocess(text) {
@@ -20,42 +20,44 @@ class SjisWrapper extends BaseMarkdownWrapper {
preprocess(text) {
return text.replace(
- /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/ig,
+ /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/gi,
(match, capture) => {
- var ret = '%%%SJIS' + this.buf.length;
+ var ret = "%%%SJIS" + this.buf.length;
this.buf.push(capture);
return ret;
- });
+ }
+ );
}
postprocess(text) {
return text.replace(
/(?:<p>)?%%%SJIS(\d+)(?:<\/p>)?/,
(match, capture) => {
- return '<div class="sjis">' + this.buf[capture] + '</div>';
- });
+ return '<div class="sjis">' + this.buf[capture] + "</div>";
+ }
+ );
}
}
// fix \ before ~ being stripped away
class TildeWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/\\~/g, '%%%T');
+ return text.replace(/\\~/g, "%%%T");
}
postprocess(text) {
- return text.replace(/%%%T/g, '\\~');
+ return text.replace(/%%%T/g, "\\~");
}
}
// prevent ^#... from being treated as headers, due to tag permalinks
class TagPermalinkFixWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/^#/g, '%%%#');
+ return text.replace(/^#/g, "%%%#");
}
postprocess(text) {
- return text.replace(/%%%#/g, '#');
+ return text.replace(/%%%#/g, "#");
}
}
@@ -63,19 +65,23 @@ class TagPermalinkFixWrapper extends BaseMarkdownWrapper {
class EntityPermalinkWrapper extends BaseMarkdownWrapper {
preprocess(text) {
// URL-based permalinks
+ text = text.replace(new RegExp("\\b/post/(\\d+)/?\\b", "g"), "@$1");
text = text.replace(
- new RegExp('\\b/post/(\\d+)/?\\b', 'g'), '@$1');
- text = text.replace(
- new RegExp('\\b/tag/([a-zA-Z0-9_-]+?)/?', 'g'), '#$1');
+ new RegExp("\\b/tag/([a-zA-Z0-9_-]+?)/?", "g"),
+ "#$1"
+ );
text = text.replace(
- new RegExp('\\b/user/([a-zA-Z0-9_-]+?)/?', 'g'), '+$1');
+ new RegExp("\\b/user/([a-zA-Z0-9_-]+?)/?", "g"),
+ "+$1"
+ );
text = text.replace(
/(^|^\(|(?:[^\]])\(|[\s<>\[\]\)])([+#@][a-zA-Z0-9_-]+)/g,
- '$1[$2]($2)');
- text = text.replace(/\]\(@(\d+)\)/g, '](/post/$1)');
- text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, '](/user/$1)');
- text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, '](/posts/query=$1)');
+ "$1[$2]($2)"
+ );
+ text = text.replace(/\]\(@(\d+)\)/g, "](/post/$1)");
+ text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, "](/user/$1)");
+ text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, "](/posts/query=$1)");
return text;
}
}
@@ -83,51 +89,58 @@ class EntityPermalinkWrapper extends BaseMarkdownWrapper {
class SearchPermalinkWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig,
- '<a href="/posts/query=$1"><code>$1</code></a>');
+ /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/gi,
+ '<a href="/posts/query=$1"><code>$1</code></a>'
+ );
}
}
class SpoilersWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig,
- '<span class="spoiler">$1</span>');
+ /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/gi,
+ '<span class="spoiler">$1</span>'
+ );
}
}
class SmallWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig,
- '<small>$1</small>');
+ /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/gi,
+ "<small>$1</small>"
+ );
}
}
class StrikeThroughWrapper extends BaseMarkdownWrapper {
postprocess(text) {
- text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
- return text.replace(/\\~/g, '~');
+ text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, "$1<del>$3</del>");
+ return text.replace(/\\~/g, "~");
}
}
function createRenderer() {
function sanitize(str) {
- return str.replace(/&<"/g, m => {
- if (m === '&') {
- return '&amp;';
+ return str.replace(/&<"/g, (m) => {
+ if (m === "&") {
+ return "&amp;";
}
- if (m === '<') {
- return '&lt;';
+ if (m === "<") {
+ return "&lt;";
}
- return '&quot;';
+ return "&quot;";
});
}
const renderer = new marked.Renderer();
renderer.image = (href, title, alt) => {
- let [_, url, width, height] =
- (/^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/).exec(href);
+ let [
+ _,
+ url,
+ width,
+ height,
+ ] = /^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/.exec(href);
let res = '<img src="' + sanitize(url) + '" alt="' + sanitize(alt);
if (width) {
res += '" width="' + width;
diff --git a/client/js/util/misc.js b/client/js/util/misc.js
index c922bb1..b299d3a 100644
--- a/client/js/util/misc.js
+++ b/client/js/util/misc.js
@@ -1,18 +1,18 @@
-'use strict';
+"use strict";
-const markdown = require('./markdown.js');
-const uri = require('./uri.js');
-const settings = require('../models/settings.js');
+const markdown = require("./markdown.js");
+const uri = require("./uri.js");
+const settings = require("../models/settings.js");
function decamelize(str, sep) {
- sep = sep === undefined ? '-' : sep;
+ sep = sep === undefined ? "-" : sep;
return str
- .replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2')
- .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2')
+ .replace(/([a-z\d])([A-Z])/g, "$1" + sep + "$2")
+ .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, "$1" + sep + "$2")
.toLowerCase();
}
-function *range(start = 0, end = null, step = 1) {
+function* range(start = 0, end = null, step = 1) {
if (end === null) {
end = start;
start = 0;
@@ -45,16 +45,17 @@ function formatFileSize(fileSize) {
return _formatUnits(
fileSize,
1024,
- ['B', 'K', 'M', 'G'],
+ ["B", "K", "M", "G"],
(number, suffix) => {
- const decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
+ const decimalPlaces = number < 20 && suffix !== "B" ? 1 : 0;
return number.toFixed(decimalPlaces) + suffix;
- });
+ }
+ );
}
function formatRelativeTime(timeString) {
if (!timeString) {
- return 'never';
+ return "never";
}
const then = Date.parse(timeString);
@@ -63,17 +64,17 @@ function formatRelativeTime(timeString) {
const future = now < then;
const descriptions = [
- [60, 'a few seconds', null],
- [60 * 2, 'a minute', null],
- [60 * 60, '% minutes', 60],
- [60 * 60 * 2, 'an hour', null],
- [60 * 60 * 24, '% hours', 60 * 60],
- [60 * 60 * 24 * 2, 'a day', null],
- [60 * 60 * 24 * 30.42, '% days', 60 * 60 * 24],
- [60 * 60 * 24 * 30.42 * 2, 'a month', null],
- [60 * 60 * 24 * 30.42 * 12, '% months', 60 * 60 * 24 * 30.42],
- [60 * 60 * 24 * 30.42 * 12 * 2, 'a year', null],
- [8640000000000000 /* max*/, '% years', 60 * 60 * 24 * 30.42 * 12],
+ [60, "a few seconds", null],
+ [60 * 2, "a minute", null],
+ [60 * 60, "% minutes", 60],
+ [60 * 60 * 2, "an hour", null],
+ [60 * 60 * 24, "% hours", 60 * 60],
+ [60 * 60 * 24 * 2, "a day", null],
+ [60 * 60 * 24 * 30.42, "% days", 60 * 60 * 24],
+ [60 * 60 * 24 * 30.42 * 2, "a month", null],
+ [60 * 60 * 24 * 30.42 * 12, "% months", 60 * 60 * 24 * 30.42],
+ [60 * 60 * 24 * 30.42 * 12 * 2, "a year", null],
+ [8640000000000000 /* max*/, "% years", 60 * 60 * 24 * 30.42 * 12],
];
let text = null;
@@ -87,10 +88,10 @@ function formatRelativeTime(timeString) {
}
}
- if (text === 'a day') {
- return future ? 'tomorrow' : 'yesterday';
+ if (text === "a day") {
+ return future ? "tomorrow" : "yesterday";
}
- return future ? 'in ' + text : text + ' ago';
+ return future ? "in " + text : text + " ago";
}
function formatMarkdown(text) {
@@ -102,7 +103,7 @@ function formatInlineMarkdown(text) {
}
function splitByWhitespace(str) {
- return str.split(/\s+/).filter(s => s);
+ return str.split(/\s+/).filter((s) => s);
}
function unindent(callSite, ...args) {
@@ -110,28 +111,30 @@ function unindent(callSite, ...args) {
let size = -1;
return str.replace(/\n(\s+)/g, (m, m1) => {
if (size < 0) {
- size = m1.replace(/\t/g, ' ').length;
+ size = m1.replace(/\t/g, " ").length;
}
- return '\n' + m1.slice(Math.min(m1.length, size));
+ return "\n" + m1.slice(Math.min(m1.length, size));
});
}
- if (typeof callSite === 'string') {
+ if (typeof callSite === "string") {
return format(callSite);
}
- if (typeof callSite === 'function') {
+ if (typeof callSite === "function") {
return (...args) => format(callSite(...args));
}
let output = callSite
.slice(0, args.length + 1)
- .map((text, i) => (i === 0 ? '' : args[i - 1]) + text)
- .join('');
+ .map((text, i) => (i === 0 ? "" : args[i - 1]) + text)
+ .join("");
return format(output);
}
function enableExitConfirmation() {
- window.onbeforeunload = e => {
- return 'Are you sure you want to leave? ' +
- 'Data you have entered may not be saved.';
+ window.onbeforeunload = (e) => {
+ return (
+ "Are you sure you want to leave? " +
+ "Data you have entered may not be saved."
+ );
};
}
@@ -150,16 +153,17 @@ function confirmPageExit() {
}
function makeCssName(text, suffix) {
- return suffix + '-' + text.replace(/[^a-z0-9]/g, '_');
+ return suffix + "-" + text.replace(/[^a-z0-9]/g, "_");
}
function escapeHtml(unsafe) {
- return unsafe.toString()
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&apos;');
+ return unsafe
+ .toString()
+ .replace(/&/g, "&amp;")
+ .replace(/</g, "&lt;")
+ .replace(/>/g, "&gt;")
+ .replace(/"/g, "&quot;")
+ .replace(/'/g, "&apos;");
}
function arraysDiffer(source1, source2, orderImportant) {
@@ -177,25 +181,27 @@ function arraysDiffer(source1, source2, orderImportant) {
return false;
}
return (
- source1.filter(value => !source2.includes(value)).length > 0 ||
- source2.filter(value => !source1.includes(value)).length > 0);
+ source1.filter((value) => !source2.includes(value)).length > 0 ||
+ source2.filter((value) => !source1.includes(value)).length > 0
+ );
}
function escapeSearchTerm(text) {
- return text.replace(/([a-z_-]):/g, '$1\\:');
+ return text.replace(/([a-z_-]):/g, "$1\\:");
}
function dataURItoBlob(dataURI) {
- const chunks = dataURI.split(',');
- const byteString = chunks[0].indexOf('base64') >= 0 ?
- window.atob(chunks[1]) :
- unescape(chunks[1]);
- const mimeString = chunks[0].split(':')[1].split(';')[0];
+ const chunks = dataURI.split(",");
+ const byteString =
+ chunks[0].indexOf("base64") >= 0
+ ? window.atob(chunks[1])
+ : unescape(chunks[1]);
+ const mimeString = chunks[0].split(":")[1].split(";")[0];
const data = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
data[i] = byteString.charCodeAt(i);
}
- return new Blob([data], {type: mimeString});
+ return new Blob([data], { type: mimeString });
}
function getPrettyTagName(tag) {
diff --git a/client/js/util/optimized_resize.js b/client/js/util/optimized_resize.js
index 545c458..d45df4a 100644
--- a/client/js/util/optimized_resize.js
+++ b/client/js/util/optimized_resize.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
let callbacks = [];
let running = false;
@@ -15,7 +15,7 @@ function resize() {
}
function runCallbacks() {
- callbacks.forEach(callback => {
+ callbacks.forEach((callback) => {
callback();
});
running = false;
@@ -26,8 +26,8 @@ function add(callback) {
}
function remove(callback) {
- callbacks = callbacks.filter(c => c !== callback);
+ callbacks = callbacks.filter((c) => c !== callback);
}
-window.addEventListener('resize', resize);
-module.exports = {add: add, remove: remove};
+window.addEventListener("resize", resize);
+module.exports = { add: add, remove: remove };
diff --git a/client/js/util/polyfill.js b/client/js/util/polyfill.js
index 09f5835..ec809ff 100644
--- a/client/js/util/polyfill.js
+++ b/client/js/util/polyfill.js
@@ -1,11 +1,11 @@
/* eslint-disable func-names, no-extend-native */
-'use strict';
+"use strict";
// fix iterating over NodeList in Chrome and Opera
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
-NodeList.prototype.querySelector = function(...args) {
+NodeList.prototype.querySelector = function (...args) {
for (let node of this) {
if (node.nodeType === 3) {
continue;
@@ -18,7 +18,7 @@ NodeList.prototype.querySelector = function(...args) {
return null;
};
-NodeList.prototype.querySelectorAll = function(...args) {
+NodeList.prototype.querySelectorAll = function (...args) {
let result = [];
for (let node of this) {
if (node.nodeType === 3) {
@@ -32,7 +32,7 @@ NodeList.prototype.querySelectorAll = function(...args) {
};
// non standard
-Node.prototype.prependChild = function(child) {
+Node.prototype.prependChild = function (child) {
if (this.firstChild) {
this.insertBefore(child, this.firstChild);
} else {
@@ -41,29 +41,25 @@ Node.prototype.prependChild = function(child) {
};
// non standard
-Promise.prototype.always = function(onResolveOrReject) {
- return this.then(
- onResolveOrReject,
- reason => {
- onResolveOrReject(reason);
- throw reason;
- });
+Promise.prototype.always = function (onResolveOrReject) {
+ return this.then(onResolveOrReject, (reason) => {
+ onResolveOrReject(reason);
+ throw reason;
+ });
};
// non standard
-Number.prototype.between = function(a, b, inclusive) {
+Number.prototype.between = function (a, b, inclusive) {
const min = Math.min(a, b);
const max = Math.max(a, b);
- return inclusive ?
- this >= min && this <= max :
- this > min && this < max;
+ return inclusive ? this >= min && this <= max : this > min && this < max;
};
// non standard
Promise.prototype.abort = () => {};
// non standard
-Date.prototype.addDays = function(days) {
+Date.prototype.addDays = function (days) {
let dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
diff --git a/client/js/util/progress.js b/client/js/util/progress.js
index 98df179..d6d12cb 100644
--- a/client/js/util/progress.js
+++ b/client/js/util/progress.js
@@ -1,6 +1,6 @@
-'use strict';
+"use strict";
-const nprogress = require('nprogress');
+const nprogress = require("nprogress");
let nesting = 0;
diff --git a/client/js/util/search.js b/client/js/util/search.js
index 8d5fca4..c540c2f 100644
--- a/client/js/util/search.js
+++ b/client/js/util/search.js
@@ -1,14 +1,16 @@
-'use strict';
+"use strict";
-const misc = require('./misc.js');
-const keyboard = require('../util/keyboard.js');
-const views = require('./views.js');
+const misc = require("./misc.js");
+const keyboard = require("../util/keyboard.js");
+const views = require("./views.js");
function searchInputNodeFocusHelper(inputNode) {
- keyboard.bind('q', () => {
+ keyboard.bind("q", () => {
inputNode.focus();
inputNode.setSelectionRange(
- inputNode.value.length, inputNode.value.length);
+ inputNode.value.length,
+ inputNode.value.length
+ );
});
}
diff --git a/client/js/util/touch.js b/client/js/util/touch.js
index 53b0978..64bd00a 100644
--- a/client/js/util/touch.js
+++ b/client/js/util/touch.js
@@ -1,11 +1,11 @@
-'use strict';
+"use strict";
const direction = {
NONE: null,
- LEFT: 'left',
- RIGHT: 'right',
- DOWN: 'down',
- UP: 'up'
+ LEFT: "left",
+ RIGHT: "right",
+ DOWN: "down",
+ UP: "up",
};
function handleTouchStart(handler, evt) {
@@ -37,20 +37,20 @@ function handleTouchMove(handler, evt) {
function handleTouchEnd(handler) {
switch (handler._direction) {
- case direction.NONE:
- return;
- case direction.LEFT:
- handler._swipeLeftTask();
- break;
- case direction.RIGHT:
- handler._swipeRightTask();
- break;
- case direction.DOWN:
- handler._swipeDownTask();
- break;
- case direction.UP:
- handler._swipeUpTask();
- // no default
+ case direction.NONE:
+ return;
+ case direction.LEFT:
+ handler._swipeLeftTask();
+ break;
+ case direction.RIGHT:
+ handler._swipeRightTask();
+ break;
+ case direction.DOWN:
+ handler._swipeDownTask();
+ break;
+ case direction.UP:
+ handler._swipeUpTask();
+ // no default
}
handler._xStart = null;
@@ -58,11 +58,13 @@ function handleTouchEnd(handler) {
}
class Touch {
- constructor(target,
+ constructor(
+ target,
swipeLeft = () => {},
swipeRight = () => {},
swipeUp = () => {},
- swipeDown = () => {}) {
+ swipeDown = () => {}
+ ) {
this._target = target;
this._swipeLeftTask = swipeLeft;
@@ -74,18 +76,15 @@ class Touch {
this._yStart = null;
this._direction = direction.NONE;
- this._target.addEventListener('touchstart',
- evt => {
- handleTouchStart(this, evt);
- });
- this._target.addEventListener('touchmove',
- evt => {
- handleTouchMove(this, evt);
- });
- this._target.addEventListener('touchend',
- () => {
- handleTouchEnd(this);
- });
+ this._target.addEventListener("touchstart", (evt) => {
+ handleTouchStart(this, evt);
+ });
+ this._target.addEventListener("touchmove", (evt) => {
+ handleTouchMove(this, evt);
+ });
+ this._target.addEventListener("touchend", () => {
+ handleTouchEnd(this);
+ });
}
}
diff --git a/client/js/util/uri.js b/client/js/util/uri.js
index 868545f..16fa4f8 100644
--- a/client/js/util/uri.js
+++ b/client/js/util/uri.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
function formatApiLink(...values) {
let parts = [];
@@ -9,18 +9,19 @@ function formatApiLink(...values) {
for (let key of Object.keys(value)) {
if (value[key]) {
variableParts.push(
- key + '=' + encodeURIComponent(value[key].toString()));
+ key + "=" + encodeURIComponent(value[key].toString())
+ );
}
}
if (variableParts.length) {
- parts.push('?' + variableParts.join('&'));
+ parts.push("?" + variableParts.join("&"));
}
break;
} else {
parts.push(encodeURIComponent(value.toString()));
}
}
- return '/' + parts.join('/');
+ return "/" + parts.join("/");
}
function escapeParam(text) {
@@ -40,48 +41,52 @@ function formatClientLink(...values) {
for (let key of Object.keys(value)) {
if (value[key]) {
variableParts.push(
- key + '=' + escapeParam(value[key].toString()));
+ key + "=" + escapeParam(value[key].toString())
+ );
}
}
if (variableParts.length) {
- parts.push(variableParts.join(';'));
+ parts.push(variableParts.join(";"));
}
break;
} else {
parts.push(escapeParam(value.toString()));
}
}
- return parts.join('/');
+ return parts.join("/");
}
function extractHostname(url) {
// https://stackoverflow.com/a/23945027
return url
- .split('/')[url.indexOf("//") > -1 ? 2 : 0]
- .split(':')[0]
- .split('?')[0];
+ .split("/")
+ [url.indexOf("//") > -1 ? 2 : 0].split(":")[0]
+ .split("?")[0];
}
function extractRootDomain(url) {
// https://stackoverflow.com/a/23945027
let domain = extractHostname(url);
- let splitArr = domain.split('.');
+ let splitArr = domain.split(".");
let arrLen = splitArr.length;
// if there is a subdomain
if (arrLen > 2) {
- domain = splitArr[arrLen - 2] + '.' + splitArr[arrLen - 1];
+ domain = splitArr[arrLen - 2] + "." + splitArr[arrLen - 1];
// check to see if it's using a Country Code Top Level Domain (ccTLD) (i.e. ".me.uk")
- if (splitArr[arrLen - 2].length === 2 && splitArr[arrLen - 1].length === 2) {
+ if (
+ splitArr[arrLen - 2].length === 2 &&
+ splitArr[arrLen - 1].length === 2
+ ) {
// this is using a ccTLD
- domain = splitArr[arrLen - 3] + '.' + domain;
+ domain = splitArr[arrLen - 3] + "." + domain;
}
}
return domain;
}
function escapeColons(text) {
- return text.replace(new RegExp(':', 'g'), '\\:');
+ return text.replace(new RegExp(":", "g"), "\\:");
}
module.exports = {
diff --git a/client/js/util/views.js b/client/js/util/views.js
index afdda76..f69b34b 100644
--- a/client/js/util/views.js
+++ b/client/js/util/views.js
@@ -1,27 +1,27 @@
-'use strict';
+"use strict";
-require('../util/polyfill.js');
-const api = require('../api.js');
-const templates = require('../templates.js');
+require("../util/polyfill.js");
+const api = require("../api.js");
+const templates = require("../templates.js");
const domParser = new DOMParser();
-const misc = require('./misc.js');
-const uri = require('./uri.js');
+const misc = require("./misc.js");
+const uri = require("./uri.js");
function _imbueId(options) {
if (!options.id) {
- options.id = 'gen-' + Math.random().toString(36).substring(7);
+ options.id = "gen-" + Math.random().toString(36).substring(7);
}
}
function _makeLabel(options, attrs) {
if (!options.text) {
- return '';
+ return "";
}
if (!attrs) {
attrs = {};
}
attrs.for = options.id;
- return makeElement('label', attrs, options.text);
+ return makeElement("label", attrs, options.text);
}
function makeFileSize(fileSize) {
@@ -34,251 +34,282 @@ function makeMarkdown(text) {
function makeRelativeTime(time) {
return makeElement(
- 'time', {datetime: time, title: time}, misc.formatRelativeTime(time));
+ "time",
+ { datetime: time, title: time },
+ misc.formatRelativeTime(time)
+ );
}
function makeThumbnail(url) {
return makeElement(
- 'span',
- url ?
- {class: 'thumbnail', style: `background-image: url(\'${url}\')`} :
- {class: 'thumbnail empty'},
- makeElement('img', {alt: 'thumbnail', src: url}));
+ "span",
+ url
+ ? {
+ class: "thumbnail",
+ style: `background-image: url(\'${url}\')`,
+ }
+ : { class: "thumbnail empty" },
+ makeElement("img", { alt: "thumbnail", src: url })
+ );
}
function makeRadio(options) {
_imbueId(options);
return makeElement(
- 'label',
- {for: options.id},
- makeElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'radio',
- checked: options.selectedValue === options.value,
- disabled: options.readonly,
- required: options.required,
- }),
- makeElement('span', {class: 'radio'}, options.text));
+ "label",
+ { for: options.id },
+ makeElement("input", {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: "radio",
+ checked: options.selectedValue === options.value,
+ disabled: options.readonly,
+ required: options.required,
+ }),
+ makeElement("span", { class: "radio" }, options.text)
+ );
}
function makeCheckbox(options) {
_imbueId(options);
return makeElement(
- 'label',
- {for: options.id},
- makeElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'checkbox',
- checked: options.checked !== undefined ?
- options.checked : false,
- disabled: options.readonly,
- required: options.required,
- }),
- makeElement('span', {class: 'checkbox'}, options.text));
+ "label",
+ { for: options.id },
+ makeElement("input", {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: "checkbox",
+ checked: options.checked !== undefined ? options.checked : false,
+ disabled: options.readonly,
+ required: options.required,
+ }),
+ makeElement("span", { class: "checkbox" }, options.text)
+ );
}
function makeSelect(options) {
- return _makeLabel(options) +
+ return (
+ _makeLabel(options) +
makeElement(
- 'select',
+ "select",
{
id: options.id,
name: options.name,
disabled: options.readonly,
},
- ...Object.keys(options.keyValues).map(key => makeElement(
- 'option',
- {value: key, selected: key === options.selectedKey},
- options.keyValues[key])));
+ ...Object.keys(options.keyValues).map((key) =>
+ makeElement(
+ "option",
+ { value: key, selected: key === options.selectedKey },
+ options.keyValues[key]
+ )
+ )
+ )
+ );
}
function makeInput(options) {
- options.value = options.value || '';
- return _makeLabel(options) + makeElement('input', options);
+ options.value = options.value || "";
+ return _makeLabel(options) + makeElement("input", options);
}
function makeButton(options) {
- options.type = 'button';
+ options.type = "button";
return makeInput(options);
}
function makeTextInput(options) {
- options.type = 'text';
+ options.type = "text";
return makeInput(options);
}
function makeTextarea(options) {
- const value = options.value || '';
+ const value = options.value || "";
delete options.value;
- return _makeLabel(options) + makeElement('textarea', options, value);
+ return _makeLabel(options) + makeElement("textarea", options, value);
}
function makePasswordInput(options) {
- options.type = 'password';
+ options.type = "password";
return makeInput(options);
}
function makeEmailInput(options) {
- options.type = 'email';
+ options.type = "email";
return makeInput(options);
}
function makeColorInput(options) {
- const textInput = makeElement(
- 'input', {
- type: 'text',
- value: options.value || '',
- required: options.required,
- class: 'color',
- });
- const backgroundPreviewNode = makeElement(
- 'div',
- {
- class: 'preview background-preview',
- style:
- `border-color: ${options.value};
+ const textInput = makeElement("input", {
+ type: "text",
+ value: options.value || "",
+ required: options.required,
+ class: "color",
+ });
+ const backgroundPreviewNode = makeElement("div", {
+ class: "preview background-preview",
+ style: `border-color: ${options.value};
background-color: ${options.value}`,
- });
- const textPreviewNode = makeElement(
- 'div',
- {
- class: 'preview text-preview',
- style:
- `border-color: ${options.value};
+ });
+ const textPreviewNode = makeElement("div", {
+ class: "preview text-preview",
+ style: `border-color: ${options.value};
color: ${options.value}`,
- });
+ });
return makeElement(
- 'label', {class: 'color'}, textInput, backgroundPreviewNode, textPreviewNode);
+ "label",
+ { class: "color" },
+ textInput,
+ backgroundPreviewNode,
+ textPreviewNode
+ );
}
function makeNumericInput(options) {
- options.type = 'number';
+ options.type = "number";
return makeInput(options);
}
function makeDateInput(options) {
- options.type = 'date';
- return makeInput(options)
+ options.type = "date";
+ return makeInput(options);
}
function getPostUrl(id, parameters) {
return uri.formatClientLink(
- 'post', id, parameters ? {query: parameters.query} : {});
+ "post",
+ id,
+ parameters ? { query: parameters.query } : {}
+ );
}
function getPostEditUrl(id, parameters) {
return uri.formatClientLink(
- 'post', id, 'edit', parameters ? {query: parameters.query} : {});
+ "post",
+ id,
+ "edit",
+ parameters ? { query: parameters.query } : {}
+ );
}
function makePostLink(id, includeHash) {
let text = id;
if (includeHash) {
- text = '@' + id;
+ text = "@" + id;
}
- return api.hasPrivilege('posts:view') ?
- makeElement(
- 'a',
- {href: uri.formatClientLink('post', id)},
- misc.escapeHtml(text)) :
- misc.escapeHtml(text);
+ return api.hasPrivilege("posts:view")
+ ? makeElement(
+ "a",
+ { href: uri.formatClientLink("post", id) },
+ misc.escapeHtml(text)
+ )
+ : misc.escapeHtml(text);
}
function makeTagLink(name, includeHash, includeCount, tag) {
- const category = tag ? tag.category : 'unknown';
+ const category = tag ? tag.category : "unknown";
let text = misc.getPrettyTagName(name);
if (includeHash === true) {
- text = '#' + text;
+ text = "#" + text;
}
if (includeCount === true) {
- text += ' (' + (tag ? tag.postCount : 0) + ')';
+ text += " (" + (tag ? tag.postCount : 0) + ")";
}
- return api.hasPrivilege('tags:view') ?
- makeElement(
- 'a',
- {
- href: uri.formatClientLink('tag', name),
- class: misc.makeCssName(category, 'tag'),
- },
- misc.escapeHtml(text)) :
- makeElement(
- 'span',
- {class: misc.makeCssName(category, 'tag')},
- misc.escapeHtml(text));
+ return api.hasPrivilege("tags:view")
+ ? makeElement(
+ "a",
+ {
+ href: uri.formatClientLink("tag", name),
+ class: misc.makeCssName(category, "tag"),
+ },
+ misc.escapeHtml(text)
+ )
+ : makeElement(
+ "span",
+ { class: misc.makeCssName(category, "tag") },
+ misc.escapeHtml(text)
+ );
}
function makePoolLink(id, includeHash, includeCount, pool, name) {
- const category = pool ? pool.category : 'unknown';
+ const category = pool ? pool.category : "unknown";
let text = name ? name : pool.names[0];
if (includeHash === true) {
- text = '#' + text;
+ text = "#" + text;
}
if (includeCount === true) {
- text += ' (' + (pool ? pool.postCount : 0) + ')';
+ text += " (" + (pool ? pool.postCount : 0) + ")";
}
- return api.hasPrivilege('pools:view') ?
- makeElement(
- 'a',
- {
- href: uri.formatClientLink('pool', id),
- class: misc.makeCssName(category, 'pool'),
- },
- misc.escapeHtml(text)) :
- makeElement(
- 'span',
- {class: misc.makeCssName(category, 'pool')},
- misc.escapeHtml(text));
+ return api.hasPrivilege("pools:view")
+ ? makeElement(
+ "a",
+ {
+ href: uri.formatClientLink("pool", id),
+ class: misc.makeCssName(category, "pool"),
+ },
+ misc.escapeHtml(text)
+ )
+ : makeElement(
+ "span",
+ { class: misc.makeCssName(category, "pool") },
+ misc.escapeHtml(text)
+ );
}
function makeUserLink(user) {
let text = makeThumbnail(user ? user.avatarUrl : null);
- text += user && user.name ? misc.escapeHtml(user.name) : 'Anonymous';
- const link = user && api.hasPrivilege('users:view') ?
- makeElement(
- 'a', {href: uri.formatClientLink('user', user.name)}, text) :
- text;
- return makeElement('span', {class: 'user'}, link);
+ text += user && user.name ? misc.escapeHtml(user.name) : "Anonymous";
+ const link =
+ user && api.hasPrivilege("users:view")
+ ? makeElement(
+ "a",
+ { href: uri.formatClientLink("user", user.name) },
+ text
+ )
+ : text;
+ return makeElement("span", { class: "user" }, link);
}
function makeFlexboxAlign(options) {
return [...misc.range(20)]
- .map(() => '<li class="flexbox-dummy"></li>').join('');
+ .map(() => '<li class="flexbox-dummy"></li>')
+ .join("");
}
function makeAccessKey(html, key) {
- const regex = new RegExp('(' + key + ')', 'i');
+ const regex = new RegExp("(" + key + ")", "i");
html = html.replace(
- regex, '<span class="access-key" data-accesskey="$1">$1</span>');
+ regex,
+ '<span class="access-key" data-accesskey="$1">$1</span>'
+ );
return html;
}
function _serializeElement(name, attributes) {
return [name]
- .concat(Object.keys(attributes).map(key => {
- if (attributes[key] === true) {
- return key;
- } else if (attributes[key] === false ||
- attributes[key] === undefined) {
- return '';
- }
- const attribute = misc.escapeHtml(attributes[key] || '');
- return `${key}="${attribute}"`;
- }))
- .join(' ');
+ .concat(
+ Object.keys(attributes).map((key) => {
+ if (attributes[key] === true) {
+ return key;
+ } else if (
+ attributes[key] === false ||
+ attributes[key] === undefined
+ ) {
+ return "";
+ }
+ const attribute = misc.escapeHtml(attributes[key] || "");
+ return `${key}="${attribute}"`;
+ })
+ )
+ .join(" ");
}
function makeElement(name, attrs, ...content) {
- return content.length !== undefined ?
- `<${_serializeElement(name, attrs)}>${content.join('')}</${name}>` :
- `<${_serializeElement(name, attrs)}/>`;
+ return content.length !== undefined
+ ? `<${_serializeElement(name, attrs)}>${content.join("")}</${name}>`
+ : `<${_serializeElement(name, attrs)}/>`;
}
function emptyContent(target) {
@@ -302,25 +333,25 @@ function replaceContent(target, source) {
function showMessage(target, message, className) {
if (!message) {
- message = 'Unknown message';
+ message = "Unknown message";
}
- const messagesHolderNode = target.querySelector('.messages');
+ const messagesHolderNode = target.querySelector(".messages");
if (!messagesHolderNode) {
return false;
}
- const textNode = document.createElement('div');
- textNode.innerHTML = message.replace(/\n/g, '<br/>');
- textNode.classList.add('message');
+ const textNode = document.createElement("div");
+ textNode.innerHTML = message.replace(/\n/g, "<br/>");
+ textNode.classList.add("message");
textNode.classList.add(className);
- const wrapperNode = document.createElement('div');
- wrapperNode.classList.add('message-wrapper');
+ const wrapperNode = document.createElement("div");
+ wrapperNode.classList.add("message-wrapper");
wrapperNode.appendChild(textNode);
messagesHolderNode.appendChild(wrapperNode);
return true;
}
function appendExclamationMark() {
- if (!document.title.startsWith('!')) {
+ if (!document.title.startsWith("!")) {
document.oldTitle = document.title;
document.title = `! ${document.title}`;
}
@@ -328,15 +359,15 @@ function appendExclamationMark() {
function showError(target, message) {
appendExclamationMark();
- return showMessage(target, misc.formatInlineMarkdown(message), 'error');
+ return showMessage(target, misc.formatInlineMarkdown(message), "error");
}
function showSuccess(target, message) {
- return showMessage(target, misc.formatInlineMarkdown(message), 'success');
+ return showMessage(target, misc.formatInlineMarkdown(message), "success");
}
function showInfo(target, message) {
- return showMessage(target, misc.formatInlineMarkdown(message), 'info');
+ return showMessage(target, misc.formatInlineMarkdown(message), "info");
}
function clearMessages(target) {
@@ -344,7 +375,7 @@ function clearMessages(target) {
document.title = document.oldTitle;
document.oldTitle = null;
}
- for (let messagesHolderNode of target.querySelectorAll('.messages')) {
+ for (let messagesHolderNode of target.querySelectorAll(".messages")) {
emptyContent(messagesHolderNode);
}
}
@@ -352,15 +383,15 @@ function clearMessages(target) {
function htmlToDom(html) {
// code taken from jQuery + Krasimir Tsonev's blog
const wrapMap = {
- _: [1, '<div>', '</div>'],
- option: [1, '<select multiple>', '</select>'],
- legend: [1, '<fieldset>', '</fieldset>'],
- area: [1, '<map>', '</map>'],
- param: [1, '<object>', '</object>'],
- thead: [1, '<table>', '</table>'],
- tr: [2, '<table><tbody>', '</tbody></table>'],
- td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
- col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+ _: [1, "<div>", "</div>"],
+ option: [1, "<select multiple>", "</select>"],
+ legend: [1, "<fieldset>", "</fieldset>"],
+ area: [1, "<map>", "</map>"],
+ param: [1, "<object>", "</object>"],
+ thead: [1, "<table>", "</table>"],
+ tr: [2, "<table><tbody>", "</tbody></table>"],
+ td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
+ col: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"],
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.thead;
@@ -369,8 +400,8 @@ function htmlToDom(html) {
wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
- let element = document.createElement('div');
- const match = (/<\s*(\w+)[^>]*?>/g).exec(html);
+ let element = document.createElement("div");
+ const match = /<\s*(\w+)[^>]*?>/g.exec(html);
if (match) {
const tag = match[1];
@@ -382,9 +413,9 @@ function htmlToDom(html) {
} else {
element.innerHTML = html;
}
- return element.childNodes.length > 1 ?
- element.childNodes :
- element.firstChild;
+ return element.childNodes.length > 1
+ ? element.childNodes
+ : element.firstChild;
}
function getTemplate(templatePath) {
@@ -392,7 +423,7 @@ function getTemplate(templatePath) {
throw `Missing template: ${templatePath}`;
}
const templateFactory = templates[templatePath];
- return ctx => {
+ return (ctx) => {
if (!ctx) {
ctx = {};
}
@@ -423,7 +454,7 @@ function getTemplate(templatePath) {
makeElement: makeElement,
makeCssName: misc.makeCssName,
makeNumericInput: makeNumericInput,
- formatClientLink: uri.formatClientLink
+ formatClientLink: uri.formatClientLink,
});
return htmlToDom(templateFactory(ctx));
};
@@ -432,49 +463,51 @@ function getTemplate(templatePath) {
function decorateValidator(form) {
// postpone showing form fields validity until user actually tries
// to submit it (seeing red/green form w/o doing anything breaks POLA)
- let submitButton = form.querySelector('.buttons input');
+ let submitButton = form.querySelector(".buttons input");
if (!submitButton) {
- submitButton = form.querySelector('input[type=submit]');
+ submitButton = form.querySelector("input[type=submit]");
}
if (submitButton) {
- submitButton.addEventListener('click', e => {
- form.classList.add('show-validation');
+ submitButton.addEventListener("click", (e) => {
+ form.classList.add("show-validation");
});
}
- form.addEventListener('submit', e => {
- form.classList.remove('show-validation');
+ form.addEventListener("submit", (e) => {
+ form.classList.remove("show-validation");
});
}
function disableForm(form) {
- for (let input of form.querySelectorAll('input')) {
+ for (let input of form.querySelectorAll("input")) {
input.disabled = true;
}
}
function enableForm(form) {
- for (let input of form.querySelectorAll('input')) {
+ for (let input of form.querySelectorAll("input")) {
input.disabled = false;
}
}
function syncScrollPosition() {
- window.requestAnimationFrame(
- () => {
- if (history.state && Object.prototype.hasOwnProperty.call(history.state, 'scrollX')) {
- window.scrollTo(history.state.scrollX, history.state.scrollY);
- } else {
- window.scrollTo(0, 0);
- }
- });
+ window.requestAnimationFrame(() => {
+ if (
+ history.state &&
+ Object.prototype.hasOwnProperty.call(history.state, "scrollX")
+ ) {
+ window.scrollTo(history.state.scrollX, history.state.scrollY);
+ } else {
+ window.scrollTo(0, 0);
+ }
+ });
}
function slideDown(element) {
const duration = 500;
return new Promise((resolve, reject) => {
const height = element.getBoundingClientRect().height;
- element.style.maxHeight = '0';
- element.style.overflow = 'hidden';
+ element.style.maxHeight = "0";
+ element.style.overflow = "hidden";
window.setTimeout(() => {
element.style.transition = `all ${duration}ms ease`;
element.style.maxHeight = `${height}px`;
@@ -489,7 +522,7 @@ function slideUp(element) {
const duration = 500;
return new Promise((resolve, reject) => {
const height = element.getBoundingClientRect().height;
- element.style.overflow = 'hidden';
+ element.style.overflow = "hidden";
element.style.maxHeight = `${height}px`;
element.style.transition = `all ${duration}ms ease`;
window.setTimeout(() => {
@@ -502,26 +535,27 @@ function slideUp(element) {
}
function monitorNodeRemoval(monitoredNode, callback) {
- const mutationObserver = new MutationObserver(
- mutations => {
- for (let mutation of mutations) {
- for (let node of mutation.removedNodes) {
- if (node.contains(monitoredNode)) {
- mutationObserver.disconnect();
- callback();
- return;
- }
+ const mutationObserver = new MutationObserver((mutations) => {
+ for (let mutation of mutations) {
+ for (let node of mutation.removedNodes) {
+ if (node.contains(monitoredNode)) {
+ mutationObserver.disconnect();
+ callback();
+ return;
}
}
- });
- mutationObserver.observe(
- document.body, {childList: true, subtree: true});
+ }
+ });
+ mutationObserver.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
}
-document.addEventListener('input', e => {
- if (e.target.classList.contains('color')) {
- let bkNode = e.target.parentNode.querySelector('.background-preview');
- let textNode = e.target.parentNode.querySelector('.text-preview');
+document.addEventListener("input", (e) => {
+ if (e.target.classList.contains("color")) {
+ let bkNode = e.target.parentNode.querySelector(".background-preview");
+ let textNode = e.target.parentNode.querySelector(".text-preview");
bkNode.style.backgroundColor = e.target.value;
bkNode.style.borderColor = e.target.value;
textNode.style.color = e.target.value;
@@ -530,8 +564,8 @@ document.addEventListener('input', e => {
});
// prevent opening buttons in new tabs
-document.addEventListener('click', e => {
- if (e.target.getAttribute('href') === '' && e.which === 2) {
+document.addEventListener("click", (e) => {
+ if (e.target.getAttribute("href") === "" && e.which === 2) {
e.preventDefault();
}
});
diff --git a/client/js/views/comments_page_view.js b/client/js/views/comments_page_view.js
index d5bb294..5648b3a 100644
--- a/client/js/views/comments_page_view.js
+++ b/client/js/views/comments_page_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const CommentListControl = require('../controls/comment_list_control.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const CommentListControl = require("../controls/comment_list_control.js");
-const template = views.getTemplate('comments-page');
+const template = views.getTemplate("comments-page");
class CommentsPageView extends events.EventTarget {
constructor(ctx) {
@@ -16,12 +16,14 @@ class CommentsPageView extends events.EventTarget {
for (let post of ctx.response.results) {
const commentListControl = new CommentListControl(
sourceNode.querySelector(
- `.comments-container[data-for="${post.id}"]`),
+ `.comments-container[data-for="${post.id}"]`
+ ),
post.comments,
- true);
- events.proxyEvent(commentListControl, this, 'submit');
- events.proxyEvent(commentListControl, this, 'score');
- events.proxyEvent(commentListControl, this, 'delete');
+ true
+ );
+ events.proxyEvent(commentListControl, this, "submit");
+ events.proxyEvent(commentListControl, this, "score");
+ events.proxyEvent(commentListControl, this, "delete");
}
views.replaceContent(this._hostNode, sourceNode);
diff --git a/client/js/views/empty_view.js b/client/js/views/empty_view.js
index 21843d7..59d336d 100644
--- a/client/js/views/empty_view.js
+++ b/client/js/views/empty_view.js
@@ -1,15 +1,16 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
const template = () => {
return views.htmlToDom(
- '<div class="wrapper"><div class="messages"></div></div>');
+ '<div class="wrapper"><div class="messages"></div></div>'
+ );
};
class EmptyView {
constructor() {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
}
diff --git a/client/js/views/endless_page_view.js b/client/js/views/endless_page_view.js
index f30b8fb..f94c371 100644
--- a/client/js/views/endless_page_view.js
+++ b/client/js/views/endless_page_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const views = require('../util/views.js');
+const router = require("../router.js");
+const views = require("../util/views.js");
-const holderTemplate = views.getTemplate('endless-pager');
-const pageTemplate = views.getTemplate('endless-pager-page');
+const holderTemplate = views.getTemplate("endless-pager");
+const pageTemplate = views.getTemplate("endless-pager-page");
function isScrolledIntoView(element) {
let top = 0;
@@ -12,14 +12,12 @@ function isScrolledIntoView(element) {
top += element.offsetTop || 0;
element = element.offsetParent;
} while (element);
- return (
- (top >= window.scrollY) &&
- (top <= window.scrollY + window.innerHeight));
+ return top >= window.scrollY && top <= window.scrollY + window.innerHeight;
}
class EndlessPageView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, holderTemplate());
}
@@ -40,12 +38,13 @@ class EndlessPageView {
this.defaultLimit = parseInt(ctx.parameters.limit || ctx.defaultLimit);
const initialOffset = parseInt(ctx.parameters.offset || 0);
- this._loadPage(ctx, initialOffset, this.defaultLimit, true)
- .then(pageNode => {
+ this._loadPage(ctx, initialOffset, this.defaultLimit, true).then(
+ (pageNode) => {
if (initialOffset !== 0) {
pageNode.scrollIntoView();
}
- });
+ }
+ );
this._timeout = window.setInterval(() => {
window.requestAnimationFrame(() => {
@@ -58,19 +57,19 @@ class EndlessPageView {
}
get pageHeaderHolderNode() {
- return this._hostNode.querySelector('.page-header-holder');
+ return this._hostNode.querySelector(".page-header-holder");
}
get topPageGuardNode() {
- return this._hostNode.querySelector('.page-guard.top');
+ return this._hostNode.querySelector(".page-guard.top");
}
get bottomPageGuardNode() {
- return this._hostNode.querySelector('.page-guard.bottom');
+ return this._hostNode.querySelector(".page-guard.bottom");
}
get _pagesHolderNode() {
- return this._hostNode.querySelector('.pages-holder');
+ return this._hostNode.querySelector(".pages-holder");
}
_destroy() {
@@ -82,9 +81,10 @@ class EndlessPageView {
let topPageNode = null;
let element = document.elementFromPoint(
window.innerWidth / 2,
- window.innerHeight / 2);
+ window.innerHeight / 2
+ );
while (element.parentNode !== null) {
- if (element.classList.contains('page')) {
+ if (element.classList.contains("page")) {
topPageNode = element;
break;
}
@@ -93,15 +93,17 @@ class EndlessPageView {
if (!topPageNode) {
return;
}
- let topOffset = parseInt(topPageNode.getAttribute('data-offset'));
- let topLimit = parseInt(topPageNode.getAttribute('data-limit'));
+ let topOffset = parseInt(topPageNode.getAttribute("data-offset"));
+ let topLimit = parseInt(topPageNode.getAttribute("data-limit"));
if (topOffset !== this.currentOffset) {
router.replace(
ctx.getClientUrlForPage(
topOffset,
- topLimit === ctx.defaultLimit ? null : topLimit),
+ topLimit === ctx.defaultLimit ? null : topLimit
+ ),
ctx.state,
- false);
+ false
+ );
this.currentOffset = topOffset;
}
}
@@ -115,43 +117,47 @@ class EndlessPageView {
return;
}
- if (this.minOffsetShown > 0 &&
- isScrolledIntoView(this.topPageGuardNode)) {
+ if (
+ this.minOffsetShown > 0 &&
+ isScrolledIntoView(this.topPageGuardNode)
+ ) {
this._loadPage(
ctx,
this.minOffsetShown - this.defaultLimit,
this.defaultLimit,
- false);
+ false
+ );
}
- if (this.maxOffsetShown < this.totalRecords &&
- isScrolledIntoView(this.bottomPageGuardNode)) {
- this._loadPage(
- ctx,
- this.maxOffsetShown,
- this.defaultLimit,
- true);
+ if (
+ this.maxOffsetShown < this.totalRecords &&
+ isScrolledIntoView(this.bottomPageGuardNode)
+ ) {
+ this._loadPage(ctx, this.maxOffsetShown, this.defaultLimit, true);
}
}
_loadPage(ctx, offset, limit, append) {
this._runningRequests++;
return new Promise((resolve, reject) => {
- ctx.requestPage(offset, limit).then(response => {
- if (!this._active) {
+ ctx.requestPage(offset, limit).then(
+ (response) => {
+ if (!this._active) {
+ this._runningRequests--;
+ return Promise.reject();
+ }
+ window.requestAnimationFrame(() => {
+ let pageNode = this._renderPage(ctx, append, response);
+ this._runningRequests--;
+ resolve(pageNode);
+ });
+ },
+ (error) => {
+ this.showError(error.message);
this._runningRequests--;
- return Promise.reject();
+ reject();
}
- window.requestAnimationFrame(() => {
- let pageNode = this._renderPage(ctx, append, response);
- this._runningRequests--;
- resolve(pageNode);
- });
- }, error => {
- this.showError(error.message);
- this._runningRequests--;
- reject();
- });
+ );
});
}
@@ -162,30 +168,35 @@ class EndlessPageView {
pageNode = pageTemplate({
totalPages: Math.ceil(response.total / response.limit),
page: Math.ceil(
- (response.offset + response.limit) / response.limit),
+ (response.offset + response.limit) / response.limit
+ ),
});
- pageNode.setAttribute('data-offset', response.offset);
- pageNode.setAttribute('data-limit', response.limit);
+ pageNode.setAttribute("data-offset", response.offset);
+ pageNode.setAttribute("data-limit", response.limit);
ctx.pageRenderer({
parameters: ctx.parameters,
response: response,
- hostNode: pageNode.querySelector('.page-content-holder'),
+ hostNode: pageNode.querySelector(".page-content-holder"),
});
this.totalRecords = response.total;
- if (response.offset < this.minOffsetShown ||
- this.minOffsetShown === null) {
+ if (
+ response.offset < this.minOffsetShown ||
+ this.minOffsetShown === null
+ ) {
this.minOffsetShown = response.offset;
}
- if (response.offset + response.results.length
- > this.maxOffsetShown ||
- this.maxOffsetShown === null) {
+ if (
+ response.offset + response.results.length >
+ this.maxOffsetShown ||
+ this.maxOffsetShown === null
+ ) {
this.maxOffsetShown =
response.offset + response.results.length;
}
- response.results.addEventListener('remove', e => {
+ response.results.addEventListener("remove", (e) => {
this.maxOffsetShown--;
this.totalRecords--;
});
@@ -200,10 +211,11 @@ class EndlessPageView {
window.scroll(
window.scrollX,
- window.scrollY + pageNode.offsetHeight);
+ window.scrollY + pageNode.offsetHeight
+ );
}
} else if (!response.results.length) {
- this.showInfo('No data to show');
+ this.showInfo("No data to show");
}
this._initialPageLoad = false;
diff --git a/client/js/views/help_view.js b/client/js/views/help_view.js
index 1ab016d..a88b016 100644
--- a/client/js/views/help_view.js
+++ b/client/js/views/help_view.js
@@ -1,73 +1,81 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const views = require('../util/views.js');
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('help');
+const template = views.getTemplate("help");
const sectionTemplates = {
- 'about': views.getTemplate('help-about'),
- 'keyboard': views.getTemplate('help-keyboard'),
- 'search': views.getTemplate('help-search'),
- 'comments': views.getTemplate('help-comments'),
- 'tos': views.getTemplate('help-tos'),
+ about: views.getTemplate("help-about"),
+ keyboard: views.getTemplate("help-keyboard"),
+ search: views.getTemplate("help-search"),
+ comments: views.getTemplate("help-comments"),
+ tos: views.getTemplate("help-tos"),
};
const subsectionTemplates = {
- 'search': {
- 'default': views.getTemplate('help-search-general'),
- 'posts': views.getTemplate('help-search-posts'),
- 'users': views.getTemplate('help-search-users'),
- 'tags': views.getTemplate('help-search-tags'),
- 'pools': views.getTemplate('help-search-pools'),
+ search: {
+ default: views.getTemplate("help-search-general"),
+ posts: views.getTemplate("help-search-posts"),
+ users: views.getTemplate("help-search-users"),
+ tags: views.getTemplate("help-search-tags"),
+ pools: views.getTemplate("help-search-pools"),
},
};
class HelpView {
constructor(section, subsection) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
const sourceNode = template();
const ctx = {
name: api.getName(),
};
- section = section || 'about';
+ section = section || "about";
if (section in sectionTemplates) {
views.replaceContent(
- sourceNode.querySelector('.content'),
- sectionTemplates[section](ctx));
+ sourceNode.querySelector(".content"),
+ sectionTemplates[section](ctx)
+ );
}
- subsection = subsection || 'default';
- if (section in subsectionTemplates &&
- subsection in subsectionTemplates[section]) {
+ subsection = subsection || "default";
+ if (
+ section in subsectionTemplates &&
+ subsection in subsectionTemplates[section]
+ ) {
views.replaceContent(
- sourceNode.querySelector('.subcontent'),
- subsectionTemplates[section][subsection](ctx));
+ sourceNode.querySelector(".subcontent"),
+ subsectionTemplates[section][subsection](ctx)
+ );
}
views.replaceContent(this._hostNode, sourceNode);
- for (let itemNode of
- sourceNode.querySelectorAll('.primary [data-name]')) {
+ for (let itemNode of sourceNode.querySelectorAll(
+ ".primary [data-name]"
+ )) {
itemNode.classList.toggle(
- 'active',
- itemNode.getAttribute('data-name') === section);
- if (itemNode.getAttribute('data-name') === section) {
+ "active",
+ itemNode.getAttribute("data-name") === section
+ );
+ if (itemNode.getAttribute("data-name") === section) {
itemNode.parentNode.scrollLeft =
itemNode.getBoundingClientRect().left -
- itemNode.parentNode.getBoundingClientRect().left
+ itemNode.parentNode.getBoundingClientRect().left;
}
}
- for (let itemNode of
- sourceNode.querySelectorAll('.secondary [data-name]')) {
+ for (let itemNode of sourceNode.querySelectorAll(
+ ".secondary [data-name]"
+ )) {
itemNode.classList.toggle(
- 'active',
- itemNode.getAttribute('data-name') === subsection);
- if (itemNode.getAttribute('data-name') === subsection) {
+ "active",
+ itemNode.getAttribute("data-name") === subsection
+ );
+ if (itemNode.getAttribute("data-name") === subsection) {
itemNode.parentNode.scrollLeft =
itemNode.getBoundingClientRect().left -
- itemNode.parentNode.getBoundingClientRect().left
+ itemNode.parentNode.getBoundingClientRect().left;
}
}
diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js
index 35d4742..c91363b 100644
--- a/client/js/views/home_view.js
+++ b/client/js/views/home_view.js
@@ -1,22 +1,20 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const PostContentControl = require('../controls/post_content_control.js');
-const PostNotesOverlayControl
- = require('../controls/post_notes_overlay_control.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const router = require("../router.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const PostContentControl = require("../controls/post_content_control.js");
+const PostNotesOverlayControl = require("../controls/post_notes_overlay_control.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('home');
-const footerTemplate = views.getTemplate('home-footer');
-const featuredPostTemplate = views.getTemplate('home-featured-post');
+const template = views.getTemplate("home");
+const footerTemplate = views.getTemplate("home-footer");
+const featuredPostTemplate = views.getTemplate("home-featured-post");
class HomeView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._ctx = ctx;
const sourceNode = template(ctx);
@@ -27,11 +25,16 @@ class HomeView {
this._autoCompleteControl = new TagAutoCompleteControl(
this._searchInputNode,
{
- confirm: tag => this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
- this._formNode.addEventListener(
- 'submit', e => this._evtFormSubmit(e));
+ confirm: (tag) =>
+ this._autoCompleteControl.replaceSelectedText(
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
}
}
@@ -46,59 +49,67 @@ class HomeView {
setStats(stats) {
views.replaceContent(
this._footerContainerNode,
- footerTemplate(Object.assign({}, stats, this._ctx)));
+ footerTemplate(Object.assign({}, stats, this._ctx))
+ );
}
setFeaturedPost(postInfo) {
views.replaceContent(
- this._postInfoContainerNode, featuredPostTemplate(postInfo));
+ this._postInfoContainerNode,
+ featuredPostTemplate(postInfo)
+ );
if (this._postContainerNode && postInfo.featuredPost) {
this._postContentControl = new PostContentControl(
this._postContainerNode,
postInfo.featuredPost,
() => {
- return [
- window.innerWidth * 0.8,
- window.innerHeight * 0.7,
- ];
+ return [window.innerWidth * 0.8, window.innerHeight * 0.7];
},
- 'fit-both');
+ "fit-both"
+ );
this._postNotesOverlay = new PostNotesOverlayControl(
- this._postContainerNode.querySelector('.post-overlay'),
- postInfo.featuredPost);
+ this._postContainerNode.querySelector(".post-overlay"),
+ postInfo.featuredPost
+ );
- if (postInfo.featuredPost.type === 'video'
- || postInfo.featuredPost.type === 'flash') {
+ if (
+ postInfo.featuredPost.type === "video" ||
+ postInfo.featuredPost.type === "flash"
+ ) {
this._postContentControl.disableOverlay();
}
}
}
get _footerContainerNode() {
- return this._hostNode.querySelector('.footer-container');
+ return this._hostNode.querySelector(".footer-container");
}
get _postInfoContainerNode() {
- return this._hostNode.querySelector('.post-info-container');
+ return this._hostNode.querySelector(".post-info-container");
}
get _postContainerNode() {
- return this._hostNode.querySelector('.post-container');
+ return this._hostNode.querySelector(".post-container");
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _searchInputNode() {
- return this._formNode.querySelector('input[name=search-text]');
+ return this._formNode.querySelector("input[name=search-text]");
}
_evtFormSubmit(e) {
e.preventDefault();
this._searchInputNode.blur();
- router.show(uri.formatClientLink('posts', {query: this._searchInputNode.value}));
+ router.show(
+ uri.formatClientLink("posts", {
+ query: this._searchInputNode.value,
+ })
+ );
}
}
diff --git a/client/js/views/login_view.js b/client/js/views/login_view.js
index 2c05332..64d49f9 100644
--- a/client/js/views/login_view.js
+++ b/client/js/views/login_view.js
@@ -1,52 +1,63 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('login');
+const template = views.getTemplate("login");
class LoginView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- views.replaceContent(this._hostNode, template({
- userNamePattern: api.getUserNameRegex(),
- passwordPattern: api.getPasswordRegex(),
- canSendMails: api.canSendMails(),
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ userNamePattern: api.getUserNameRegex(),
+ passwordPattern: api.getPasswordRegex(),
+ canSendMails: api.canSendMails(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._userNameInputNode.setAttribute('pattern', api.getUserNameRegex());
- this._passwordInputNode.setAttribute('pattern', api.getPasswordRegex());
- this._formNode.addEventListener('submit', e => {
+ this._userNameInputNode.setAttribute(
+ "pattern",
+ api.getUserNameRegex()
+ );
+ this._passwordInputNode.setAttribute(
+ "pattern",
+ api.getPasswordRegex()
+ );
+ this._formNode.addEventListener("submit", (e) => {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- name: this._userNameInputNode.value,
- password: this._passwordInputNode.value,
- remember: this._rememberInputNode.checked,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ name: this._userNameInputNode.value,
+ password: this._passwordInputNode.value,
+ remember: this._rememberInputNode.checked,
+ },
+ })
+ );
});
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameInputNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordInputNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _rememberInputNode() {
- return this._formNode.querySelector('[name=remember-user]');
+ return this._formNode.querySelector("[name=remember-user]");
}
disableForm() {
diff --git a/client/js/views/manual_page_view.js b/client/js/views/manual_page_view.js
index 6798e9b..390994d 100644
--- a/client/js/views/manual_page_view.js
+++ b/client/js/views/manual_page_view.js
@@ -1,11 +1,11 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const keyboard = require('../util/keyboard.js');
-const views = require('../util/views.js');
+const router = require("../router.js");
+const keyboard = require("../util/keyboard.js");
+const views = require("../util/views.js");
-const holderTemplate = views.getTemplate('manual-pager');
-const navTemplate = views.getTemplate('manual-pager-nav');
+const holderTemplate = views.getTemplate("manual-pager");
+const navTemplate = views.getTemplate("manual-pager-nav");
function _removeConsecutiveDuplicates(a) {
return a.filter((item, pos, ary) => {
@@ -22,9 +22,7 @@ function _getVisiblePageNumbers(currentPage, totalPages) {
for (let i = totalPages - threshold; i <= totalPages; i++) {
pagesVisible.push(i);
}
- for (let i = currentPage - threshold;
- i <= currentPage + threshold;
- i++) {
+ for (let i = currentPage - threshold; i <= currentPage + threshold; i++) {
pagesVisible.push(i);
}
pagesVisible = pagesVisible.filter((item, pos, ary) => {
@@ -38,18 +36,22 @@ function _getVisiblePageNumbers(currentPage, totalPages) {
}
function _getPages(
- currentPage, pageNumbers, limit, defaultLimit, removedItems) {
+ currentPage,
+ pageNumbers,
+ limit,
+ defaultLimit,
+ removedItems
+) {
const pages = new Map();
let prevPage = 0;
for (let page of pageNumbers) {
if (page !== prevPage + 1) {
- pages.set(page - 1, {ellipsis: true});
+ pages.set(page - 1, { ellipsis: true });
}
pages.set(page, {
number: page,
offset:
- ((page - 1) * limit) -
- (page > currentPage ? removedItems : 0),
+ (page - 1) * limit - (page > currentPage ? removedItems : 0),
limit: limit === defaultLimit ? null : limit,
active: currentPage === page,
});
@@ -60,7 +62,7 @@ function _getPages(
class ManualPageView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, holderTemplate());
}
@@ -70,52 +72,65 @@ class ManualPageView {
this.clearMessages();
views.emptyContent(this._pageNavNode);
- ctx.requestPage(offset, limit).then(response => {
- ctx.pageRenderer({
- parameters: ctx.parameters,
- response: response,
- hostNode: this._pageContentHolderNode,
- });
+ ctx.requestPage(offset, limit).then(
+ (response) => {
+ ctx.pageRenderer({
+ parameters: ctx.parameters,
+ response: response,
+ hostNode: this._pageContentHolderNode,
+ });
- keyboard.bind(['a', 'left'], () => {
- this._navigateToPrevNextPage('prev');
- });
- keyboard.bind(['d', 'right'], () => {
- this._navigateToPrevNextPage('next');
- });
+ keyboard.bind(["a", "left"], () => {
+ this._navigateToPrevNextPage("prev");
+ });
+ keyboard.bind(["d", "right"], () => {
+ this._navigateToPrevNextPage("next");
+ });
- let removedItems = 0;
- if (response.total) {
- this._refreshNav(
- offset, limit, response.total, removedItems, ctx);
- }
+ let removedItems = 0;
+ if (response.total) {
+ this._refreshNav(
+ offset,
+ limit,
+ response.total,
+ removedItems,
+ ctx
+ );
+ }
- if (!response.results.length) {
- this.showInfo('No data to show');
- }
+ if (!response.results.length) {
+ this.showInfo("No data to show");
+ }
- response.results.addEventListener('remove', e => {
- removedItems++;
- this._refreshNav(
- offset, limit, response.total, removedItems, ctx);
- });
+ response.results.addEventListener("remove", (e) => {
+ removedItems++;
+ this._refreshNav(
+ offset,
+ limit,
+ response.total,
+ removedItems,
+ ctx
+ );
+ });
- views.syncScrollPosition();
- }, response => {
- this.showError(response.message);
- });
+ views.syncScrollPosition();
+ },
+ (response) => {
+ this.showError(response.message);
+ }
+ );
}
get pageHeaderHolderNode() {
- return this._hostNode.querySelector('.page-header-holder');
+ return this._hostNode.querySelector(".page-header-holder");
}
get _pageContentHolderNode() {
- return this._hostNode.querySelector('.page-content-holder');
+ return this._hostNode.querySelector(".page-content-holder");
}
get _pageNavNode() {
- return this._hostNode.querySelector('.page-nav');
+ return this._hostNode.querySelector(".page-nav");
}
clearMessages() {
@@ -135,11 +150,11 @@ class ManualPageView {
}
_navigateToPrevNextPage(className) {
- const linkNode = this._hostNode.querySelector('a.' + className);
- if (linkNode.classList.contains('disabled')) {
+ const linkNode = this._hostNode.querySelector("a." + className);
+ if (linkNode.classList.contains("disabled")) {
return;
}
- router.show(linkNode.getAttribute('href'));
+ router.show(linkNode.getAttribute("href"));
}
_refreshNav(offset, limit, total, removedItems, ctx) {
@@ -147,7 +162,12 @@ class ManualPageView {
const totalPages = Math.ceil((total - removedItems) / limit);
const pageNumbers = _getVisiblePageNumbers(currentPage, totalPages);
const pages = _getPages(
- currentPage, pageNumbers, limit, ctx.defaultLimit, removedItems);
+ currentPage,
+ pageNumbers,
+ limit,
+ ctx.defaultLimit,
+ removedItems
+ );
views.replaceContent(
this._pageNavNode,
@@ -158,7 +178,8 @@ class ManualPageView {
currentPage: currentPage,
totalPages: totalPages,
pages: pages,
- }));
+ })
+ );
}
}
diff --git a/client/js/views/not_found_view.js b/client/js/views/not_found_view.js
index 487613b..c930b09 100644
--- a/client/js/views/not_found_view.js
+++ b/client/js/views/not_found_view.js
@@ -1,14 +1,14 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('not-found');
+const template = views.getTemplate("not-found");
class NotFoundView {
constructor(path) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- const sourceNode = template({path: path});
+ const sourceNode = template({ path: path });
views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
}
diff --git a/client/js/views/password_reset_view.js b/client/js/views/password_reset_view.js
index 685fe5a..82a7d50 100644
--- a/client/js/views/password_reset_view.js
+++ b/client/js/views/password_reset_view.js
@@ -1,30 +1,35 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('password-reset');
+const template = views.getTemplate("password-reset");
class PasswordResetView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- views.replaceContent(this._hostNode, template({
- canSendMails: api.canSendMails(),
- contactEmail: api.getContactEmail(),
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ canSendMails: api.canSendMails(),
+ contactEmail: api.getContactEmail(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => {
+ this._formNode.addEventListener("submit", (e) => {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- userNameOrEmail: this._userNameOrEmailFieldNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ userNameOrEmail: this._userNameOrEmailFieldNode.value,
+ },
+ })
+ );
});
}
@@ -49,11 +54,11 @@ class PasswordResetView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameOrEmailFieldNode() {
- return this._formNode.querySelector('[name=user-name]');
+ return this._formNode.querySelector("[name=user-name]");
}
}
diff --git a/client/js/views/pool_categories_view.js b/client/js/views/pool_categories_view.js
index 1928358..ac381d5 100644
--- a/client/js/views/pool_categories_view.js
+++ b/client/js/views/pool_categories_view.js
@@ -1,17 +1,17 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const PoolCategory = require('../models/pool_category.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const PoolCategory = require("../models/pool_category.js");
-const template = views.getTemplate('pool-categories');
-const rowTemplate = views.getTemplate('pool-category-row');
+const template = views.getTemplate("pool-categories");
+const rowTemplate = views.getTemplate("pool-category-row");
class PoolCategoriesView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template(ctx));
views.syncScrollPosition();
@@ -31,18 +31,22 @@ class PoolCategoriesView extends events.EventTarget {
}
if (this._addLinkNode) {
- this._addLinkNode.addEventListener(
- 'click', e => this._evtAddButtonClick(e));
+ this._addLinkNode.addEventListener("click", (e) =>
+ this._evtAddButtonClick(e)
+ );
}
- ctx.poolCategories.addEventListener(
- 'add', e => this._evtPoolCategoryAdded(e));
+ ctx.poolCategories.addEventListener("add", (e) =>
+ this._evtPoolCategoryAdded(e)
+ );
- ctx.poolCategories.addEventListener(
- 'remove', e => this._evtPoolCategoryDeleted(e));
+ ctx.poolCategories.addEventListener("remove", (e) =>
+ this._evtPoolCategoryDeleted(e)
+ );
- this._formNode.addEventListener(
- 'submit', e => this._evtSaveButtonClick(e, ctx));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtSaveButtonClick(e, ctx)
+ );
}
enableForm() {
@@ -66,44 +70,48 @@ class PoolCategoriesView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _tableBodyNode() {
- return this._hostNode.querySelector('tbody');
+ return this._hostNode.querySelector("tbody");
}
get _addLinkNode() {
- return this._hostNode.querySelector('a.add');
+ return this._hostNode.querySelector("a.add");
}
_addPoolCategoryRowNode(poolCategory) {
const rowNode = rowTemplate(
- Object.assign(
- {}, this._ctx, {poolCategory: poolCategory}));
+ Object.assign({}, this._ctx, { poolCategory: poolCategory })
+ );
- const nameInput = rowNode.querySelector('.name input');
+ const nameInput = rowNode.querySelector(".name input");
if (nameInput) {
- nameInput.addEventListener(
- 'change', e => this._evtNameChange(e, rowNode));
+ nameInput.addEventListener("change", (e) =>
+ this._evtNameChange(e, rowNode)
+ );
}
- const colorInput = rowNode.querySelector('.color input');
+ const colorInput = rowNode.querySelector(".color input");
if (colorInput) {
- colorInput.addEventListener(
- 'change', e => this._evtColorChange(e, rowNode));
+ colorInput.addEventListener("change", (e) =>
+ this._evtColorChange(e, rowNode)
+ );
}
- const removeLinkNode = rowNode.querySelector('.remove a');
+ const removeLinkNode = rowNode.querySelector(".remove a");
if (removeLinkNode) {
- removeLinkNode.addEventListener(
- 'click', e => this._evtDeleteButtonClick(e, rowNode));
+ removeLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteButtonClick(e, rowNode)
+ );
}
- const defaultLinkNode = rowNode.querySelector('.set-default a');
+ const defaultLinkNode = rowNode.querySelector(".set-default a");
if (defaultLinkNode) {
- defaultLinkNode.addEventListener(
- 'click', e => this._evtSetDefaultButtonClick(e, rowNode));
+ defaultLinkNode.addEventListener("click", (e) =>
+ this._evtSetDefaultButtonClick(e, rowNode)
+ );
}
this._tableBodyNode.appendChild(rowNode);
@@ -141,7 +149,7 @@ class PoolCategoriesView extends events.EventTarget {
_evtDeleteButtonClick(e, rowNode, link) {
e.preventDefault();
- if (e.target.classList.contains('inactive')) {
+ if (e.target.classList.contains("inactive")) {
return;
}
this._ctx.poolCategories.remove(rowNode._poolCategory);
@@ -150,16 +158,16 @@ class PoolCategoriesView extends events.EventTarget {
_evtSetDefaultButtonClick(e, rowNode) {
e.preventDefault();
this._ctx.poolCategories.defaultCategory = rowNode._poolCategory;
- const oldRowNode = rowNode.parentNode.querySelector('tr.default');
+ const oldRowNode = rowNode.parentNode.querySelector("tr.default");
if (oldRowNode) {
- oldRowNode.classList.remove('default');
+ oldRowNode.classList.remove("default");
}
- rowNode.classList.add('default');
+ rowNode.classList.add("default");
}
_evtSaveButtonClick(e, ctx) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit'));
+ this.dispatchEvent(new CustomEvent("submit"));
}
}
diff --git a/client/js/views/pool_create_view.js b/client/js/views/pool_create_view.js
index f22cf71..fc75f45 100644
--- a/client/js/views/pool_create_view.js
+++ b/client/js/views/pool_create_view.js
@@ -1,41 +1,43 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const Pool = require('../models/pool.js')
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const Pool = require("../models/pool.js");
-const template = views.getTemplate('pool-create');
+const template = views.getTemplate("pool-create");
class PoolCreateView extends events.EventTarget {
constructor(ctx) {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
if (this._namesFieldNode) {
- this._namesFieldNode.addEventListener(
- 'input', e => this._evtNameInput(e));
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
}
if (this._postsFieldNode) {
- this._postsFieldNode.addEventListener(
- 'input', e => this._evtPostsInput(e));
+ this._postsFieldNode.addEventListener("input", (e) =>
+ this._evtPostsInput(e)
+ );
}
for (let node of this._formNode.querySelectorAll(
- 'input, select, textarea, posts')) {
- node.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- });
+ "input, select, textarea, posts"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -64,19 +66,21 @@ class PoolCreateView extends events.EventTarget {
if (!list.length) {
this._namesFieldNode.setCustomValidity(
- 'Pools must have at least one name.');
+ "Pools must have at least one name."
+ );
return;
}
for (let item of list) {
if (!regex.test(item)) {
this._namesFieldNode.setCustomValidity(
- `Pool name "${item}" contains invalid symbols.`);
+ `Pool name "${item}" contains invalid symbols.`
+ );
return;
}
}
- this._namesFieldNode.setCustomValidity('');
+ this._namesFieldNode.setCustomValidity("");
}
_evtPostsInput(e) {
@@ -86,46 +90,50 @@ class PoolCreateView extends events.EventTarget {
for (let item of list) {
if (!regex.test(item)) {
this._postsFieldNode.setCustomValidity(
- `Pool ID "${item}" is not an integer.`);
+ `Pool ID "${item}" is not an integer.`
+ );
return;
}
}
- this._postsFieldNode.setCustomValidity('');
+ this._postsFieldNode.setCustomValidity("");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- names: misc.splitByWhitespace(this._namesFieldNode.value),
- category: this._categoryFieldNode.value,
- description: this._descriptionFieldNode.value,
- posts: misc.splitByWhitespace(this._postsFieldNode.value)
- .map(i => parseInt(i))
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ names: misc.splitByWhitespace(this._namesFieldNode.value),
+ category: this._categoryFieldNode.value,
+ description: this._descriptionFieldNode.value,
+ posts: misc
+ .splitByWhitespace(this._postsFieldNode.value)
+ .map((i) => parseInt(i)),
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _namesFieldNode() {
- return this._formNode.querySelector('.names input');
+ return this._formNode.querySelector(".names input");
}
get _categoryFieldNode() {
- return this._formNode.querySelector('.category select');
+ return this._formNode.querySelector(".category select");
}
get _descriptionFieldNode() {
- return this._formNode.querySelector('.description textarea');
+ return this._formNode.querySelector(".description textarea");
}
get _postsFieldNode() {
- return this._formNode.querySelector('.posts input');
+ return this._formNode.querySelector(".posts input");
}
}
diff --git a/client/js/views/pool_delete_view.js b/client/js/views/pool_delete_view.js
index d3707db..fa92a49 100644
--- a/client/js/views/pool_delete_view.js
+++ b/client/js/views/pool_delete_view.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('pool-delete');
+const template = views.getTemplate("pool-delete");
class PoolDeleteView extends events.EventTarget {
constructor(ctx) {
@@ -13,7 +13,7 @@ class PoolDeleteView extends events.EventTarget {
this._pool = ctx.pool;
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -38,15 +38,17 @@ class PoolDeleteView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- pool: this._pool,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
}
diff --git a/client/js/views/pool_edit_view.js b/client/js/views/pool_edit_view.js
index 9c118b3..b30ab9b 100644
--- a/client/js/views/pool_edit_view.js
+++ b/client/js/views/pool_edit_view.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const Post = require('../models/post.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const Post = require("../models/post.js");
-const template = views.getTemplate('pool-edit');
+const template = views.getTemplate("pool-edit");
class PoolEditView extends events.EventTarget {
constructor(ctx) {
@@ -19,24 +19,26 @@ class PoolEditView extends events.EventTarget {
views.decorateValidator(this._formNode);
if (this._namesFieldNode) {
- this._namesFieldNode.addEventListener(
- 'input', e => this._evtNameInput(e));
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
}
if (this._postsFieldNode) {
- this._postsFieldNode.addEventListener(
- 'input', e => this._evtPostsInput(e));
+ this._postsFieldNode.addEventListener("input", (e) =>
+ this._evtPostsInput(e)
+ );
}
for (let node of this._formNode.querySelectorAll(
- 'input, select, textarea, posts')) {
- node.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- });
+ "input, select, textarea, posts"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -65,19 +67,21 @@ class PoolEditView extends events.EventTarget {
if (!list.length) {
this._namesFieldNode.setCustomValidity(
- 'Pools must have at least one name.');
+ "Pools must have at least one name."
+ );
return;
}
for (let item of list) {
if (!regex.test(item)) {
this._namesFieldNode.setCustomValidity(
- `Pool name "${item}" contains invalid symbols.`);
+ `Pool name "${item}" contains invalid symbols.`
+ );
return;
}
}
- this._namesFieldNode.setCustomValidity('');
+ this._namesFieldNode.setCustomValidity("");
}
_evtPostsInput(e) {
@@ -87,57 +91,60 @@ class PoolEditView extends events.EventTarget {
for (let item of list) {
if (!regex.test(item)) {
this._postsFieldNode.setCustomValidity(
- `Pool ID "${item}" is not an integer.`);
+ `Pool ID "${item}" is not an integer.`
+ );
return;
}
}
- this._postsFieldNode.setCustomValidity('');
+ this._postsFieldNode.setCustomValidity("");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- pool: this._pool,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
- names: this._namesFieldNode ?
- misc.splitByWhitespace(this._namesFieldNode.value) :
- undefined,
+ names: this._namesFieldNode
+ ? misc.splitByWhitespace(this._namesFieldNode.value)
+ : undefined,
- category: this._categoryFieldNode ?
- this._categoryFieldNode.value :
- undefined,
+ category: this._categoryFieldNode
+ ? this._categoryFieldNode.value
+ : undefined,
- description: this._descriptionFieldNode ?
- this._descriptionFieldNode.value :
- undefined,
+ description: this._descriptionFieldNode
+ ? this._descriptionFieldNode.value
+ : undefined,
- posts: this._postsFieldNode ?
- misc.splitByWhitespace(this._postsFieldNode.value) :
- undefined,
- },
- }));
+ posts: this._postsFieldNode
+ ? misc.splitByWhitespace(this._postsFieldNode.value)
+ : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _namesFieldNode() {
- return this._formNode.querySelector('.names input');
+ return this._formNode.querySelector(".names input");
}
get _categoryFieldNode() {
- return this._formNode.querySelector('.category select');
+ return this._formNode.querySelector(".category select");
}
get _descriptionFieldNode() {
- return this._formNode.querySelector('.description textarea');
+ return this._formNode.querySelector(".description textarea");
}
get _postsFieldNode() {
- return this._formNode.querySelector('.posts input');
+ return this._formNode.querySelector(".posts input");
}
}
diff --git a/client/js/views/pool_merge_view.js b/client/js/views/pool_merge_view.js
index 09c4e8d..f0ca15a 100644
--- a/client/js/views/pool_merge_view.js
+++ b/client/js/views/pool_merge_view.js
@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
-const PoolAutoCompleteControl =
- require('../controls/pool_auto_complete_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const PoolAutoCompleteControl = require("../controls/pool_auto_complete_control.js");
-const template = views.getTemplate('pool-merge');
+const template = views.getTemplate("pool-merge");
class PoolMergeView extends events.EventTarget {
constructor(ctx) {
@@ -23,15 +22,18 @@ class PoolMergeView extends events.EventTarget {
this._autoCompleteControl = new PoolAutoCompleteControl(
this._targetPoolFieldNode,
{
- confirm: pool => {
+ confirm: (pool) => {
this._targetPoolId = pool.id;
this._autoCompleteControl.replaceSelectedText(
- pool.names[0], false);
- }
- });
+ pool.names[0],
+ false
+ );
+ },
+ }
+ );
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -56,24 +58,26 @@ class PoolMergeView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- pool: this._pool,
- targetPoolId: this._targetPoolId
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
+ targetPoolId: this._targetPoolId,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _targetPoolFieldNode() {
- return this._formNode.querySelector('input[name=target-pool]');
+ return this._formNode.querySelector("input[name=target-pool]");
}
get _addAliasCheckboxNode() {
- return this._formNode.querySelector('input[name=alias]');
+ return this._formNode.querySelector("input[name=alias]");
}
}
diff --git a/client/js/views/pool_summary_view.js b/client/js/views/pool_summary_view.js
index a5808cc..37ce1c2 100644
--- a/client/js/views/pool_summary_view.js
+++ b/client/js/views/pool_summary_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('pool-summary');
+const template = views.getTemplate("pool-summary");
class PoolSummaryView {
constructor(ctx) {
diff --git a/client/js/views/pool_view.js b/client/js/views/pool_view.js
index f296e90..12b7704 100644
--- a/client/js/views/pool_view.js
+++ b/client/js/views/pool_view.js
@@ -1,26 +1,26 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const misc = require('../util/misc.js');
-const PoolSummaryView = require('./pool_summary_view.js');
-const PoolEditView = require('./pool_edit_view.js');
-const PoolMergeView = require('./pool_merge_view.js');
-const PoolDeleteView = require('./pool_delete_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const misc = require("../util/misc.js");
+const PoolSummaryView = require("./pool_summary_view.js");
+const PoolEditView = require("./pool_edit_view.js");
+const PoolMergeView = require("./pool_merge_view.js");
+const PoolDeleteView = require("./pool_delete_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('pool');
+const template = views.getTemplate("pool");
class PoolView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.pool.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.pool.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
ctx.getPrettyPoolName = misc.getPrettyPoolName;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -28,52 +28,54 @@ class PoolView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('.pool-content-holder');
- if (ctx.section === 'edit') {
+ ctx.hostNode = this._hostNode.querySelector(".pool-content-holder");
+ if (ctx.section === "edit") {
if (!this._ctx.canEditAnything) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to edit pools.');
+ "You don't have privileges to edit pools."
+ );
} else {
this._view = new PoolEditView(ctx);
- events.proxyEvent(this._view, this, 'submit');
+ events.proxyEvent(this._view, this, "submit");
}
-
- } else if (ctx.section === 'merge') {
+ } else if (ctx.section === "merge") {
if (!this._ctx.canMerge) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to merge pools.');
+ "You don't have privileges to merge pools."
+ );
} else {
this._view = new PoolMergeView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'merge');
+ events.proxyEvent(this._view, this, "submit", "merge");
}
-
- } else if (ctx.section === 'delete') {
+ } else if (ctx.section === "delete") {
if (!this._ctx.canDelete) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to delete pools.');
+ "You don't have privileges to delete pools."
+ );
} else {
this._view = new PoolDeleteView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'delete');
+ events.proxyEvent(this._view, this, "submit", "delete");
}
-
} else {
this._view = new PoolSummaryView(ctx);
}
- events.proxyEvent(this._view, this, 'change');
+ events.proxyEvent(this._view, this, "change");
views.syncScrollPosition();
}
diff --git a/client/js/views/pools_header_view.js b/client/js/views/pools_header_view.js
index 65bbe1b..cfc6c8b 100644
--- a/client/js/views/pools_header_view.js
+++ b/client/js/views/pools_header_view.js
@@ -1,13 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const misc = require('../util/misc.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
-const PoolAutoCompleteControl =
- require('../controls/pool_auto_complete_control.js');
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const PoolAutoCompleteControl = require("../controls/pool_auto_complete_control.js");
-const template = views.getTemplate('pools-header');
+const template = views.getTemplate("pools-header");
class PoolsHeaderView extends events.EventTarget {
constructor(ctx) {
@@ -20,31 +19,41 @@ class PoolsHeaderView extends events.EventTarget {
this._autoCompleteControl = new PoolAutoCompleteControl(
this._queryInputNode,
{
- confirm: pool => this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(pool.names[0]), true),
- });
+ confirm: (pool) =>
+ this._autoCompleteControl.replaceSelectedText(
+ misc.escapeSearchTerm(pool.names[0]),
+ true
+ ),
+ }
+ );
}
search.searchInputNodeFocusHelper(this._queryInputNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _queryInputNode() {
- return this._hostNode.querySelector('[name=search-text]');
+ return this._hostNode.querySelector("[name=search-text]");
}
_evtSubmit(e) {
e.preventDefault();
this._queryInputNode.blur();
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._queryInputNode.value,
- page: 1,
- }}}));
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
}
}
diff --git a/client/js/views/pools_page_view.js b/client/js/views/pools_page_view.js
index 234d446..6230ef6 100644
--- a/client/js/views/pools_page_view.js
+++ b/client/js/views/pools_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('pools-page');
+const template = views.getTemplate("pools-page");
class PoolsPageView {
constructor(ctx) {
diff --git a/client/js/views/post_detail_view.js b/client/js/views/post_detail_view.js
index 14786d3..587c41f 100644
--- a/client/js/views/post_detail_view.js
+++ b/client/js/views/post_detail_view.js
@@ -1,21 +1,21 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const PostMergeView = require('./post_merge_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const PostMergeView = require("./post_merge_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('post-detail');
+const template = views.getTemplate("post-detail");
class PostDetailView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.post.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.post.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -23,28 +23,30 @@ class PostDetailView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('.post-content-holder');
- if (ctx.section === 'merge') {
+ ctx.hostNode = this._hostNode.querySelector(".post-content-holder");
+ if (ctx.section === "merge") {
if (!this._ctx.canMerge) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to merge posts.');
+ "You don't have privileges to merge posts."
+ );
} else {
this._view = new PostMergeView(ctx);
- events.proxyEvent(this._view, this, 'select');
- events.proxyEvent(this._view, this, 'submit', 'merge');
+ events.proxyEvent(this._view, this, "select");
+ events.proxyEvent(this._view, this, "submit", "merge");
}
-
} else {
// this._view = new PostSummaryView(ctx);
}
diff --git a/client/js/views/post_main_view.js b/client/js/views/post_main_view.js
index 6a7472c..73bb324 100644
--- a/client/js/views/post_main_view.js
+++ b/client/js/views/post_main_view.js
@@ -1,35 +1,33 @@
-'use strict';
+"use strict";
-const iosCorrectedInnerHeight = require('ios-inner-height');
-const router = require('../router.js');
-const views = require('../util/views.js');
-const uri = require('../util/uri.js');
-const keyboard = require('../util/keyboard.js');
-const Touch = require('../util/touch.js');
-const PostContentControl = require('../controls/post_content_control.js');
-const PostNotesOverlayControl =
- require('../controls/post_notes_overlay_control.js');
-const PostReadonlySidebarControl =
- require('../controls/post_readonly_sidebar_control.js');
-const PostEditSidebarControl =
- require('../controls/post_edit_sidebar_control.js');
-const CommentControl = require('../controls/comment_control.js');
-const CommentListControl = require('../controls/comment_list_control.js');
+const iosCorrectedInnerHeight = require("ios-inner-height");
+const router = require("../router.js");
+const views = require("../util/views.js");
+const uri = require("../util/uri.js");
+const keyboard = require("../util/keyboard.js");
+const Touch = require("../util/touch.js");
+const PostContentControl = require("../controls/post_content_control.js");
+const PostNotesOverlayControl = require("../controls/post_notes_overlay_control.js");
+const PostReadonlySidebarControl = require("../controls/post_readonly_sidebar_control.js");
+const PostEditSidebarControl = require("../controls/post_edit_sidebar_control.js");
+const CommentControl = require("../controls/comment_control.js");
+const CommentListControl = require("../controls/comment_list_control.js");
-const template = views.getTemplate('post-main');
+const template = views.getTemplate("post-main");
class PostMainView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
const sourceNode = template(ctx);
- const postContainerNode = sourceNode.querySelector('.post-container');
- const sidebarNode = sourceNode.querySelector('.sidebar');
+ const postContainerNode = sourceNode.querySelector(".post-container");
+ const sidebarNode = sourceNode.querySelector(".sidebar");
views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
- const topNavigationNode =
- document.body.querySelector('#top-navigation');
+ const topNavigationNode = document.body.querySelector(
+ "#top-navigation"
+ );
this._postContentControl = new PostContentControl(
postContainerNode,
@@ -43,15 +41,17 @@ class PostMainView {
margin,
iosCorrectedInnerHeight() -
topNavigationNode.getBoundingClientRect().height -
- (margin * 2),
+ margin * 2,
];
- });
+ }
+ );
this._postNotesOverlayControl = new PostNotesOverlayControl(
- postContainerNode.querySelector('.post-overlay'),
- ctx.post);
+ postContainerNode.querySelector(".post-overlay"),
+ ctx.post
+ );
- if (ctx.post.type === 'video' || ctx.post.type === 'flash') {
+ if (ctx.post.type === "video" || ctx.post.type === "flash") {
this._postContentControl.disableOverlay();
}
@@ -71,16 +71,16 @@ class PostMainView {
}
};
- keyboard.bind('e', () => {
+ keyboard.bind("e", () => {
if (ctx.editMode) {
- router.show(uri.formatClientLink('post', ctx.post.id));
+ router.show(uri.formatClientLink("post", ctx.post.id));
} else {
- router.show(uri.formatClientLink('post', ctx.post.id, 'edit'));
+ router.show(uri.formatClientLink("post", ctx.post.id, "edit"));
}
});
- keyboard.bind(['a', 'left'], showPreviousImage);
- keyboard.bind(['d', 'right'], showNextImage);
- keyboard.bind('del', e => {
+ keyboard.bind(["a", "left"], showPreviousImage);
+ keyboard.bind(["d", "right"], showNextImage);
+ keyboard.bind("del", (e) => {
if (ctx.editMode) {
this.sidebarControl._evtDeleteClick(e);
}
@@ -90,53 +90,65 @@ class PostMainView {
postContainerNode,
() => {
if (!ctx.editMode) {
- showPreviousImage()
+ showPreviousImage();
}
},
() => {
if (!ctx.editMode) {
- showNextImage()
+ showNextImage();
}
}
- )
+ );
}
_installSidebar(ctx) {
const sidebarContainerNode = document.querySelector(
- '#content-holder .sidebar-container');
+ "#content-holder .sidebar-container"
+ );
if (ctx.editMode) {
this.sidebarControl = new PostEditSidebarControl(
sidebarContainerNode,
ctx.post,
this._postContentControl,
- this._postNotesOverlayControl);
+ this._postNotesOverlayControl
+ );
} else {
this.sidebarControl = new PostReadonlySidebarControl(
- sidebarContainerNode, ctx.post, this._postContentControl);
+ sidebarContainerNode,
+ ctx.post,
+ this._postContentControl
+ );
}
}
_installCommentForm() {
const commentFormContainer = document.querySelector(
- '#content-holder .comment-form-container');
+ "#content-holder .comment-form-container"
+ );
if (!commentFormContainer) {
return;
}
this.commentControl = new CommentControl(
- commentFormContainer, null, true);
+ commentFormContainer,
+ null,
+ true
+ );
}
_installComments(comments) {
const commentsContainerNode = document.querySelector(
- '#content-holder .comments-container');
+ "#content-holder .comments-container"
+ );
if (!commentsContainerNode) {
return;
}
this.commentListControl = new CommentListControl(
- commentsContainerNode, comments);
+ commentsContainerNode,
+ comments
+ );
}
}
diff --git a/client/js/views/post_merge_view.js b/client/js/views/post_merge_view.js
index 952e3a3..20924d3 100644
--- a/client/js/views/post_merge_view.js
+++ b/client/js/views/post_merge_view.js
@@ -1,11 +1,11 @@
-'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 KEY_RETURN = 13;
-const template = views.getTemplate('post-merge');
-const sideTemplate = views.getTemplate('post-merge-side');
+const template = views.getTemplate("post-merge");
+const sideTemplate = views.getTemplate("post-merge-side");
class PostMergeView extends events.EventTarget {
constructor(ctx) {
@@ -23,7 +23,7 @@ class PostMergeView extends events.EventTarget {
this._refreshLeftSide();
this._refreshRightSide();
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -52,47 +52,61 @@ class PostMergeView extends events.EventTarget {
}
_refreshLeftSide() {
- this._refreshSide(this._leftPost, this._leftSideNode, 'left', false);
+ this._refreshSide(this._leftPost, this._leftSideNode, "left", false);
}
_refreshRightSide() {
- this._refreshSide(this._rightPost, this._rightSideNode, 'right', true);
+ this._refreshSide(this._rightPost, this._rightSideNode, "right", true);
}
_refreshSide(post, sideNode, sideName, isEditable) {
views.replaceContent(
sideNode,
- sideTemplate(Object.assign({}, this._ctx, {post: post,
- name: sideName,
- editable: isEditable})));
+ sideTemplate(
+ Object.assign({}, this._ctx, {
+ post: post,
+ name: sideName,
+ editable: isEditable,
+ })
+ )
+ );
- let postIdNode = sideNode.querySelector('input[type=text]');
- let searchButtonNode = sideNode.querySelector('input[type=button]');
+ let postIdNode = sideNode.querySelector("input[type=text]");
+ let searchButtonNode = sideNode.querySelector("input[type=button]");
if (isEditable) {
- postIdNode.addEventListener(
- 'keydown', e => this._evtPostSearchFieldKeyDown(e));
- searchButtonNode.addEventListener(
- 'click', e => this._evtPostSearchButtonClick(e, postIdNode));
+ postIdNode.addEventListener("keydown", (e) =>
+ this._evtPostSearchFieldKeyDown(e)
+ );
+ searchButtonNode.addEventListener("click", (e) =>
+ this._evtPostSearchButtonClick(e, postIdNode)
+ );
}
}
_evtSubmit(e) {
e.preventDefault();
const checkedTargetPost = this._formNode.querySelector(
- '.target-post :checked').value;
+ ".target-post :checked"
+ ).value;
const checkedTargetPostContent = this._formNode.querySelector(
- '.target-post-content :checked').value;
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- post: checkedTargetPost === 'left' ?
- this._rightPost :
- this._leftPost,
- targetPost: checkedTargetPost === 'left' ?
- this._leftPost :
- this._rightPost,
- useOldContent: checkedTargetPostContent !== checkedTargetPost,
- },
- }));
+ ".target-post-content :checked"
+ ).value;
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ post:
+ checkedTargetPost === "left"
+ ? this._rightPost
+ : this._leftPost,
+ targetPost:
+ checkedTargetPost === "left"
+ ? this._leftPost
+ : this._rightPost,
+ useOldContent:
+ checkedTargetPostContent !== checkedTargetPost,
+ },
+ })
+ );
}
_evtPostSearchFieldKeyDown(e) {
@@ -102,33 +116,37 @@ class PostMergeView extends events.EventTarget {
}
e.target.blur();
e.preventDefault();
- this.dispatchEvent(new CustomEvent('select', {
- detail: {
- postId: e.target.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("select", {
+ detail: {
+ postId: e.target.value,
+ },
+ })
+ );
}
_evtPostSearchButtonClick(e, textNode) {
e.target.blur();
e.preventDefault();
- this.dispatchEvent(new CustomEvent('select', {
- detail: {
- postId: textNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("select", {
+ detail: {
+ postId: textNode.value,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _leftSideNode() {
- return this._hostNode.querySelector('.left-post-container');
+ return this._hostNode.querySelector(".left-post-container");
}
get _rightSideNode() {
- return this._hostNode.querySelector('.right-post-container');
+ return this._hostNode.querySelector(".right-post-container");
}
}
diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js
index f1d465f..7daf4fb 100644
--- a/client/js/views/post_upload_view.js
+++ b/client/js/views/post_upload_view.js
@@ -1,22 +1,24 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const FileDropperControl = require('../controls/file_dropper_control.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const FileDropperControl = require("../controls/file_dropper_control.js");
-const template = views.getTemplate('post-upload');
-const rowTemplate = views.getTemplate('post-upload-row');
+const template = views.getTemplate("post-upload");
+const rowTemplate = views.getTemplate("post-upload-row");
function _mimeTypeToPostType(mimeType) {
- return {
- 'application/x-shockwave-flash': 'flash',
- 'image/gif': 'image',
- 'image/jpeg': 'image',
- 'image/png': 'image',
- 'image/webp': 'image',
- 'video/mp4': 'video',
- 'video/webm': 'video',
- }[mimeType] || 'unknown';
+ return (
+ {
+ "application/x-shockwave-flash": "flash",
+ "image/gif": "image",
+ "image/jpeg": "image",
+ "image/png": "image",
+ "image/webp": "image",
+ "video/mp4": "video",
+ "video/webm": "video",
+ }[mimeType] || "unknown"
+ );
}
class Uploadable extends events.EventTarget {
@@ -24,18 +26,17 @@ class Uploadable extends events.EventTarget {
super();
this.lookalikes = [];
this.lookalikesConfirmed = false;
- this.safety = 'safe';
+ this.safety = "safe";
this.flags = [];
this.tags = [];
this.relations = [];
this.anonymous = false;
}
- destroy() {
- }
+ destroy() {}
get mimeType() {
- return 'application/octet-stream';
+ return "application/octet-stream";
}
get type() {
@@ -43,11 +44,11 @@ class Uploadable extends events.EventTarget {
}
get key() {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
get name() {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
}
@@ -62,10 +63,11 @@ class File extends Uploadable {
} else {
let reader = new FileReader();
reader.readAsDataURL(file);
- reader.addEventListener('load', e => {
+ reader.addEventListener("load", (e) => {
this._previewUrl = e.target.result;
this.dispatchEvent(
- new CustomEvent('finish', {detail: {uploadable: this}}));
+ new CustomEvent("finish", { detail: { uploadable: this } })
+ );
});
}
}
@@ -97,25 +99,25 @@ class Url extends Uploadable {
constructor(url) {
super();
this.url = url;
- this.dispatchEvent(new CustomEvent('finish'));
+ this.dispatchEvent(new CustomEvent("finish"));
}
get mimeType() {
let mime = {
- 'swf': 'application/x-shockwave-flash',
- 'jpg': 'image/jpeg',
- 'png': 'image/png',
- 'gif': 'image/gif',
- 'webp': 'image/webp',
- 'mp4': 'video/mp4',
- 'webm': 'video/webm',
+ swf: "application/x-shockwave-flash",
+ jpg: "image/jpeg",
+ png: "image/png",
+ gif: "image/gif",
+ webp: "image/webp",
+ mp4: "video/mp4",
+ webm: "video/webm",
};
for (let extension of Object.keys(mime)) {
- if (this.url.toLowerCase().indexOf('.' + extension) !== -1) {
+ if (this.url.toLowerCase().indexOf("." + extension) !== -1) {
return mime[extension];
}
}
- return 'unknown';
+ return "unknown";
}
get previewUrl() {
@@ -135,7 +137,7 @@ class PostUploadView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
@@ -143,40 +145,46 @@ class PostUploadView extends events.EventTarget {
this._cancelButtonNode.disabled = true;
this._uploadables = [];
- this._uploadables.find = u => {
- return this._uploadables.findIndex(u2 => u.key === u2.key);
+ this._uploadables.find = (u) => {
+ return this._uploadables.findIndex((u2) => u.key === u2.key);
};
this._contentFileDropper = new FileDropperControl(
this._contentInputNode,
{
extraText:
- 'Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf',
+ "Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf",
allowUrls: true,
allowMultiple: true,
lock: false,
- });
- this._contentFileDropper.addEventListener(
- 'fileadd', e => this._evtFilesAdded(e));
- this._contentFileDropper.addEventListener(
- 'urladd', e => this._evtUrlsAdded(e));
+ }
+ );
+ this._contentFileDropper.addEventListener("fileadd", (e) =>
+ this._evtFilesAdded(e)
+ );
+ this._contentFileDropper.addEventListener("urladd", (e) =>
+ this._evtUrlsAdded(e)
+ );
- this._cancelButtonNode.addEventListener(
- 'click', e => this._evtCancelButtonClick(e));
- this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
- this._formNode.classList.add('inactive');
+ this._cancelButtonNode.addEventListener("click", (e) =>
+ this._evtCancelButtonClick(e)
+ );
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
+ this._formNode.classList.add("inactive");
}
enableForm() {
views.enableForm(this._formNode);
this._cancelButtonNode.disabled = true;
- this._formNode.classList.remove('uploading');
+ this._formNode.classList.remove("uploading");
}
disableForm() {
views.disableForm(this._formNode);
this._cancelButtonNode.disabled = false;
- this._formNode.classList.add('uploading');
+ this._formNode.classList.add("uploading");
}
clearMessages() {
@@ -201,7 +209,7 @@ class PostUploadView extends events.EventTarget {
}
addUploadables(uploadables) {
- this._formNode.classList.remove('inactive');
+ this._formNode.classList.remove("inactive");
let duplicatesFound = 0;
for (let uploadable of uploadables) {
if (this._uploadables.find(uploadable) !== -1) {
@@ -209,20 +217,22 @@ class PostUploadView extends events.EventTarget {
continue;
}
this._uploadables.push(uploadable);
- this._emit('change');
+ this._emit("change");
this._renderRowNode(uploadable);
- uploadable.addEventListener(
- 'finish', e => this._updateThumbnailNode(e.detail.uploadable));
+ uploadable.addEventListener("finish", (e) =>
+ this._updateThumbnailNode(e.detail.uploadable)
+ );
}
if (duplicatesFound) {
let message = null;
if (duplicatesFound < uploadables.length) {
- message = 'Some of the files were already added ' +
- 'and have been skipped.';
+ message =
+ "Some of the files were already added " +
+ "and have been skipped.";
} else if (duplicatesFound === 1) {
- message = 'This file was already added.';
+ message = "This file was already added.";
} else {
- message = 'These files were already added.';
+ message = "These files were already added.";
}
alert(message);
}
@@ -235,10 +245,10 @@ class PostUploadView extends events.EventTarget {
uploadable.destroy();
uploadable.rowNode.parentNode.removeChild(uploadable.rowNode);
this._uploadables.splice(this._uploadables.find(uploadable), 1);
- this._emit('change');
+ this._emit("change");
if (!this._uploadables.length) {
- this._formNode.classList.add('inactive');
- this._submitButtonNode.value = 'Upload all';
+ this._formNode.classList.add("inactive");
+ this._submitButtonNode.value = "Upload all";
}
}
@@ -248,16 +258,16 @@ class PostUploadView extends events.EventTarget {
}
_evtFilesAdded(e) {
- this.addUploadables(e.detail.files.map(file => new File(file)));
+ this.addUploadables(e.detail.files.map((file) => new File(file)));
}
_evtUrlsAdded(e) {
- this.addUploadables(e.detail.urls.map(url => new Url(url)));
+ this.addUploadables(e.detail.urls.map((url) => new Url(url)));
}
_evtCancelButtonClick(e) {
e.preventDefault();
- this._emit('cancel');
+ this._emit("cancel");
}
_evtFormSubmit(e) {
@@ -265,19 +275,21 @@ class PostUploadView extends events.EventTarget {
for (let uploadable of this._uploadables) {
this._updateUploadableFromDom(uploadable);
}
- this._submitButtonNode.value = 'Resume upload';
- this._emit('submit');
+ this._submitButtonNode.value = "Resume upload";
+ this._emit("submit");
}
_updateUploadableFromDom(uploadable) {
const rowNode = uploadable.rowNode;
- const safetyNode = rowNode.querySelector('.safety input:checked');
+ const safetyNode = rowNode.querySelector(".safety input:checked");
if (safetyNode) {
uploadable.safety = safetyNode.value;
}
- const anonymousNode = rowNode.querySelector('.anonymous input:checked');
+ const anonymousNode = rowNode.querySelector(
+ ".anonymous input:checked"
+ );
if (anonymousNode) {
uploadable.anonymous = true;
}
@@ -286,11 +298,14 @@ class PostUploadView extends events.EventTarget {
uploadable.relations = [];
for (let [i, lookalike] of uploadable.lookalikes.entries()) {
let lookalikeNode = rowNode.querySelector(
- `.lookalikes li:nth-child(${i + 1})`);
- if (lookalikeNode.querySelector('[name=copy-tags]').checked) {
- uploadable.tags = uploadable.tags.concat(lookalike.post.tagNames);
+ `.lookalikes li:nth-child(${i + 1})`
+ );
+ if (lookalikeNode.querySelector("[name=copy-tags]").checked) {
+ uploadable.tags = uploadable.tags.concat(
+ lookalike.post.tagNames
+ );
}
- if (lookalikeNode.querySelector('[name=add-relation]').checked) {
+ if (lookalikeNode.querySelector("[name=add-relation]").checked) {
uploadable.relations.push(lookalike.post.id);
}
}
@@ -317,78 +332,97 @@ class PostUploadView extends events.EventTarget {
this._uploadables[index + delta] = uploadable1;
if (delta === 1) {
this._listNode.insertBefore(
- uploadable2.rowNode, uploadable1.rowNode);
+ uploadable2.rowNode,
+ uploadable1.rowNode
+ );
} else {
this._listNode.insertBefore(
- uploadable1.rowNode, uploadable2.rowNode);
+ uploadable1.rowNode,
+ uploadable2.rowNode
+ );
}
}
}
_emit(eventType) {
this.dispatchEvent(
- new CustomEvent(
- eventType,
- {detail: {
+ new CustomEvent(eventType, {
+ detail: {
uploadables: this._uploadables,
skipDuplicates: this._skipDuplicatesCheckboxNode.checked,
- }}));
+ },
+ })
+ );
}
_renderRowNode(uploadable) {
- const rowNode = rowTemplate(Object.assign(
- {}, this._ctx, {uploadable: uploadable}));
+ const rowNode = rowTemplate(
+ Object.assign({}, this._ctx, { uploadable: uploadable })
+ );
if (uploadable.rowNode) {
uploadable.rowNode.parentNode.replaceChild(
- rowNode, uploadable.rowNode);
+ rowNode,
+ uploadable.rowNode
+ );
} else {
this._listNode.appendChild(rowNode);
}
uploadable.rowNode = rowNode;
- rowNode.querySelector('a.remove').addEventListener('click',
- e => this._evtRemoveClick(e, uploadable));
- rowNode.querySelector('a.move-up').addEventListener('click',
- e => this._evtMoveClick(e, uploadable, -1));
- rowNode.querySelector('a.move-down').addEventListener('click',
- e => this._evtMoveClick(e, uploadable, 1));
+ rowNode
+ .querySelector("a.remove")
+ .addEventListener("click", (e) =>
+ this._evtRemoveClick(e, uploadable)
+ );
+ rowNode
+ .querySelector("a.move-up")
+ .addEventListener("click", (e) =>
+ this._evtMoveClick(e, uploadable, -1)
+ );
+ rowNode
+ .querySelector("a.move-down")
+ .addEventListener("click", (e) =>
+ this._evtMoveClick(e, uploadable, 1)
+ );
}
_updateThumbnailNode(uploadable) {
- const rowNode = rowTemplate(Object.assign(
- {}, this._ctx, {uploadable: uploadable}));
+ const rowNode = rowTemplate(
+ Object.assign({}, this._ctx, { uploadable: uploadable })
+ );
views.replaceContent(
- uploadable.rowNode.querySelector('.thumbnail'),
- rowNode.querySelector('.thumbnail').childNodes);
+ uploadable.rowNode.querySelector(".thumbnail"),
+ rowNode.querySelector(".thumbnail").childNodes
+ );
}
get _uploading() {
- return this._formNode.classList.contains('uploading');
+ return this._formNode.classList.contains("uploading");
}
get _listNode() {
- return this._hostNode.querySelector('.uploadables-container');
+ return this._hostNode.querySelector(".uploadables-container");
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _skipDuplicatesCheckboxNode() {
- return this._hostNode.querySelector('form [name=skip-duplicates]');
+ return this._hostNode.querySelector("form [name=skip-duplicates]");
}
get _submitButtonNode() {
- return this._hostNode.querySelector('form [type=submit]');
+ return this._hostNode.querySelector("form [type=submit]");
}
get _cancelButtonNode() {
- return this._hostNode.querySelector('form .cancel');
+ return this._hostNode.querySelector("form .cancel");
}
get _contentInputNode() {
- return this._formNode.querySelector('.dropper-container');
+ return this._formNode.querySelector(".dropper-container");
}
}
diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js
index 0797fff..81546a7 100644
--- a/client/js/views/posts_header_view.js
+++ b/client/js/views/posts_header_view.js
@@ -1,53 +1,56 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const settings = require('../models/settings.js');
-const keyboard = require('../util/keyboard.js');
-const misc = require('../util/misc.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const events = require("../events.js");
+const settings = require("../models/settings.js");
+const keyboard = require("../util/keyboard.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('posts-header');
+const template = views.getTemplate("posts-header");
class BulkEditor extends events.EventTarget {
constructor(hostNode) {
super();
this._hostNode = hostNode;
- this._openLinkNode.addEventListener(
- 'click', e => this._evtOpenLinkClick(e));
- this._closeLinkNode.addEventListener(
- 'click', e => this._evtCloseLinkClick(e));
+ this._openLinkNode.addEventListener("click", (e) =>
+ this._evtOpenLinkClick(e)
+ );
+ this._closeLinkNode.addEventListener("click", (e) =>
+ this._evtCloseLinkClick(e)
+ );
}
get opened() {
- return this._hostNode.classList.contains('opened') &&
- !this._hostNode.classList.contains('hidden');
+ return (
+ this._hostNode.classList.contains("opened") &&
+ !this._hostNode.classList.contains("hidden")
+ );
}
get _openLinkNode() {
- return this._hostNode.querySelector('.open');
+ return this._hostNode.querySelector(".open");
}
get _closeLinkNode() {
- return this._hostNode.querySelector('.close');
+ return this._hostNode.querySelector(".close");
}
toggleOpen(state) {
- this._hostNode.classList.toggle('opened', state);
+ this._hostNode.classList.toggle("opened", state);
}
toggleHide(state) {
- this._hostNode.classList.toggle('hidden', state);
+ this._hostNode.classList.toggle("hidden", state);
}
_evtOpenLinkClick(e) {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
_evtCloseLinkClick(e) {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
}
@@ -55,13 +58,13 @@ class BulkSafetyEditor extends BulkEditor {
_evtOpenLinkClick(e) {
e.preventDefault();
this.toggleOpen(true);
- this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("open", { detail: {} }));
}
_evtCloseLinkClick(e) {
e.preventDefault();
this.toggleOpen(false);
- this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("close", { detail: {} }));
}
}
@@ -71,10 +74,16 @@ class BulkTagEditor extends BulkEditor {
this._autoCompleteControl = new TagAutoCompleteControl(
this._inputNode,
{
- confirm: tag => this._autoCompleteControl.replaceSelectedText(
- tag.names[0], false),
- });
- this._hostNode.addEventListener('submit', e => this._evtFormSubmit(e));
+ confirm: (tag) =>
+ this._autoCompleteControl.replaceSelectedText(
+ tag.names[0],
+ false
+ ),
+ }
+ );
+ this._hostNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
}
get value() {
@@ -82,7 +91,7 @@ class BulkTagEditor extends BulkEditor {
}
get _inputNode() {
- return this._hostNode.querySelector('input[name=tag]');
+ return this._hostNode.querySelector("input[name=tag]");
}
focus() {
@@ -96,22 +105,22 @@ class BulkTagEditor extends BulkEditor {
_evtFormSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("submit", { detail: {} }));
}
_evtOpenLinkClick(e) {
e.preventDefault();
this.toggleOpen(true);
this.focus();
- this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("open", { detail: {} }));
}
_evtCloseLinkClick(e) {
e.preventDefault();
- this._inputNode.value = '';
+ this._inputNode.value = "";
this.toggleOpen(false);
this.blur();
- this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("close", { detail: {} }));
}
}
@@ -127,18 +136,25 @@ class PostsHeaderView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._queryInputNode,
{
- confirm: tag => this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
+ confirm: (tag) =>
+ this._autoCompleteControl.replaceSelectedText(
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
- keyboard.bind('p', () => this._focusFirstPostNode());
+ keyboard.bind("p", () => this._focusFirstPostNode());
search.searchInputNodeFocusHelper(this._queryInputNode);
for (let safetyButtonNode of this._safetyButtonNodes) {
- safetyButtonNode.addEventListener(
- 'click', e => this._evtSafetyButtonClick(e));
+ safetyButtonNode.addEventListener("click", (e) =>
+ this._evtSafetyButtonClick(e)
+ );
}
- this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
this._bulkEditors = [];
if (this._bulkEditTagsNode) {
@@ -148,19 +164,20 @@ class PostsHeaderView extends events.EventTarget {
if (this._bulkEditSafetyNode) {
this._bulkSafetyEditor = new BulkSafetyEditor(
- this._bulkEditSafetyNode);
+ this._bulkEditSafetyNode
+ );
this._bulkEditors.push(this._bulkSafetyEditor);
}
for (let editor of this._bulkEditors) {
- editor.addEventListener('submit', e => {
+ editor.addEventListener("submit", (e) => {
this._navigate();
});
- editor.addEventListener('open', e => {
+ editor.addEventListener("open", (e) => {
this._hideBulkEditorsExcept(editor);
this._navigate();
});
- editor.addEventListener('close', e => {
+ editor.addEventListener("close", (e) => {
this._closeAndShowAllBulkEditors();
this._navigate();
});
@@ -174,23 +191,23 @@ class PostsHeaderView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form.search');
+ return this._hostNode.querySelector("form.search");
}
get _safetyButtonNodes() {
- return this._hostNode.querySelectorAll('form .safety');
+ return this._hostNode.querySelectorAll("form .safety");
}
get _queryInputNode() {
- return this._hostNode.querySelector('form [name=search-text]');
+ return this._hostNode.querySelector("form [name=search-text]");
}
get _bulkEditTagsNode() {
- return this._hostNode.querySelector('.bulk-edit-tags');
+ return this._hostNode.querySelector(".bulk-edit-tags");
}
get _bulkEditSafetyNode() {
- return this._hostNode.querySelector('.bulk-edit-safety');
+ return this._hostNode.querySelector(".bulk-edit-safety");
}
_openBulkEditor(editor) {
@@ -216,20 +233,23 @@ class PostsHeaderView extends events.EventTarget {
_evtSafetyButtonClick(e, url) {
e.preventDefault();
- e.target.classList.toggle('disabled');
- const safety = e.target.getAttribute('data-safety');
+ e.target.classList.toggle("disabled");
+ const safety = e.target.getAttribute("data-safety");
let browsingSettings = settings.get();
- browsingSettings.listPosts[safety] =
- !browsingSettings.listPosts[safety];
+ browsingSettings.listPosts[safety] = !browsingSettings.listPosts[
+ safety
+ ];
settings.save(browsingSettings, true);
this.dispatchEvent(
- new CustomEvent(
- 'navigate', {
- detail: {
- parameters: Object.assign(
- {}, this._ctx.parameters, {tag: null, offset: 0}),
- },
- }));
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: Object.assign({}, this._ctx.parameters, {
+ tag: null,
+ offset: 0,
+ }),
+ },
+ })
+ );
}
_evtFormSubmit(e) {
@@ -239,27 +259,33 @@ class PostsHeaderView extends events.EventTarget {
_navigate() {
this._autoCompleteControl.hide();
- let parameters = {query: this._queryInputNode.value};
+ let parameters = { query: this._queryInputNode.value };
// convert falsy values to an empty string "" so that we can correctly compare with the current query
- const prevQuery = this._ctx.parameters.query ? this._ctx.parameters.query : "";
- parameters.offset = parameters.query === prevQuery ? this._ctx.parameters.offset : 0;
+ const prevQuery = this._ctx.parameters.query
+ ? this._ctx.parameters.query
+ : "";
+ parameters.offset =
+ parameters.query === prevQuery ? this._ctx.parameters.offset : 0;
if (this._bulkTagEditor && this._bulkTagEditor.opened) {
parameters.tag = this._bulkTagEditor.value;
this._bulkTagEditor.blur();
} else {
parameters.tag = null;
}
- parameters.safety = (
- this._bulkSafetyEditor &&
- this._bulkSafetyEditor.opened ? '1' : null);
+ parameters.safety =
+ this._bulkSafetyEditor && this._bulkSafetyEditor.opened
+ ? "1"
+ : null;
this.dispatchEvent(
- new CustomEvent('navigate', {detail: {parameters: parameters}}));
+ new CustomEvent("navigate", { detail: { parameters: parameters } })
+ );
}
_focusFirstPostNode() {
- const firstPostNode =
- document.body.querySelector('.post-list li:first-child a');
+ const firstPostNode = document.body.querySelector(
+ ".post-list li:first-child a"
+ );
if (firstPostNode) {
firstPostNode.focus();
}
diff --git a/client/js/views/posts_page_view.js b/client/js/views/posts_page_view.js
index 84521e3..ba07a63 100644
--- a/client/js/views/posts_page_view.js
+++ b/client/js/views/posts_page_view.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('posts-page');
+const template = views.getTemplate("posts-page");
class PostsPageView extends events.EventTarget {
constructor(ctx) {
@@ -15,26 +15,28 @@ class PostsPageView extends events.EventTarget {
this._postIdToPost = {};
for (let post of ctx.response.results) {
this._postIdToPost[post.id] = post;
- post.addEventListener('change', e => this._evtPostChange(e));
+ post.addEventListener("change", (e) => this._evtPostChange(e));
}
this._postIdToListItemNode = {};
for (let listItemNode of this._listItemNodes) {
- const postId = listItemNode.getAttribute('data-post-id');
+ const postId = listItemNode.getAttribute("data-post-id");
const post = this._postIdToPost[postId];
this._postIdToListItemNode[postId] = listItemNode;
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
if (tagFlipperNode) {
- tagFlipperNode.addEventListener(
- 'click', e => this._evtBulkEditTagsClick(e, post));
+ tagFlipperNode.addEventListener("click", (e) =>
+ this._evtBulkEditTagsClick(e, post)
+ );
}
const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode);
if (safetyFlipperNode) {
- for (let linkNode of safetyFlipperNode.querySelectorAll('a')) {
- linkNode.addEventListener(
- 'click', e => this._evtBulkEditSafetyClick(e, post));
+ for (let linkNode of safetyFlipperNode.querySelectorAll("a")) {
+ linkNode.addEventListener("click", (e) =>
+ this._evtBulkEditSafetyClick(e, post)
+ );
}
}
}
@@ -43,21 +45,21 @@ class PostsPageView extends events.EventTarget {
}
get _listItemNodes() {
- return this._hostNode.querySelectorAll('li');
+ return this._hostNode.querySelectorAll("li");
}
_getTagFlipperNode(listItemNode) {
- return listItemNode.querySelector('.tag-flipper');
+ return listItemNode.querySelector(".tag-flipper");
}
_getSafetyFlipperNode(listItemNode) {
- return listItemNode.querySelector('.safety-flipper');
+ return listItemNode.querySelector(".safety-flipper");
}
_evtPostChange(e) {
const listItemNode = this._postIdToListItemNode[e.detail.post.id];
- for (let node of listItemNode.querySelectorAll('[data-disabled]')) {
- node.removeAttribute('data-disabled');
+ for (let node of listItemNode.querySelectorAll("[data-disabled]")) {
+ node.removeAttribute("data-disabled");
}
this._syncBulkEditorsHighlights();
}
@@ -65,35 +67,41 @@ class PostsPageView extends events.EventTarget {
_evtBulkEditTagsClick(e, post) {
e.preventDefault();
const linkNode = e.target;
- if (linkNode.getAttribute('data-disabled')) {
+ if (linkNode.getAttribute("data-disabled")) {
return;
}
- linkNode.setAttribute('data-disabled', true);
+ linkNode.setAttribute("data-disabled", true);
this.dispatchEvent(
new CustomEvent(
- linkNode.classList.contains('tagged') ? 'untag' : 'tag',
- {detail: {post: post}}));
+ linkNode.classList.contains("tagged") ? "untag" : "tag",
+ {
+ detail: { post: post },
+ }
+ )
+ );
}
_evtBulkEditSafetyClick(e, post) {
e.preventDefault();
const linkNode = e.target;
- if (linkNode.getAttribute('data-disabled')) {
+ if (linkNode.getAttribute("data-disabled")) {
return;
}
- const newSafety = linkNode.getAttribute('data-safety');
+ const newSafety = linkNode.getAttribute("data-safety");
if (post.safety === newSafety) {
return;
}
- linkNode.setAttribute('data-disabled', true);
+ linkNode.setAttribute("data-disabled", true);
this.dispatchEvent(
- new CustomEvent(
- 'changeSafety', {detail: {post: post, safety: newSafety}}));
+ new CustomEvent("changeSafety", {
+ detail: { post: post, safety: newSafety },
+ })
+ );
}
_syncBulkEditorsHighlights() {
for (let listItemNode of this._listItemNodes) {
- const postId = listItemNode.getAttribute('data-post-id');
+ const postId = listItemNode.getAttribute("data-post-id");
const post = this._postIdToPost[postId];
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
@@ -102,14 +110,17 @@ class PostsPageView extends events.EventTarget {
for (let tag of this._ctx.bulkEdit.tags) {
tagged &= post.tags.isTaggedWith(tag);
}
- tagFlipperNode.classList.toggle('tagged', tagged);
+ tagFlipperNode.classList.toggle("tagged", tagged);
}
const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode);
if (safetyFlipperNode) {
- for (let linkNode of safetyFlipperNode.querySelectorAll('a')) {
- const safety = linkNode.getAttribute('data-safety');
- linkNode.classList.toggle('active', post.safety === safety);
+ for (let linkNode of safetyFlipperNode.querySelectorAll("a")) {
+ const safety = linkNode.getAttribute("data-safety");
+ linkNode.classList.toggle(
+ "active",
+ post.safety === safety
+ );
}
}
}
diff --git a/client/js/views/registration_view.js b/client/js/views/registration_view.js
index 1db5fcb..0a08de2 100644
--- a/client/js/views/registration_view.js
+++ b/client/js/views/registration_view.js
@@ -1,22 +1,25 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('user-registration');
+const template = views.getTemplate("user-registration");
class RegistrationView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
- views.replaceContent(this._hostNode, template({
- userNamePattern: api.getUserNameRegex(),
- passwordPattern: api.getPasswordRegex(),
- }));
+ this._hostNode = document.getElementById("content-holder");
+ views.replaceContent(
+ this._hostNode,
+ template({
+ userNamePattern: api.getUserNameRegex(),
+ passwordPattern: api.getPasswordRegex(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -37,29 +40,31 @@ class RegistrationView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- name: this._userNameFieldNode.value,
- password: this._passwordFieldNode.value,
- email: this._emailFieldNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ name: this._userNameFieldNode.value,
+ password: this._passwordFieldNode.value,
+ email: this._emailFieldNode.value,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameFieldNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordFieldNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _emailFieldNode() {
- return this._formNode.querySelector('[name=email]');
+ return this._formNode.querySelector("[name=email]");
}
}
diff --git a/client/js/views/settings_view.js b/client/js/views/settings_view.js
index 5ab7316..184028e 100644
--- a/client/js/views/settings_view.js
+++ b/client/js/views/settings_view.js
@@ -1,21 +1,23 @@
-'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('settings');
+const template = views.getTemplate("settings");
class SettingsView extends events.EventTarget {
constructor(ctx) {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(
- this._hostNode, template({browsingSettings: ctx.settings}));
+ this._hostNode,
+ template({ browsingSettings: ctx.settings })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -28,26 +30,32 @@ class SettingsView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- upscaleSmallPosts: this._find('upscale-small-posts').checked,
- endlessScroll: this._find('endless-scroll').checked,
- keyboardShortcuts: this._find('keyboard-shortcuts').checked,
- transparencyGrid: this._find('transparency-grid').checked,
- tagSuggestions: this._find('tag-suggestions').checked,
- autoplayVideos: this._find('autoplay-videos').checked,
- postsPerPage: this._find('posts-per-page').value,
- tagUnderscoresAsSpaces: this._find('tag-underscores-as-spaces').checked,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ upscaleSmallPosts: this._find("upscale-small-posts")
+ .checked,
+ endlessScroll: this._find("endless-scroll").checked,
+ keyboardShortcuts: this._find("keyboard-shortcuts")
+ .checked,
+ transparencyGrid: this._find("transparency-grid").checked,
+ tagSuggestions: this._find("tag-suggestions").checked,
+ autoplayVideos: this._find("autoplay-videos").checked,
+ postsPerPage: this._find("posts-per-page").value,
+ tagUnderscoresAsSpaces: this._find(
+ "tag-underscores-as-spaces"
+ ).checked,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
_find(nodeName) {
- return this._formNode.querySelector('[name=' + nodeName + ']');
+ return this._formNode.querySelector("[name=" + nodeName + "]");
}
}
diff --git a/client/js/views/snapshots_page_view.js b/client/js/views/snapshots_page_view.js
index e7ea264..a665ea0 100644
--- a/client/js/views/snapshots_page_view.js
+++ b/client/js/views/snapshots_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('snapshots-page');
+const template = views.getTemplate("snapshots-page");
function _extend(target, source) {
target.push.apply(target, source);
@@ -10,18 +10,18 @@ function _extend(target, source) {
function _formatBasicChange(diff, text) {
const lines = [];
- if (diff.type === 'list change') {
+ if (diff.type === "list change") {
const addedItems = diff.added;
const removedItems = diff.removed;
if (addedItems && addedItems.length) {
- lines.push(`Added ${text} (${addedItems.join(', ')})`);
+ lines.push(`Added ${text} (${addedItems.join(", ")})`);
}
if (removedItems && removedItems.length) {
- lines.push(`Removed ${text} (${removedItems.join(', ')})`);
+ lines.push(`Removed ${text} (${removedItems.join(", ")})`);
}
- } else if (diff.type === 'primitive change') {
- const oldValue = diff['old-value'];
- const newValue = diff['new-value'];
+ } else if (diff.type === "primitive change") {
+ const oldValue = diff["old-value"];
+ const newValue = diff["new-value"];
lines.push(`Changed ${text} (${oldValue} &rarr; ${newValue})`);
} else {
lines.push(`Changed ${text}`);
@@ -30,13 +30,13 @@ function _formatBasicChange(diff, text) {
}
function _makeResourceLink(type, id) {
- if (type === 'post') {
+ if (type === "post") {
return views.makePostLink(id, true);
- } else if (type === 'tag') {
+ } else if (type === "tag") {
return views.makeTagLink(id, true);
- } else if (type === 'tag_category') {
+ } else if (type === "tag_category") {
return 'category "' + id + '"';
- } else if (type === 'pool') {
+ } else if (type === "pool") {
return views.makePoolLink(id, true);
}
}
@@ -50,96 +50,102 @@ function _makeItemCreation(type, data) {
let text = key[0].toUpperCase() + key.substr(1).toLowerCase();
if (Array.isArray(data[key])) {
if (data[key].length) {
- lines.push(`${text}: ${data[key].join(', ')}`);
+ lines.push(`${text}: ${data[key].join(", ")}`);
}
} else {
lines.push(`${text}: ${data[key]}`);
}
}
- return lines.join('<br/>');
+ return lines.join("<br/>");
}
function _makeItemModification(type, data) {
const lines = [];
const diff = data.value;
- if (type === 'tag_category') {
+ if (type === "tag_category") {
if (diff.name) {
- _extend(lines, _formatBasicChange(diff.name, 'name'));
+ _extend(lines, _formatBasicChange(diff.name, "name"));
}
if (diff.color) {
- _extend(lines, _formatBasicChange(diff.color, 'color'));
+ _extend(lines, _formatBasicChange(diff.color, "color"));
}
if (diff.default) {
- _extend(lines, ['Made into default category']);
+ _extend(lines, ["Made into default category"]);
}
-
- } else if (type === 'tag') {
+ } else if (type === "tag") {
if (diff.names) {
- _extend(lines, _formatBasicChange(diff.names, 'names'));
+ _extend(lines, _formatBasicChange(diff.names, "names"));
}
if (diff.category) {
- _extend(
- lines, _formatBasicChange(diff.category, 'category'));
+ _extend(lines, _formatBasicChange(diff.category, "category"));
}
if (diff.suggestions) {
_extend(
- lines, _formatBasicChange(diff.suggestions, 'suggestions'));
+ lines,
+ _formatBasicChange(diff.suggestions, "suggestions")
+ );
}
if (diff.implications) {
_extend(
- lines, _formatBasicChange(diff.implications, 'implications'));
+ lines,
+ _formatBasicChange(diff.implications, "implications")
+ );
}
-
- } else if (type === 'post') {
+ } else if (type === "post") {
if (diff.checksum) {
- _extend(lines, ['Changed content']);
+ _extend(lines, ["Changed content"]);
}
if (diff.featured) {
- _extend(lines, ['Featured on front page']);
+ _extend(lines, ["Featured on front page"]);
}
if (diff.source) {
- _extend(lines, _formatBasicChange(diff.source, 'source'));
+ _extend(lines, _formatBasicChange(diff.source, "source"));
}
if (diff.safety) {
- _extend(lines, _formatBasicChange(diff.safety, 'safety'));
+ _extend(lines, _formatBasicChange(diff.safety, "safety"));
}
if (diff.tags) {
- _extend(lines, _formatBasicChange(diff.tags, 'tags'));
+ _extend(lines, _formatBasicChange(diff.tags, "tags"));
}
if (diff.relations) {
- _extend(lines, _formatBasicChange(diff.relations, 'relations'));
+ _extend(lines, _formatBasicChange(diff.relations, "relations"));
}
if (diff.notes) {
- _extend(lines, ['Changed notes']);
+ _extend(lines, ["Changed notes"]);
}
if (diff.flags) {
- _extend(lines, ['Changed flags']);
+ _extend(lines, ["Changed flags"]);
}
-
- } else if (type === 'pool') {
+ } else if (type === "pool") {
if (diff.names) {
- _extend(lines, _formatBasicChange(diff.names, 'names'));
+ _extend(lines, _formatBasicChange(diff.names, "names"));
}
if (diff.category) {
- _extend(
- lines, _formatBasicChange(diff.category, 'category'));
+ _extend(lines, _formatBasicChange(diff.category, "category"));
}
if (diff.posts) {
- _extend(
- lines, _formatBasicChange(diff.posts, 'posts'));
+ _extend(lines, _formatBasicChange(diff.posts, "posts"));
}
}
- return lines.join('<br/>');
+ return lines.join("<br/>");
}
class SnapshotsPageView {
constructor(ctx) {
- views.replaceContent(ctx.hostNode, template(Object.assign({
- makeResourceLink: _makeResourceLink,
- makeItemCreation: _makeItemCreation,
- makeItemModification: _makeItemModification,
- }, ctx)));
+ views.replaceContent(
+ ctx.hostNode,
+ template(
+ Object.assign(
+ {
+ makeResourceLink: _makeResourceLink,
+ makeItemCreation: _makeItemCreation,
+ makeItemModification: _makeItemModification,
+ },
+ ctx
+ )
+ )
+ );
}
}
diff --git a/client/js/views/tag_categories_view.js b/client/js/views/tag_categories_view.js
index 7e1000d..1f1a4da 100644
--- a/client/js/views/tag_categories_view.js
+++ b/client/js/views/tag_categories_view.js
@@ -1,17 +1,17 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const TagCategory = require('../models/tag_category.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const TagCategory = require("../models/tag_category.js");
-const template = views.getTemplate('tag-categories');
-const rowTemplate = views.getTemplate('tag-category-row');
+const template = views.getTemplate("tag-categories");
+const rowTemplate = views.getTemplate("tag-category-row");
class TagCategoriesView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template(ctx));
views.syncScrollPosition();
@@ -31,18 +31,22 @@ class TagCategoriesView extends events.EventTarget {
}
if (this._addLinkNode) {
- this._addLinkNode.addEventListener(
- 'click', e => this._evtAddButtonClick(e));
+ this._addLinkNode.addEventListener("click", (e) =>
+ this._evtAddButtonClick(e)
+ );
}
- ctx.tagCategories.addEventListener(
- 'add', e => this._evtTagCategoryAdded(e));
+ ctx.tagCategories.addEventListener("add", (e) =>
+ this._evtTagCategoryAdded(e)
+ );
- ctx.tagCategories.addEventListener(
- 'remove', e => this._evtTagCategoryDeleted(e));
+ ctx.tagCategories.addEventListener("remove", (e) =>
+ this._evtTagCategoryDeleted(e)
+ );
- this._formNode.addEventListener(
- 'submit', e => this._evtSaveButtonClick(e, ctx));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtSaveButtonClick(e, ctx)
+ );
}
enableForm() {
@@ -66,44 +70,48 @@ class TagCategoriesView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _tableBodyNode() {
- return this._hostNode.querySelector('tbody');
+ return this._hostNode.querySelector("tbody");
}
get _addLinkNode() {
- return this._hostNode.querySelector('a.add');
+ return this._hostNode.querySelector("a.add");
}
_addTagCategoryRowNode(tagCategory) {
const rowNode = rowTemplate(
- Object.assign(
- {}, this._ctx, {tagCategory: tagCategory}));
+ Object.assign({}, this._ctx, { tagCategory: tagCategory })
+ );
- const nameInput = rowNode.querySelector('.name input');
+ const nameInput = rowNode.querySelector(".name input");
if (nameInput) {
- nameInput.addEventListener(
- 'change', e => this._evtNameChange(e, rowNode));
+ nameInput.addEventListener("change", (e) =>
+ this._evtNameChange(e, rowNode)
+ );
}
- const colorInput = rowNode.querySelector('.color input');
+ const colorInput = rowNode.querySelector(".color input");
if (colorInput) {
- colorInput.addEventListener(
- 'change', e => this._evtColorChange(e, rowNode));
+ colorInput.addEventListener("change", (e) =>
+ this._evtColorChange(e, rowNode)
+ );
}
- const removeLinkNode = rowNode.querySelector('.remove a');
+ const removeLinkNode = rowNode.querySelector(".remove a");
if (removeLinkNode) {
- removeLinkNode.addEventListener(
- 'click', e => this._evtDeleteButtonClick(e, rowNode));
+ removeLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteButtonClick(e, rowNode)
+ );
}
- const defaultLinkNode = rowNode.querySelector('.set-default a');
+ const defaultLinkNode = rowNode.querySelector(".set-default a");
if (defaultLinkNode) {
- defaultLinkNode.addEventListener(
- 'click', e => this._evtSetDefaultButtonClick(e, rowNode));
+ defaultLinkNode.addEventListener("click", (e) =>
+ this._evtSetDefaultButtonClick(e, rowNode)
+ );
}
this._tableBodyNode.appendChild(rowNode);
@@ -141,7 +149,7 @@ class TagCategoriesView extends events.EventTarget {
_evtDeleteButtonClick(e, rowNode, link) {
e.preventDefault();
- if (e.target.classList.contains('inactive')) {
+ if (e.target.classList.contains("inactive")) {
return;
}
this._ctx.tagCategories.remove(rowNode._tagCategory);
@@ -150,16 +158,16 @@ class TagCategoriesView extends events.EventTarget {
_evtSetDefaultButtonClick(e, rowNode) {
e.preventDefault();
this._ctx.tagCategories.defaultCategory = rowNode._tagCategory;
- const oldRowNode = rowNode.parentNode.querySelector('tr.default');
+ const oldRowNode = rowNode.parentNode.querySelector("tr.default");
if (oldRowNode) {
- oldRowNode.classList.remove('default');
+ oldRowNode.classList.remove("default");
}
- rowNode.classList.add('default');
+ rowNode.classList.add("default");
}
_evtSaveButtonClick(e, ctx) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit'));
+ this.dispatchEvent(new CustomEvent("submit"));
}
}
diff --git a/client/js/views/tag_delete_view.js b/client/js/views/tag_delete_view.js
index 4d27f15..4246ec3 100644
--- a/client/js/views/tag_delete_view.js
+++ b/client/js/views/tag_delete_view.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('tag-delete');
+const template = views.getTemplate("tag-delete");
class TagDeleteView extends events.EventTarget {
constructor(ctx) {
@@ -13,7 +13,7 @@ class TagDeleteView extends events.EventTarget {
this._tag = ctx.tag;
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -38,15 +38,17 @@ class TagDeleteView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
}
diff --git a/client/js/views/tag_edit_view.js b/client/js/views/tag_edit_view.js
index bb4a382..58c1bc4 100644
--- a/client/js/views/tag_edit_view.js
+++ b/client/js/views/tag_edit_view.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const TagInputControl = require('../controls/tag_input_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const TagInputControl = require("../controls/tag_input_control.js");
-const template = views.getTemplate('tag-edit');
+const template = views.getTemplate("tag-edit");
class TagEditView extends events.EventTarget {
constructor(ctx) {
@@ -19,28 +19,33 @@ class TagEditView extends events.EventTarget {
views.decorateValidator(this._formNode);
if (this._namesFieldNode) {
- this._namesFieldNode.addEventListener(
- 'input', e => this._evtNameInput(e));
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
}
if (this._implicationsFieldNode) {
new TagInputControl(
- this._implicationsFieldNode, this._tag.implications);
+ this._implicationsFieldNode,
+ this._tag.implications
+ );
}
if (this._suggestionsFieldNode) {
new TagInputControl(
- this._suggestionsFieldNode, this._tag.suggestions);
+ this._suggestionsFieldNode,
+ this._tag.suggestions
+ );
}
for (let node of this._formNode.querySelectorAll(
- 'input, select, textarea')) {
- node.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- });
+ "input, select, textarea"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -69,72 +74,80 @@ class TagEditView extends events.EventTarget {
if (!list.length) {
this._namesFieldNode.setCustomValidity(
- 'Tags must have at least one name.');
+ "Tags must have at least one name."
+ );
return;
}
for (let item of list) {
if (!regex.test(item)) {
this._namesFieldNode.setCustomValidity(
- `Tag name "${item}" contains invalid symbols.`);
+ `Tag name "${item}" contains invalid symbols.`
+ );
return;
}
}
- this._namesFieldNode.setCustomValidity('');
+ this._namesFieldNode.setCustomValidity("");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
- names: this._namesFieldNode ?
- misc.splitByWhitespace(this._namesFieldNode.value) :
- undefined,
+ names: this._namesFieldNode
+ ? misc.splitByWhitespace(this._namesFieldNode.value)
+ : undefined,
- category: this._categoryFieldNode ?
- this._categoryFieldNode.value :
- undefined,
+ category: this._categoryFieldNode
+ ? this._categoryFieldNode.value
+ : undefined,
- implications: this._implicationsFieldNode ?
- misc.splitByWhitespace(this._implicationsFieldNode.value) :
- undefined,
+ implications: this._implicationsFieldNode
+ ? misc.splitByWhitespace(
+ this._implicationsFieldNode.value
+ )
+ : undefined,
- suggestions: this._suggestionsFieldNode ?
- misc.splitByWhitespace(this._suggestionsFieldNode.value) :
- undefined,
+ suggestions: this._suggestionsFieldNode
+ ? misc.splitByWhitespace(
+ this._suggestionsFieldNode.value
+ )
+ : undefined,
- description: this._descriptionFieldNode ?
- this._descriptionFieldNode.value :
- undefined,
- },
- }));
+ description: this._descriptionFieldNode
+ ? this._descriptionFieldNode.value
+ : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _namesFieldNode() {
- return this._formNode.querySelector('.names input');
+ return this._formNode.querySelector(".names input");
}
get _categoryFieldNode() {
- return this._formNode.querySelector('.category select');
+ return this._formNode.querySelector(".category select");
}
get _implicationsFieldNode() {
- return this._formNode.querySelector('.implications input');
+ return this._formNode.querySelector(".implications input");
}
get _suggestionsFieldNode() {
- return this._formNode.querySelector('.suggestions input');
+ return this._formNode.querySelector(".suggestions input");
}
get _descriptionFieldNode() {
- return this._formNode.querySelector('.description textarea');
+ return this._formNode.querySelector(".description textarea");
}
}
diff --git a/client/js/views/tag_merge_view.js b/client/js/views/tag_merge_view.js
index e29183a..f823ca4 100644
--- a/client/js/views/tag_merge_view.js
+++ b/client/js/views/tag_merge_view.js
@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('tag-merge');
+const template = views.getTemplate("tag-merge");
class TagMergeView extends events.EventTarget {
constructor(ctx) {
@@ -22,12 +21,16 @@ class TagMergeView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._targetTagFieldNode,
{
- confirm: tag => this._autoCompleteControl.replaceSelectedText(
- tag.names[0], false),
- });
+ confirm: (tag) =>
+ this._autoCompleteControl.replaceSelectedText(
+ tag.names[0],
+ false
+ ),
+ }
+ );
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -52,25 +55,27 @@ class TagMergeView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
- targetTagName: this._targetTagFieldNode.value,
- addAlias: this._addAliasCheckboxNode.checked,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
+ targetTagName: this._targetTagFieldNode.value,
+ addAlias: this._addAliasCheckboxNode.checked,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _targetTagFieldNode() {
- return this._formNode.querySelector('input[name=target-tag]');
+ return this._formNode.querySelector("input[name=target-tag]");
}
get _addAliasCheckboxNode() {
- return this._formNode.querySelector('input[name=alias]');
+ return this._formNode.querySelector("input[name=alias]");
}
}
diff --git a/client/js/views/tag_summary_view.js b/client/js/views/tag_summary_view.js
index 019e72b..11c6191 100644
--- a/client/js/views/tag_summary_view.js
+++ b/client/js/views/tag_summary_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('tag-summary');
+const template = views.getTemplate("tag-summary");
class TagSummaryView {
constructor(ctx) {
diff --git a/client/js/views/tag_view.js b/client/js/views/tag_view.js
index 2aaa999..e6c3776 100644
--- a/client/js/views/tag_view.js
+++ b/client/js/views/tag_view.js
@@ -1,26 +1,26 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const misc = require('../util/misc.js');
-const TagSummaryView = require('./tag_summary_view.js');
-const TagEditView = require('./tag_edit_view.js');
-const TagMergeView = require('./tag_merge_view.js');
-const TagDeleteView = require('./tag_delete_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const misc = require("../util/misc.js");
+const TagSummaryView = require("./tag_summary_view.js");
+const TagEditView = require("./tag_edit_view.js");
+const TagMergeView = require("./tag_merge_view.js");
+const TagDeleteView = require("./tag_delete_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('tag');
+const template = views.getTemplate("tag");
class TagView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.tag.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.tag.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
ctx.getPrettyTagName = misc.getPrettyTagName;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -28,52 +28,54 @@ class TagView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('.tag-content-holder');
- if (ctx.section === 'edit') {
+ ctx.hostNode = this._hostNode.querySelector(".tag-content-holder");
+ if (ctx.section === "edit") {
if (!this._ctx.canEditAnything) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to edit tags.');
+ "You don't have privileges to edit tags."
+ );
} else {
this._view = new TagEditView(ctx);
- events.proxyEvent(this._view, this, 'submit');
+ events.proxyEvent(this._view, this, "submit");
}
-
- } else if (ctx.section === 'merge') {
+ } else if (ctx.section === "merge") {
if (!this._ctx.canMerge) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to merge tags.');
+ "You don't have privileges to merge tags."
+ );
} else {
this._view = new TagMergeView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'merge');
+ events.proxyEvent(this._view, this, "submit", "merge");
}
-
- } else if (ctx.section === 'delete') {
+ } else if (ctx.section === "delete") {
if (!this._ctx.canDelete) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to delete tags.');
+ "You don't have privileges to delete tags."
+ );
} else {
this._view = new TagDeleteView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'delete');
+ events.proxyEvent(this._view, this, "submit", "delete");
}
-
} else {
this._view = new TagSummaryView(ctx);
}
- events.proxyEvent(this._view, this, 'change');
+ events.proxyEvent(this._view, this, "change");
views.syncScrollPosition();
}
diff --git a/client/js/views/tags_header_view.js b/client/js/views/tags_header_view.js
index 425c811..6dd7626 100644
--- a/client/js/views/tags_header_view.js
+++ b/client/js/views/tags_header_view.js
@@ -1,13 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const misc = require('../util/misc.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('tags-header');
+const template = views.getTemplate("tags-header");
class TagsHeaderView extends events.EventTarget {
constructor(ctx) {
@@ -20,31 +19,41 @@ class TagsHeaderView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._queryInputNode,
{
- confirm: tag => this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
+ confirm: (tag) =>
+ this._autoCompleteControl.replaceSelectedText(
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
}
search.searchInputNodeFocusHelper(this._queryInputNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _queryInputNode() {
- return this._hostNode.querySelector('[name=search-text]');
+ return this._hostNode.querySelector("[name=search-text]");
}
_evtSubmit(e) {
e.preventDefault();
this._queryInputNode.blur();
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._queryInputNode.value,
- page: 1,
- }}}));
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
}
}
diff --git a/client/js/views/tags_page_view.js b/client/js/views/tags_page_view.js
index cd335a4..e2b2820 100644
--- a/client/js/views/tags_page_view.js
+++ b/client/js/views/tags_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('tags-page');
+const template = views.getTemplate("tags-page");
class TagsPageView {
constructor(ctx) {
diff --git a/client/js/views/top_navigation_view.js b/client/js/views/top_navigation_view.js
index 2f99187..efe75a9 100644
--- a/client/js/views/top_navigation_view.js
+++ b/client/js/views/top_navigation_view.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('top-navigation');
+const template = views.getTemplate("top-navigation");
class TopNavigationView {
constructor() {
- this._hostNode = document.getElementById('top-navigation-holder');
+ this._hostNode = document.getElementById("top-navigation-holder");
}
get _mobileNavigationToggleNode() {
- return this._hostNode.querySelector('#mobile-navigation-toggle');
+ return this._hostNode.querySelector("#mobile-navigation-toggle");
}
get _navigationListNode() {
- return this._hostNode.querySelector('nav > ul');
+ return this._hostNode.querySelector("nav > ul");
}
get _navigationLinkNodes() {
- return this._navigationListNode.querySelectorAll('li > a');
+ return this._navigationListNode.querySelectorAll("li > a");
}
render(ctx) {
@@ -28,28 +28,32 @@ class TopNavigationView {
}
activate(key) {
- for (let itemNode of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let itemNode of this._hostNode.querySelectorAll("[data-name]")) {
itemNode.classList.toggle(
- 'active', itemNode.getAttribute('data-name') === key);
+ "active",
+ itemNode.getAttribute("data-name") === key
+ );
}
}
_bindMobileNavigationEvents() {
- this._mobileNavigationToggleNode.addEventListener(
- 'click', e => this._mobileNavigationToggleClick(e));
+ this._mobileNavigationToggleNode.addEventListener("click", (e) =>
+ this._mobileNavigationToggleClick(e)
+ );
for (let navigationLinkNode of this._navigationLinkNodes) {
- navigationLinkNode.addEventListener(
- 'click', e => this._navigationLinkClick(e));
+ navigationLinkNode.addEventListener("click", (e) =>
+ this._navigationLinkClick(e)
+ );
}
}
_mobileNavigationToggleClick(e) {
- this._navigationListNode.classList.toggle('opened');
+ this._navigationListNode.classList.toggle("opened");
}
_navigationLinkClick(e) {
- this._navigationListNode.classList.remove('opened');
+ this._navigationListNode.classList.remove("opened");
}
}
diff --git a/client/js/views/user_delete_view.js b/client/js/views/user_delete_view.js
index bdaf9e6..37de52f 100644
--- a/client/js/views/user_delete_view.js
+++ b/client/js/views/user_delete_view.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('user-delete');
+const template = views.getTemplate("user-delete");
class UserDeleteView extends events.EventTarget {
constructor(ctx) {
@@ -14,7 +14,7 @@ class UserDeleteView extends events.EventTarget {
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -39,16 +39,17 @@ class UserDeleteView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
-
+ return this._hostNode.querySelector("form");
}
}
diff --git a/client/js/views/user_edit_view.js b/client/js/views/user_edit_view.js
index 317d8e1..4886726 100644
--- a/client/js/views/user_edit_view.js
+++ b/client/js/views/user_edit_view.js
@@ -1,18 +1,18 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
-const FileDropperControl = require('../controls/file_dropper_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const FileDropperControl = require("../controls/file_dropper_control.js");
-const template = views.getTemplate('user-edit');
+const template = views.getTemplate("user-edit");
class UserEditView extends events.EventTarget {
constructor(ctx) {
super();
- ctx.userNamePattern = api.getUserNameRegex() + (/|^$/).source;
- ctx.passwordPattern = api.getPasswordRegex() + (/|^$/).source;
+ ctx.userNamePattern = api.getUserNameRegex() + /|^$/.source;
+ ctx.passwordPattern = api.getPasswordRegex() + /|^$/.source;
this._user = ctx.user;
this._hostNode = ctx.hostNode;
@@ -22,24 +22,26 @@ class UserEditView extends events.EventTarget {
this._avatarContent = null;
if (this._avatarContentInputNode) {
this._avatarFileDropper = new FileDropperControl(
- this._avatarContentInputNode, {lock: true});
- this._avatarFileDropper.addEventListener('fileadd', e => {
+ this._avatarContentInputNode,
+ { lock: true }
+ );
+ this._avatarFileDropper.addEventListener("fileadd", (e) => {
this._hostNode.querySelector(
- '[name=avatar-style][value=manual]').checked = true;
+ "[name=avatar-style][value=manual]"
+ ).checked = true;
this._avatarContent = e.detail.files[0];
});
}
- for (let node of this._formNode.querySelectorAll('input, select')) {
- node.addEventListener(
- 'change', e => {
- if (!e.target.classList.contains('anticomplete')) {
- this.dispatchEvent(new CustomEvent('change'));
- }
- });
+ for (let node of this._formNode.querySelectorAll("input, select")) {
+ node.addEventListener("change", (e) => {
+ if (!e.target.classList.contains("anticomplete")) {
+ this.dispatchEvent(new CustomEvent("change"));
+ }
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -64,61 +66,63 @@ class UserEditView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
- name: this._userNameInputNode ?
- this._userNameInputNode.value :
- undefined,
+ name: this._userNameInputNode
+ ? this._userNameInputNode.value
+ : undefined,
- email: this._emailInputNode ?
- this._emailInputNode.value :
- undefined,
+ email: this._emailInputNode
+ ? this._emailInputNode.value
+ : undefined,
- rank: this._rankInputNode ?
- this._rankInputNode.value :
- undefined,
+ rank: this._rankInputNode
+ ? this._rankInputNode.value
+ : undefined,
- avatarStyle: this._avatarStyleInputNode ?
- this._avatarStyleInputNode.value :
- undefined,
+ avatarStyle: this._avatarStyleInputNode
+ ? this._avatarStyleInputNode.value
+ : undefined,
- password: this._passwordInputNode ?
- this._passwordInputNode.value :
- undefined,
+ password: this._passwordInputNode
+ ? this._passwordInputNode.value
+ : undefined,
- avatarContent: this._avatarContent,
- },
- }));
+ avatarContent: this._avatarContent,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _rankInputNode() {
- return this._formNode.querySelector('[name=rank]');
+ return this._formNode.querySelector("[name=rank]");
}
get _emailInputNode() {
- return this._formNode.querySelector('[name=email]');
+ return this._formNode.querySelector("[name=email]");
}
get _userNameInputNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordInputNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _avatarContentInputNode() {
- return this._formNode.querySelector('#avatar-content');
+ return this._formNode.querySelector("#avatar-content");
}
get _avatarStyleInputNode() {
- return this._formNode.querySelector('[name=avatar-style]:checked');
+ return this._formNode.querySelector("[name=avatar-style]:checked");
}
}
diff --git a/client/js/views/user_summary_view.js b/client/js/views/user_summary_view.js
index d8463f3..eab827f 100644
--- a/client/js/views/user_summary_view.js
+++ b/client/js/views/user_summary_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('user-summary');
+const template = views.getTemplate("user-summary");
class UserSummaryView {
constructor(ctx) {
diff --git a/client/js/views/user_tokens_view.js b/client/js/views/user_tokens_view.js
index 8e283bf..68707f0 100644
--- a/client/js/views/user_tokens_view.js
+++ b/client/js/views/user_tokens_view.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('user-tokens');
+const template = views.getTemplate("user-tokens");
class UserTokenView extends events.EventTarget {
constructor(ctx) {
@@ -16,7 +16,7 @@ class UserTokenView extends events.EventTarget {
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
this._decorateTokenForms();
this._decorateTokenNoteChangeLinks();
@@ -26,8 +26,9 @@ class UserTokenView extends events.EventTarget {
this._tokenFormNodes = [];
for (let i = 0; i < this._tokens.length; i++) {
let formNode = this._hostNode.querySelector(
- '.token[data-token-id=\"' + i + '\"]');
- formNode.addEventListener('submit', e => this._evtDelete(e));
+ '.token[data-token-id="' + i + '"]'
+ );
+ formNode.addEventListener("submit", (e) => this._evtDelete(e));
this._tokenFormNodes.push(formNode);
}
}
@@ -35,9 +36,11 @@ class UserTokenView extends events.EventTarget {
_decorateTokenNoteChangeLinks() {
for (let i = 0; i < this._tokens.length; i++) {
let linkNode = this._hostNode.querySelector(
- '.token-change-note[data-token-id=\"' + i + '\"]');
- linkNode.addEventListener(
- 'click', e => this._evtChangeNoteClick(e));
+ '.token-change-note[data-token-id="' + i + '"]'
+ );
+ linkNode.addEventListener("click", (e) =>
+ this._evtChangeNoteClick(e)
+ );
}
}
@@ -69,65 +72,75 @@ class UserTokenView extends events.EventTarget {
_evtDelete(e) {
e.preventDefault();
- const userToken = this._tokens[parseInt(
- e.target.getAttribute('data-token-id'))];
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- user: this._user,
- userToken: userToken,
- },
- }));
+ const userToken = this._tokens[
+ parseInt(e.target.getAttribute("data-token-id"))
+ ];
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ user: this._user,
+ userToken: userToken,
+ },
+ })
+ );
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
- note: this._userTokenNoteInputNode ?
- this._userTokenNoteInputNode.value :
- undefined,
+ note: this._userTokenNoteInputNode
+ ? this._userTokenNoteInputNode.value
+ : undefined,
- expirationTime:
- (this._userTokenExpirationTimeInputNode
- && this._userTokenExpirationTimeInputNode.value) ?
- new Date(this._userTokenExpirationTimeInputNode.value)
- .toISOString() :
- undefined,
- },
- }));
+ expirationTime:
+ this._userTokenExpirationTimeInputNode &&
+ this._userTokenExpirationTimeInputNode.value
+ ? new Date(
+ this._userTokenExpirationTimeInputNode.value
+ ).toISOString()
+ : undefined,
+ },
+ })
+ );
}
_evtChangeNoteClick(e) {
e.preventDefault();
const userToken = this._tokens[
- parseInt(e.target.getAttribute('data-token-id'))];
+ parseInt(e.target.getAttribute("data-token-id"))
+ ];
const text = window.prompt(
- 'Please enter the new name:',
- userToken.note !== null ? userToken.note : undefined);
+ "Please enter the new name:",
+ userToken.note !== null ? userToken.note : undefined
+ );
if (!text) {
return;
}
- this.dispatchEvent(new CustomEvent('update', {
- detail: {
- user: this._user,
- userToken: userToken,
- note: text ? text : undefined,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("update", {
+ detail: {
+ user: this._user,
+ userToken: userToken,
+ note: text ? text : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('#create-token-form');
+ return this._hostNode.querySelector("#create-token-form");
}
get _userTokenNoteInputNode() {
- return this._formNode.querySelector('.note input');
+ return this._formNode.querySelector(".note input");
}
get _userTokenExpirationTimeInputNode() {
- return this._formNode.querySelector('.expirationTime input');
+ return this._formNode.querySelector(".expirationTime input");
}
}
diff --git a/client/js/views/user_view.js b/client/js/views/user_view.js
index d96ebe1..2eebfe9 100644
--- a/client/js/views/user_view.js
+++ b/client/js/views/user_view.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const UserDeleteView = require('./user_delete_view.js');
-const UserTokensView = require('./user_tokens_view.js');
-const UserSummaryView = require('./user_summary_view.js');
-const UserEditView = require('./user_edit_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const UserDeleteView = require("./user_delete_view.js");
+const UserTokensView = require("./user_tokens_view.js");
+const UserSummaryView = require("./user_summary_view.js");
+const UserEditView = require("./user_edit_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('user');
+const template = views.getTemplate("user");
class UserView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.user.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.user.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -26,52 +26,56 @@ class UserView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('#user-content-holder');
- if (ctx.section === 'edit') {
+ ctx.hostNode = this._hostNode.querySelector("#user-content-holder");
+ if (ctx.section === "edit") {
if (!this._ctx.canEditAnything) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to edit users.');
+ "You don't have privileges to edit users."
+ );
} else {
this._view = new UserEditView(ctx);
- events.proxyEvent(this._view, this, 'submit');
+ events.proxyEvent(this._view, this, "submit");
}
- } else if (ctx.section === 'list-tokens') {
+ } else if (ctx.section === "list-tokens") {
if (!this._ctx.canListTokens) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to view user tokens.');
+ "You don't have privileges to view user tokens."
+ );
} else {
this._view = new UserTokensView(ctx);
- events.proxyEvent(this._view, this, 'delete', 'delete-token');
- events.proxyEvent(this._view, this, 'submit', 'create-token');
- events.proxyEvent(this._view, this, 'update', 'update-token');
+ events.proxyEvent(this._view, this, "delete", "delete-token");
+ events.proxyEvent(this._view, this, "submit", "create-token");
+ events.proxyEvent(this._view, this, "update", "update-token");
}
- } else if (ctx.section === 'delete') {
+ } else if (ctx.section === "delete") {
if (!this._ctx.canDelete) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to delete users.');
+ "You don't have privileges to delete users."
+ );
} else {
this._view = new UserDeleteView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'delete');
+ events.proxyEvent(this._view, this, "submit", "delete");
}
-
} else {
this._view = new UserSummaryView(ctx);
}
- events.proxyEvent(this._view, this, 'change');
+ events.proxyEvent(this._view, this, "change");
views.syncScrollPosition();
}
diff --git a/client/js/views/users_header_view.js b/client/js/views/users_header_view.js
index 08b7620..d6b7c6a 100644
--- a/client/js/views/users_header_view.js
+++ b/client/js/views/users_header_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('users-header');
+const template = views.getTemplate("users-header");
class UsersHeaderView extends events.EventTarget {
constructor(ctx) {
@@ -15,23 +15,29 @@ class UsersHeaderView extends events.EventTarget {
search.searchInputNodeFocusHelper(this._queryInputNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _queryInputNode() {
- return this._formNode.querySelector('[name=search-text]');
+ return this._formNode.querySelector("[name=search-text]");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._queryInputNode.value,
- page: 1,
- }}}));
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
}
}
diff --git a/client/js/views/users_page_view.js b/client/js/views/users_page_view.js
index f772d4e..2689433 100644
--- a/client/js/views/users_page_view.js
+++ b/client/js/views/users_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('users-page');
+const template = views.getTemplate("users-page");
class UsersPageView {
constructor(ctx) {

© 2015 - 2026 Jakob L. Kreuze