diff --git a/client/.eslintrc.yml b/client/.eslintrc.yml new file mode 100644 index 00000000..a176248f --- /dev/null +++ b/client/.eslintrc.yml @@ -0,0 +1,293 @@ +env: + browser: true + commonjs: true + es6: true +extends: 'eslint:recommended' +globals: + Atomics: readonly + SharedArrayBuffer: readonly +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/js/api.js b/client/js/api.js index 07ec5ec9..303c0775 100644 --- a/client/js/api.js +++ b/client/js/api.js @@ -377,8 +377,9 @@ class Api extends events.EventTarget { try { if (this.userName && this.token) { req.auth = null; - req.set('Authorization', 'Token ' - + new Buffer(this.userName + ":" + this.token).toString('base64')) + // eslint-disable-next-line no-undef + req.set('Authorization', 'Token ' + new Buffer( + this.userName + ":" + this.token).toString('base64')) } else if (this.userName && this.userPassword) { req.auth( this.userName, diff --git a/client/js/controllers/comments_controller.js b/client/js/controllers/comments_controller.js index 2de638cb..67e44ac1 100644 --- a/client/js/controllers/comments_controller.js +++ b/client/js/controllers/comments_controller.js @@ -34,7 +34,9 @@ class CommentsController { requestPage: (offset, limit) => { return PostList.search( 'sort:comment-date comment-count-min:1', - offset, limit, fields); + offset, + limit, + fields); }, pageRenderer: pageCtx => { Object.assign(pageCtx, { @@ -68,9 +70,10 @@ class CommentsController { e.detail.comment.delete() .catch(error => window.alert(error.message)); } -}; +} module.exports = router => { - router.enter(['comments'], - (ctx, next) => { new CommentsController(ctx); }); -}; + router.enter(['comments'], (ctx, next) => { + new CommentsController(ctx); + }); +} diff --git a/client/js/controllers/home_controller.js b/client/js/controllers/home_controller.js index cc22ca95..590da672 100644 --- a/client/js/controllers/home_controller.js +++ b/client/js/controllers/home_controller.js @@ -41,10 +41,10 @@ class HomeController { showError(message) { this._homeView.showError(message); } -}; +} 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 66f52e92..8ceeef0e 100644 --- a/client/js/controllers/not_found_controller.js +++ b/client/js/controllers/not_found_controller.js @@ -9,10 +9,10 @@ class NotFoundController { topNavigation.setTitle('Not found'); this._notFoundView = new NotFoundView(path); } -}; +} module.exports = router => { router.enter(null, (ctx, next) => { ctx.controller = new NotFoundController(ctx.canonicalPath); }); -}; +} diff --git a/client/js/controllers/post_detail_controller.js b/client/js/controllers/post_detail_controller.js index 47d5430c..bd9c2e69 100644 --- a/client/js/controllers/post_detail_controller.js +++ b/client/js/controllers/post_detail_controller.js @@ -57,7 +57,8 @@ class PostDetailController extends BasePostController { if (this._id !== e.detail.post.id) { router.replace( uri.formatClientLink('post', e.detail.post.id, section), - null, false); + null, + false); } } @@ -71,7 +72,8 @@ class PostDetailController extends BasePostController { router.replace( uri.formatClientLink( 'post', e.detail.targetPost.id, 'merge'), - null, false); + null, + false); }, error => { this._view.showError(error.message); this._view.enableForm(); diff --git a/client/js/controllers/post_list_controller.js b/client/js/controllers/post_list_controller.js index fd1adfea..d7836073 100644 --- a/client/js/controllers/post_list_controller.js +++ b/client/js/controllers/post_list_controller.js @@ -13,7 +13,8 @@ const EmptyView = require('../views/empty_view.js'); const fields = [ 'id', 'thumbnailUrl', 'type', 'safety', - 'score', 'favoriteCount', 'commentCount', 'tags', 'version']; + 'score', 'favoriteCount', 'commentCount', 'tags', 'version' +]; class PostListController { constructor(ctx) { @@ -62,8 +63,7 @@ class PostListController { _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)); } @@ -117,5 +117,7 @@ class PostListController { module.exports = router => { router.enter( ['posts'], - (ctx, next) => { ctx.controller = new PostListController(ctx); }); + (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 19148526..924e918c 100644 --- a/client/js/controllers/post_main_controller.js +++ b/client/js/controllers/post_main_controller.js @@ -18,10 +18,10 @@ class PostMainController extends BasePostController { let parameters = ctx.parameters; Promise.all([ - Post.get(ctx.parameters.id), - PostList.getAround( - ctx.parameters.id, - parameters ? parameters.query : null), + Post.get(ctx.parameters.id), + PostList.getAround( + ctx.parameters.id, + parameters ? parameters.query : null), ]).then(responses => { const [post, aroundResponse] = responses; diff --git a/client/js/controllers/post_upload_controller.js b/client/js/controllers/post_upload_controller.js index 1124ff76..f16aaf02 100644 --- a/client/js/controllers/post_upload_controller.js +++ b/client/js/controllers/post_upload_controller.js @@ -57,33 +57,32 @@ class PostUploadController { this._view.clearMessages(); e.detail.uploadables.reduce( - (promise, uploadable) => - promise.then(() => this._uploadSinglePost( - uploadable, e.detail.skipDuplicates)), + (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); - } + .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(error.message); + this._view.showError(genericErrorMessage); + this._view.showError( + error.message, error.uploadable); } - this._view.enableForm(); - }); + } else { + this._view.showError(error.message); + } + this._view.enableForm(); + }); } _uploadSinglePost(uploadable, skipDuplicates) { @@ -153,7 +152,9 @@ class PostUploadController { post.newContent = uploadable.url || uploadable.file; // if uploadable.source is ever going to be a valid field (e.g when setting source directly in the upload window) // you'll need to change the line below to `post.source = uploadable.source || uploadable.url;` - if (uploadable.url) post.source = uploadable.url; + if (uploadable.url) { + post.source = uploadable.url; + } return post; } } diff --git a/client/js/controllers/settings_controller.js b/client/js/controllers/settings_controller.js index 224b2059..7765143a 100644 --- a/client/js/controllers/settings_controller.js +++ b/client/js/controllers/settings_controller.js @@ -19,7 +19,7 @@ class SettingsController { settings.save(e.detail); this._view.showSuccess('Settings saved.'); } -}; +} module.exports = router => { router.enter(['settings'], (ctx, next) => { diff --git a/client/js/controllers/snapshots_controller.js b/client/js/controllers/snapshots_controller.js index e64b9db1..0e9b773c 100644 --- a/client/js/controllers/snapshots_controller.js +++ b/client/js/controllers/snapshots_controller.js @@ -45,5 +45,7 @@ class SnapshotsController { module.exports = router => { router.enter(['history'], - (ctx, next) => { ctx.controller = new SnapshotsController(ctx); }); + (ctx, next) => { + ctx.controller = new SnapshotsController(ctx); + }); }; diff --git a/client/js/controllers/tag_controller.js b/client/js/controllers/tag_controller.js index d64ab220..71405dc8 100644 --- a/client/js/controllers/tag_controller.js +++ b/client/js/controllers/tag_controller.js @@ -69,7 +69,8 @@ class TagController { if (this._name !== e.detail.tag.names[0]) { router.replace( uri.formatClientLink('tag', e.detail.tag.names[0], section), - null, false); + null, + false); } } @@ -105,7 +106,8 @@ class TagController { router.replace( uri.formatClientLink( 'tag', e.detail.targetTagName, 'merge'), - null, false); + null, + false); }, error => { this._view.showError(error.message); this._view.enableForm(); diff --git a/client/js/controllers/tag_list_controller.js b/client/js/controllers/tag_list_controller.js index 8bc7dbba..db31cc62 100644 --- a/client/js/controllers/tag_list_controller.js +++ b/client/js/controllers/tag_list_controller.js @@ -16,7 +16,8 @@ const fields = [ 'implications', 'creationTime', 'usages', - 'category']; + 'category' +]; class TagListController { constructor(ctx) { @@ -81,5 +82,7 @@ class TagListController { module.exports = router => { router.enter( ['tags'], - (ctx, next) => { ctx.controller = new TagListController(ctx); }); + (ctx, next) => { + ctx.controller = new TagListController(ctx); + }); }; diff --git a/client/js/controllers/user_controller.js b/client/js/controllers/user_controller.js index 48989af3..e192d879 100644 --- a/client/js/controllers/user_controller.js +++ b/client/js/controllers/user_controller.js @@ -42,7 +42,7 @@ class UserController { userTokenPromise, User.get(userName) ]).then(responses => { - const [userTokens, user] = responses; + const [userTokens, user] = responses; const isLoggedIn = api.isLoggedIn(user); const infix = isLoggedIn ? 'self' : 'any'; @@ -133,7 +133,8 @@ class UserController { if (this._name !== e.detail.user.name) { router.replace( uri.formatClientLink('user', e.detail.user.name, section), - null, false); + null, + false); } } diff --git a/client/js/controllers/user_list_controller.js b/client/js/controllers/user_list_controller.js index fa878d85..13dcf434 100644 --- a/client/js/controllers/user_list_controller.js +++ b/client/js/controllers/user_list_controller.js @@ -51,7 +51,7 @@ class UserListController { defaultLimit: 30, getClientUrlForPage: (offset, limit) => { const parameters = Object.assign( - {}, this._ctx.parameters, {offset, offset, limit: limit}); + {}, this._ctx.parameters, {offset: offset, limit: limit}); return uri.formatClientLink('users', parameters); }, requestPage: (offset, limit) => { @@ -71,5 +71,7 @@ class UserListController { module.exports = router => { router.enter( ['users'], - (ctx, next) => { ctx.controller = new UserListController(ctx); }); + (ctx, next) => { + ctx.controller = new UserListController(ctx); + }); }; diff --git a/client/js/controls/auto_complete_control.js b/client/js/controls/auto_complete_control.js index 5ce3bb2e..a802209e 100644 --- a/client/js/controls/auto_complete_control.js +++ b/client/js/controls/auto_complete_control.js @@ -121,7 +121,9 @@ class AutoCompleteControl { document.body.appendChild(this._suggestionDiv); views.monitorNodeRemoval( - this._sourceInputNode, () => { this._uninstall(); }); + this._sourceInputNode, () => { + this._uninstall(); + }); } _uninstall() { @@ -137,13 +139,21 @@ class AutoCompleteControl { if (key === KEY_ESCAPE) { func = this.hide; } else if (key === KEY_TAB && shift) { - func = () => { this._selectPrevious(); }; + func = () => { + this._selectPrevious(); + }; } else if (key === KEY_TAB && !shift) { - func = () => { this._selectNext(); }; + func = () => { + this._selectNext(); + }; } else if (key === KEY_UP) { - func = () => { this._selectPrevious(); }; + func = () => { + this._selectPrevious(); + }; } else if (key === KEY_DOWN) { - func = () => { this._selectNext(); }; + func = () => { + this._selectNext(); + }; } else if (key === KEY_RETURN && this._activeResult >= 0) { func = () => { this._confirm(this._getActiveSuggestion()); @@ -165,13 +175,17 @@ class AutoCompleteControl { } else { window.clearTimeout(this._showTimeout); this._showTimeout = window.setTimeout( - () => { this._showOrHide(); }, 250); + () => { + this._showOrHide(); + }, 250); } } _evtBlur(e) { window.clearTimeout(this._showTimeout); - window.setTimeout(() => { this.hide(); }, 50); + window.setTimeout(() => { + this.hide(); + }, 50); } _getActiveSuggestion() { @@ -261,10 +275,10 @@ 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 ? + let y = direction === 1 ? inputRect.bottom - bodyRect.top - verticalShift : inputRect.top - bodyRect.top - listRect.height + verticalShift; @@ -276,7 +290,7 @@ class AutoCompleteControl { const prevHeight = listRect.height; listRect = this._suggestionDiv.getBoundingClientRect(); const heightDelta = prevHeight - listRect.height; - if (direction == -1) { + if (direction === -1) { y += heightDelta; } } @@ -296,6 +310,6 @@ class AutoCompleteControl { activeItem.classList.add('active'); } } -}; +} module.exports = AutoCompleteControl; diff --git a/client/js/controls/comment_control.js b/client/js/controls/comment_control.js index 849dd4df..c105bc07 100644 --- a/client/js/controls/comment_control.js +++ b/client/js/controls/comment_control.js @@ -212,11 +212,6 @@ class CommentControl extends events.EventTarget { this._selectTab('preview'); } - _evtEditClick(e) { - e.preventDefault(); - this.enterEditMode(); - } - _evtSaveChangesClick(e) { e.preventDefault(); this.dispatchEvent(new CustomEvent('submit', { @@ -260,6 +255,6 @@ class CommentControl extends events.EventTarget { _forgetHeight() { this._heightKeeperNode.style.minHeight = null; } -}; +} module.exports = CommentControl; diff --git a/client/js/controls/comment_list_control.js b/client/js/controls/comment_list_control.js index ddef71f3..4f57fd2a 100644 --- a/client/js/controls/comment_list_control.js +++ b/client/js/controls/comment_list_control.js @@ -54,6 +54,6 @@ class CommentListControl extends events.EventTarget { _evtRemove(e) { this._uninstallCommentNode(e.detail.comment); } -}; +} module.exports = CommentListControl; diff --git a/client/js/controls/expander_control.js b/client/js/controls/expander_control.js index beb0e69a..28a4ffb8 100644 --- a/client/js/controls/expander_control.js +++ b/client/js/controls/expander_control.js @@ -39,6 +39,7 @@ class ExpanderControl { this._syncIcon(); } + // eslint-disable-next-line accessor-pairs set title(newTitle) { if (this._expanderNode) { this._expanderNode diff --git a/client/js/controls/post_content_control.js b/client/js/controls/post_content_control.js index 856fb775..d1848b3a 100644 --- a/client/js/controls/post_content_control.js +++ b/client/js/controls/post_content_control.js @@ -107,7 +107,9 @@ class PostContentControl { this._reinstall(); optimizedResize.add(() => this._refreshSize()); views.monitorNodeRemoval( - this._hostNode, () => { this._uninstall(); }); + this._hostNode, () => { + this._uninstall(); + }); } _reinstall() { diff --git a/client/js/controls/post_edit_sidebar_control.js b/client/js/controls/post_edit_sidebar_control.js index 030bb7a2..11ce2103 100644 --- a/client/js/controls/post_edit_sidebar_control.js +++ b/client/js/controls/post_edit_sidebar_control.js @@ -37,7 +37,6 @@ class PostEditSidebarControl extends events.EventTarget { canEditPostFlags: api.hasPrivilege('posts:edit:flags'), canEditPostContent: api.hasPrivilege('posts:edit:content'), canEditPostThumbnail: api.hasPrivilege('posts:edit:thumbnail'), - canEditPostSource : api.hasPrivilege('posts:edit:source'), canCreateAnonymousPosts: api.hasPrivilege('posts:create:anonymous'), canDeletePosts: api.hasPrivilege('posts:delete'), canFeaturePosts: api.hasPrivilege('posts:feature'), @@ -78,8 +77,7 @@ class PostEditSidebarControl extends events.EventTarget { 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 => { @@ -284,6 +282,7 @@ class PostEditSidebarControl extends events.EventTarget { try { success = document.execCommand('copy'); } catch (err) { + // continue regardless of error } textarea.blur(); document.body.removeChild(textarea); @@ -383,10 +382,16 @@ class PostEditSidebarControl extends events.EventTarget { } get _videoFlags() { - if (!this._loopVideoInputNode) return undefined; + if (!this._loopVideoInputNode) { + return undefined; + } let ret = []; - if (this._loopVideoInputNode.checked) ret.push('loop'); - if (this._soundVideoInputNode.checked) ret.push('sound'); + if (this._loopVideoInputNode.checked) { + ret.push('loop'); + } + if (this._soundVideoInputNode.checked) { + ret.push('sound'); + } return ret; } @@ -462,6 +467,6 @@ class PostEditSidebarControl extends events.EventTarget { showError(message) { views.showError(this._hostNode, message); } -}; +} module.exports = PostEditSidebarControl; diff --git a/client/js/controls/post_notes_overlay_control.js b/client/js/controls/post_notes_overlay_control.js index bbea0956..7bf69b28 100644 --- a/client/js/controls/post_notes_overlay_control.js +++ b/client/js/controls/post_notes_overlay_control.js @@ -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; @@ -188,12 +188,12 @@ class SelectedState extends ActiveState { evtCanvasKeyDown(e) { const delta = e.ctrlKey ? 10 : 1; const offsetMap = { - [KEY_LEFT]: [-delta, 0], - [KEY_UP]: [0, -delta], - [KEY_DOWN]: [0, delta], + [KEY_LEFT]: [-delta, 0], + [KEY_UP]: [0, -delta], + [KEY_DOWN]: [0, delta], [KEY_RIGHT]: [delta, 0], }; - if (offsetMap.hasOwnProperty(e.which)) { + if (Object.prototype.hasOwnProperty.call(offsetMap, e.witch)) { e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault(); @@ -283,8 +283,8 @@ 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); @@ -305,7 +305,7 @@ class MovingPointState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which == KEY_ESCAPE) { + 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); @@ -333,7 +333,7 @@ class MovingNoteState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which == KEY_ESCAPE) { + if (e.which === KEY_ESCAPE) { for (let i of misc.range(this._note.polygon.length)) { this._note.polygon.at(i).x = this._originalPolygon[i].x; this._note.polygon.at(i).y = this._originalPolygon[i].y; @@ -366,7 +366,7 @@ class ScalingNoteState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which == KEY_ESCAPE) { + if (e.which === KEY_ESCAPE) { for (let i of misc.range(this._note.polygon.length)) { this._note.polygon.at(i).x = this._originalPolygon[i].x; this._note.polygon.at(i).y = this._originalPolygon[i].y; @@ -384,12 +384,12 @@ 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))); } } @@ -466,12 +466,12 @@ class DrawingPolygonState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which == KEY_ESCAPE) { + if (e.which === KEY_ESCAPE) { this._note.polygon.remove(this._note.polygon.secondLastPoint); if (this._note.polygon.length === 1) { this._cancel(); } - } else if (e.which == KEY_RETURN) { + } else if (e.which === KEY_RETURN) { this._finish(); } } @@ -674,13 +674,13 @@ class PostNotesOverlayControl extends events.EventTarget { const x = ( -bodyRect.left + svgRect.left + - svgRect.width * centroid.x - - noteRect.width / 2); + (svgRect.width * centroid.x) - + (noteRect.width / 2)); const y = ( -bodyRect.top + svgRect.top + - svgRect.height * centroid.y - - noteRect.height / 2); + (svgRect.height * centroid.y) - + (noteRect.height / 2)); this._textNode.style.left = x + 'px'; this._textNode.style.top = y + 'px'; } diff --git a/client/js/controls/post_readonly_sidebar_control.js b/client/js/controls/post_readonly_sidebar_control.js index 0d662524..388c238c 100644 --- a/client/js/controls/post_readonly_sidebar_control.js +++ b/client/js/controls/post_readonly_sidebar_control.js @@ -197,6 +197,6 @@ class PostReadonlySidebarControl extends events.EventTarget { _evtChangeScore(e) { this._installScore(); } -}; +} module.exports = PostReadonlySidebarControl; diff --git a/client/js/controls/tag_auto_complete_control.js b/client/js/controls/tag_auto_complete_control.js index 3d9130ec..f8d3f6c3 100644 --- a/client/js/controls/tag_auto_complete_control.js +++ b/client/js/controls/tag_auto_complete_control.js @@ -36,22 +36,21 @@ class TagAutoCompleteControl extends AutoCompleteControl { const term = misc.escapeSearchTerm(text); const query = ( text.length < minLengthForPartialSearch - ? term + '*' - : '*' + term + '*') + ' sort:usages'; + ? 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); + query, 0, this._options.maxResults, ['names', 'category', 'usages']) + .then( + response => resolve( + _tagListToMatches(response.results, this._options)), + reject); }); }; super(input, options); } -}; +} module.exports = TagAutoCompleteControl; diff --git a/client/js/controls/tag_input_control.js b/client/js/controls/tag_input_control.js index 1ad0957e..e0b13393 100644 --- a/client/js/controls/tag_input_control.js +++ b/client/js/controls/tag_input_control.js @@ -51,7 +51,7 @@ class SuggestionList { } set(suggestion, weight) { - if (this._suggestions.hasOwnProperty(suggestion)) { + if (Object.prototype.hasOwnProperty.call(this._suggestions, suggestion)) { weight = Math.max(weight, this._suggestions[suggestion]); } this._suggestions[suggestion] = weight; @@ -72,7 +72,7 @@ class SuggestionList { tuples.sort((a, b) => { let weightDiff = b[1] - a[1]; let nameDiff = a[0].localeCompare(b[0]); - return weightDiff == 0 ? nameDiff : weightDiff; + return weightDiff === 0 ? nameDiff : weightDiff; }); return tuples.map(tuple => { return {tagName: tuple[0], weight: tuple[1]}; @@ -102,7 +102,7 @@ class TagInputControl extends events.EventTarget { }, confirm: tag => { this._tagInputNode.value = ''; - // XXX: tags from autocomplete don't contain implications + // 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); }, @@ -160,7 +160,7 @@ class TagInputControl extends events.EventTarget { } addTag(tag, source) { - if (source != SOURCE_INIT && this.tags.isTaggedWith(tag.names[0])) { + if (source !== SOURCE_INIT && this.tags.isTaggedWith(tag.names[0])) { const listItemNode = this._getListItemNode(tag); if (source !== SOURCE_IMPLICATION) { listItemNode.classList.add('duplicate'); @@ -240,7 +240,7 @@ class TagInputControl extends events.EventTarget { } _evtInputKeyDown(e) { - if (e.which == KEY_RETURN || e.which == KEY_SPACE) { + if (e.which === KEY_RETURN || e.which === KEY_SPACE) { e.preventDefault(); this._hideAutoComplete(); this.addTagByText(this._tagInputNode.value, SOURCE_USER_INPUT); @@ -328,8 +328,8 @@ class TagInputControl extends events.EventTarget { return; } api.get( - uri.formatApiLink('tag-siblings', tag.names[0]), - {noProgress: true}) + uri.formatApiLink('tag-siblings', tag.names[0]), + {noProgress: true}) .then(response => { return Promise.resolve(response.results); }, response => { diff --git a/client/js/events.js b/client/js/events.js index e395214b..945771a4 100644 --- a/client/js/events.js +++ b/client/js/events.js @@ -11,7 +11,7 @@ class EventTarget { this[method] = this.eventTarget[method].bind(this.eventTarget); } } -}; +} function proxyEvent(source, target, sourceEventType, targetEventType) { if (!source.addEventListener) { diff --git a/client/js/main.js b/client/js/main.js index dd974fd8..cb0eb076 100644 --- a/client/js/main.js +++ b/client/js/main.js @@ -60,17 +60,17 @@ api.fetchConfig().then(() => { window.alert('Could not fetch basic configuration from server'); }).then(() => { api.loginFromCookies().then(() => { - tags.refreshCategoryColorMap(); + tags.refreshCategoryColorMap(); + router.start(); + }, error => { + if (window.location.href.indexOf('login') !== -1) { + api.forget(); 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: ' + + } 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/comment.js b/client/js/models/comment.js index e10e83cb..e292ec46 100644 --- a/client/js/models/comment.js +++ b/client/js/models/comment.js @@ -22,16 +22,41 @@ class Comment extends events.EventTarget { return comment; } - get id() { return this._id; } - get postId() { return this._postId; } - get text() { return this._text || ''; } - get user() { return this._user; } - get creationTime() { return this._creationTime; } - get lastEditTime() { return this._lastEditTime; } - get score() { return this._score; } - get ownScore() { return this._ownScore; } + get id() { + return this._id; + } - set text(value) { this._text = value; } + get postId() { + return this._postId; + } + + get text() { + return this._text || ''; + } + + get user() { + return this._user; + } + + get creationTime() { + return this._creationTime; + } + + get lastEditTime() { + return this._lastEditTime; + } + + get score() { + return this._score; + } + + get ownScore() { + return this._ownScore; + } + + set text(value) { + this._text = value; + } save() { const detail = { @@ -56,8 +81,8 @@ class Comment extends events.EventTarget { delete() { return api.delete( - uri.formatApiLink('comment', this.id), - {version: this._version}) + uri.formatApiLink('comment', this.id), + {version: this._version}) .then(response => { this.dispatchEvent(new CustomEvent('delete', { detail: { @@ -70,8 +95,8 @@ class Comment extends events.EventTarget { setScore(score) { return api.put( - uri.formatApiLink('comment', this.id, 'score'), - {score: score}) + uri.formatApiLink('comment', this.id, 'score'), + {score: score}) .then(response => { this._updateFromResponse(response); this.dispatchEvent(new CustomEvent('changeScore', { @@ -84,15 +109,15 @@ class Comment extends events.EventTarget { } _updateFromResponse(response) { - this._version = response.version; - this._id = response.id; - this._postId = response.postId; - this._text = response.text; - this._user = response.user; + this._version = response.version; + this._id = response.id; + this._postId = response.postId; + this._text = response.text; + this._user = response.user; this._creationTime = response.creationTime; this._lastEditTime = response.lastEditTime; - this._score = parseInt(response.score); - this._ownScore = parseInt(response.ownScore); + this._score = parseInt(response.score); + this._ownScore = parseInt(response.ownScore); } } diff --git a/client/js/models/note.js b/client/js/models/note.js index 877db4e7..1709d443 100644 --- a/client/js/models/note.js +++ b/client/js/models/note.js @@ -11,10 +11,17 @@ class Note extends events.EventTarget { this._polygon = new PointList(); } - get text() { return this._text; } - get polygon() { return this._polygon; } + get text() { + return this._text; + } - set text(value) { this._text = value; } + get polygon() { + return this._polygon; + } + + set text(value) { + this._text = value; + } static fromResponse(response) { const note = new Note(); diff --git a/client/js/models/point.js b/client/js/models/point.js index f1c551e3..bbb05ecb 100644 --- a/client/js/models/point.js +++ b/client/js/models/point.js @@ -9,8 +9,13 @@ class Point extends events.EventTarget { this._y = y; } - get x() { return this._x; } - get y() { return this._y; } + get x() { + return this._x; + } + + get y() { + return this._y; + } set x(value) { this._x = value; @@ -21,6 +26,6 @@ class Point extends events.EventTarget { this._y = value; this.dispatchEvent(new CustomEvent('change', {detail: {point: this}})); } -}; +} module.exports = Point; diff --git a/client/js/models/post.js b/client/js/models/post.js index d2124adb..be219049 100644 --- a/client/js/models/post.js +++ b/client/js/models/post.js @@ -23,43 +23,141 @@ class Post extends events.EventTarget { this._updateFromResponse({}); } - get id() { return this._id; } - get type() { return this._type; } - get mimeType() { return this._mimeType; } - get creationTime() { return this._creationTime; } - get user() { return this._user; } - get safety() { return this._safety; } - get contentUrl() { return this._contentUrl; } - get fullContentUrl() { return this._fullContentUrl; } - get thumbnailUrl() { return this._thumbnailUrl; } - get source() { return this._source; } - get sourceSplit() { return this._source.split('\n'); } - get canvasWidth() { return this._canvasWidth || 800; } - get canvasHeight() { return this._canvasHeight || 450; } - get fileSize() { return this._fileSize || 0; } - get newContent() { throw 'Invalid operation'; } - get newThumbnail() { throw 'Invalid operation'; } + get id() { + return this._id; + } - get flags() { return this._flags; } - get tags() { return this._tags; } - get tagNames() { return this._tags.map(tag => tag.names[0]); } - get notes() { return this._notes; } - get comments() { return this._comments; } - get relations() { return this._relations; } + get type() { + return this._type; + } - get score() { return this._score; } - get commentCount() { return this._commentCount; } - get favoriteCount() { return this._favoriteCount; } - get ownFavorite() { return this._ownFavorite; } - get ownScore() { return this._ownScore; } - get hasCustomThumbnail() { return this._hasCustomThumbnail; } + get mimeType() { + return this._mimeType; + } - set flags(value) { this._flags = value; } - set safety(value) { this._safety = value; } - set relations(value) { this._relations = value; } - set newContent(value) { this._newContent = value; } - set newThumbnail(value) { this._newThumbnail = value; } - set source(value) { this._source = value; } + get creationTime() { + return this._creationTime; + } + + get user() { + return this._user; + } + + get safety() { + return this._safety; + } + + get contentUrl() { + return this._contentUrl; + } + + get fullContentUrl() { + return this._fullContentUrl; + } + + get thumbnailUrl() { + return this._thumbnailUrl; + } + + get source() { + return this._source; + } + + get sourceSplit() { + return this._source.split('\n'); + } + + get canvasWidth() { + return this._canvasWidth || 800; + } + + get canvasHeight() { + return this._canvasHeight || 450; + } + + get fileSize() { + return this._fileSize || 0; + } + + get newContent() { + throw 'Invalid operation'; + } + + get newThumbnail() { + throw 'Invalid operation'; + } + + get flags() { + return this._flags; + } + + get tags() { + return this._tags; + } + + get tagNames() { + return this._tags.map(tag => tag.names[0]); + } + + get notes() { + return this._notes; + } + + get comments() { + return this._comments; + } + + get relations() { + return this._relations; + } + + get score() { + return this._score; + } + + get commentCount() { + return this._commentCount; + } + + get favoriteCount() { + return this._favoriteCount; + } + + get ownFavorite() { + return this._ownFavorite; + } + + get ownScore() { + return this._ownScore; + } + + get hasCustomThumbnail() { + return this._hasCustomThumbnail; + } + + set flags(value) { + this._flags = value; + } + + set safety(value) { + this._safety = value; + } + + set relations(value) { + this._relations = value; + } + + set newContent(value) { + this._newContent = value; + } + + set newThumbnail(value) { + this._newThumbnail = value; + } + + set source(value) { + this._source = value; + } static fromResponse(response) { const ret = new Post(); @@ -158,8 +256,8 @@ class Post extends events.EventTarget { feature() { return api.post( - uri.formatApiLink('featured-post'), - {id: this._id}) + uri.formatApiLink('featured-post'), + {id: this._id}) .then(response => { return Promise.resolve(); }); @@ -167,8 +265,8 @@ class Post extends events.EventTarget { delete() { return api.delete( - uri.formatApiLink('post', this.id), - {version: this._version}) + uri.formatApiLink('post', this.id), + {version: this._version}) .then(response => { this.dispatchEvent(new CustomEvent('delete', { detail: { @@ -202,8 +300,8 @@ class Post extends events.EventTarget { setScore(score) { return api.put( - uri.formatApiLink('post', this.id, 'score'), - {score: score}) + uri.formatApiLink('post', this.id, 'score'), + {score: score}) .then(response => { const prevFavorite = this._ownFavorite; this._updateFromResponse(response); @@ -274,29 +372,29 @@ class Post extends events.EventTarget { _updateFromResponse(response) { const map = () => ({ - _version: response.version, - _id: response.id, - _type: response.type, - _mimeType: response.mimeType, - _creationTime: response.creationTime, - _user: response.user, - _safety: response.safety, - _contentUrl: response.contentUrl, + _version: response.version, + _id: response.id, + _type: response.type, + _mimeType: response.mimeType, + _creationTime: response.creationTime, + _user: response.user, + _safety: response.safety, + _contentUrl: response.contentUrl, _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, + _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, + _score: response.score, + _commentCount: response.commentCount, _favoriteCount: response.favoriteCount, - _ownScore: response.ownScore, - _ownFavorite: response.ownFavorite, + _ownScore: response.ownScore, + _ownFavorite: response.ownFavorite, _hasCustomThumbnail: response.hasCustomThumbnail, }); @@ -309,6 +407,6 @@ class Post extends events.EventTarget { Object.assign(this, map()); Object.assign(this._orig, map()); } -}; +} module.exports = Post; diff --git a/client/js/models/post_list.js b/client/js/models/post_list.js index 74f089f3..eae1128b 100644 --- a/client/js/models/post_list.js +++ b/client/js/models/post_list.js @@ -18,13 +18,13 @@ class PostList extends AbstractList { static search(text, offset, limit, fields) { return api.get( - uri.formatApiLink( - 'posts', { - query: PostList._decorateSearchQuery(text || ''), - offset: offset, - limit: limit, - fields: fields.join(','), - })) + uri.formatApiLink( + 'posts', { + query: PostList._decorateSearchQuery(text || ''), + offset: offset, + limit: limit, + fields: fields.join(','), + })) .then(response => { return Promise.resolve(Object.assign( {}, diff --git a/client/js/models/settings.js b/client/js/models/settings.js index b4b04bbb..774aa0bf 100644 --- a/client/js/models/settings.js +++ b/client/js/models/settings.js @@ -30,6 +30,7 @@ class Settings extends events.EventTarget { try { Object.assign(ret, JSON.parse(localStorage.getItem('settings'))); } catch (e) { + // continue regardless of error } return ret; } @@ -50,6 +51,6 @@ class Settings extends events.EventTarget { get() { return this.cache; } -}; +} module.exports = new Settings(); diff --git a/client/js/models/snapshot.js b/client/js/models/snapshot.js index 78b367c1..cf5a3083 100644 --- a/client/js/models/snapshot.js +++ b/client/js/models/snapshot.js @@ -10,12 +10,29 @@ class Snapshot extends events.EventTarget { this._updateFromResponse({}); } - get operation() { return this._operation; } - get type() { return this._type; } - get id() { return this._id; } - get user() { return this._user; } - get data() { return this._data; } - get time() { return this._time; } + get operation() { + return this._operation; + } + + get type() { + return this._type; + } + + get id() { + return this._id; + } + + get user() { + return this._user; + } + + get data() { + return this._data; + } + + get time() { + return this._time; + } static fromResponse(response) { const ret = new Snapshot(); @@ -26,11 +43,11 @@ class Snapshot extends events.EventTarget { _updateFromResponse(response) { const map = { _operation: response.operation, - _type: response.type, - _id: response.id, - _user: response.user, - _data: response.data, - _time: response.time, + _type: response.type, + _id: response.id, + _user: response.user, + _data: response.data, + _time: response.time, }; Object.assign(this, map); diff --git a/client/js/models/snapshot_list.js b/client/js/models/snapshot_list.js index 3263a6af..475b89a3 100644 --- a/client/js/models/snapshot_list.js +++ b/client/js/models/snapshot_list.js @@ -8,7 +8,7 @@ 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})) + 'snapshots', {query: text, offset: offset, limit: limit})) .then(response => { return Promise.resolve(Object.assign( {}, diff --git a/client/js/models/tag.js b/client/js/models/tag.js index c7435540..b99c63f1 100644 --- a/client/js/models/tag.js +++ b/client/js/models/tag.js @@ -20,18 +20,49 @@ class Tag extends events.EventTarget { this._updateFromResponse({}); } - get names() { return this._names; } - get category() { return this._category; } - get description() { return this._description; } - get suggestions() { return this._suggestions; } - get implications() { return this._implications; } - get postCount() { return this._postCount; } - get creationTime() { return this._creationTime; } - get lastEditTime() { return this._lastEditTime; } + get names() { + return this._names; + } - set names(value) { this._names = value; } - set category(value) { this._category = value; } - set description(value) { this._description = value; } + get category() { + return this._category; + } + + get description() { + return this._description; + } + + get suggestions() { + return this._suggestions; + } + + get implications() { + return this._implications; + } + + get postCount() { + return this._postCount; + } + + get creationTime() { + return this._creationTime; + } + + get lastEditTime() { + return this._lastEditTime; + } + + set names(value) { + this._names = value; + } + + set category(value) { + this._category = value; + } + + set description(value) { + this._description = value; + } static fromResponse(response) { const ret = new Tag(); @@ -113,8 +144,8 @@ class Tag extends events.EventTarget { delete() { return api.delete( - uri.formatApiLink('tag', this._origName), - {version: this._version}) + uri.formatApiLink('tag', this._origName), + {version: this._version}) .then(response => { this.dispatchEvent(new CustomEvent('delete', { detail: { @@ -127,14 +158,14 @@ class Tag extends events.EventTarget { _updateFromResponse(response) { const map = { - _version: response.version, - _origName: response.names ? response.names[0] : null, - _names: response.names, - _category: response.category, - _description: response.description, + _version: response.version, + _origName: response.names ? response.names[0] : null, + _names: response.names, + _category: response.category, + _description: response.description, _creationTime: response.creationTime, _lastEditTime: response.lastEditTime, - _postCount: response.usages || 0, + _postCount: response.usages || 0, }; for (let obj of [this, this._orig]) { @@ -145,6 +176,6 @@ class Tag extends events.EventTarget { Object.assign(this, map); Object.assign(this._orig, map); } -}; +} module.exports = Tag; diff --git a/client/js/models/tag_category.js b/client/js/models/tag_category.js index 04bd8fe6..42e54d8d 100644 --- a/client/js/models/tag_category.js +++ b/client/js/models/tag_category.js @@ -7,22 +7,41 @@ const events = require('../events.js'); class TagCategory extends events.EventTarget { constructor() { super(); - this._name = ''; - this._color = '#000000'; - this._tagCount = 0; + this._name = ''; + this._color = '#000000'; + this._tagCount = 0; this._isDefault = false; - this._origName = null; + this._origName = null; this._origColor = null; } - get name() { return this._name; } - get color() { return this._color; } - get tagCount() { return this._tagCount; } - get isDefault() { return this._isDefault; } - get isTransient() { return !this._origName; } + get name() { + return this._name; + } - set name(value) { this._name = value; } - set color(value) { this._color = value; } + get color() { + return this._color; + } + + get tagCount() { + return this._tagCount; + } + + get isDefault() { + return this._isDefault; + } + + get isTransient() { + return !this._origName; + } + + set name(value) { + this._name = value; + } + + set color(value) { + this._color = value; + } static fromResponse(response) { const ret = new TagCategory(); @@ -64,8 +83,8 @@ class TagCategory extends events.EventTarget { delete() { return api.delete( - uri.formatApiLink('tag-category', this._origName), - {version: this._version}) + uri.formatApiLink('tag-category', this._origName), + {version: this._version}) .then(response => { this.dispatchEvent(new CustomEvent('delete', { detail: { @@ -77,12 +96,12 @@ class TagCategory extends events.EventTarget { } _updateFromResponse(response) { - this._version = response.version; - this._name = response.name; - this._color = response.color; + this._version = response.version; + this._name = response.name; + this._color = response.color; this._isDefault = response.default; - this._tagCount = response.usages; - this._origName = this.name; + this._tagCount = response.usages; + this._origName = this.name; this._origColor = this.color; } } diff --git a/client/js/models/tag_list.js b/client/js/models/tag_list.js index d87b694e..31a34fa3 100644 --- a/client/js/models/tag_list.js +++ b/client/js/models/tag_list.js @@ -8,13 +8,13 @@ const Tag = require('./tag.js'); class TagList extends AbstractList { static search(text, offset, limit, fields) { return api.get( - uri.formatApiLink( - 'tags', { - query: text, - offset: offset, - limit: limit, - fields: fields.join(','), - })) + uri.formatApiLink( + 'tags', { + query: text, + offset: offset, + limit: limit, + fields: fields.join(','), + })) .then(response => { return Promise.resolve(Object.assign( {}, diff --git a/client/js/models/top_navigation.js b/client/js/models/top_navigation.js index bf2cffe0..44ad6712 100644 --- a/client/js/models/top_navigation.js +++ b/client/js/models/top_navigation.js @@ -12,7 +12,7 @@ class TopNavigationItem { this.imageUrl = imageUrl === undefined ? null : imageUrl; this.key = null; } -}; +} class TopNavigation extends events.EventTarget { constructor() { @@ -72,7 +72,7 @@ class TopNavigation extends events.EventTarget { hide(key) { this.get(key).available = false; } -}; +} function _makeTopNavigation() { const ret = new TopNavigation(); diff --git a/client/js/models/user.js b/client/js/models/user.js index abb5f57f..40fbb14d 100644 --- a/client/js/models/user.js +++ b/client/js/models/user.js @@ -11,28 +11,89 @@ class User extends events.EventTarget { this._updateFromResponse({}); } - get name() { return this._name; } - get rank() { return this._rank; } - get email() { return this._email; } - get avatarStyle() { return this._avatarStyle; } - get avatarUrl() { return this._avatarUrl; } - get creationTime() { return this._creationTime; } - get lastLoginTime() { return this._lastLoginTime; } - get commentCount() { return this._commentCount; } - get favoritePostCount() { return this._favoritePostCount; } - get uploadedPostCount() { return this._uploadedPostCount; } - get likedPostCount() { return this._likedPostCount; } - get dislikedPostCount() { return this._dislikedPostCount; } - get rankName() { return api.rankNames.get(this.rank); } - get avatarContent() { throw 'Invalid operation'; } - get password() { throw 'Invalid operation'; } + get name() { + return this._name; + } - set name(value) { this._name = value; } - set rank(value) { this._rank = value; } - set email(value) { this._email = value || null; } - set avatarStyle(value) { this._avatarStyle = value; } - set avatarContent(value) { this._avatarContent = value; } - set password(value) { this._password = value; } + get rank() { + return this._rank; + } + + get email() { + return this._email; + } + + get avatarStyle() { + return this._avatarStyle; + } + + get avatarUrl() { + return this._avatarUrl; + } + + get creationTime() { + return this._creationTime; + } + + get lastLoginTime() { + return this._lastLoginTime; + } + + get commentCount() { + return this._commentCount; + } + + get favoritePostCount() { + return this._favoritePostCount; + } + + get uploadedPostCount() { + return this._uploadedPostCount; + } + + get likedPostCount() { + return this._likedPostCount; + } + + get dislikedPostCount() { + return this._dislikedPostCount; + } + + get rankName() { + return api.rankNames.get(this.rank); + } + + get avatarContent() { + throw 'Invalid operation'; + } + + get password() { + throw 'Invalid operation'; + } + + set name(value) { + this._name = value; + } + + set rank(value) { + this._rank = value; + } + + set email(value) { + this._email = value || null; + } + + set avatarStyle(value) { + this._avatarStyle = value; + } + + set avatarContent(value) { + this._avatarContent = value; + } + + set password(value) { + this._password = value; + } static fromResponse(response) { const ret = new User(); @@ -91,8 +152,8 @@ class User extends events.EventTarget { delete() { return api.delete( - uri.formatApiLink('user', this._orig._name), - {version: this._version}) + uri.formatApiLink('user', this._orig._name), + {version: this._version}) .then(response => { this.dispatchEvent(new CustomEvent('delete', { detail: { @@ -105,27 +166,27 @@ class User extends events.EventTarget { _updateFromResponse(response) { const map = { - _version: response.version, - _name: response.name, - _rank: response.rank, - _email: response.email, - _avatarStyle: response.avatarStyle, - _avatarUrl: response.avatarUrl, - _creationTime: response.creationTime, - _lastLoginTime: response.lastLoginTime, - _commentCount: response.commentCount, + _version: response.version, + _name: response.name, + _rank: response.rank, + _email: response.email, + _avatarStyle: response.avatarStyle, + _avatarUrl: response.avatarUrl, + _creationTime: response.creationTime, + _lastLoginTime: response.lastLoginTime, + _commentCount: response.commentCount, _favoritePostCount: response.favoritePostCount, _uploadedPostCount: response.uploadedPostCount, - _likedPostCount: response.likedPostCount, + _likedPostCount: response.likedPostCount, _dislikedPostCount: response.dislikedPostCount, }; Object.assign(this, map); Object.assign(this._orig, map); - this._password = null; - this._avatarContent = null; + this._password = null; + this._avatarContent = null; } -}; +} module.exports = User; diff --git a/client/js/models/user_list.js b/client/js/models/user_list.js index c48fc883..d44622c8 100644 --- a/client/js/models/user_list.js +++ b/client/js/models/user_list.js @@ -8,8 +8,8 @@ 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})) + uri.formatApiLink( + 'users', {query: text, offset: offset, limit: limit})) .then(response => { return Promise.resolve(Object.assign( {}, diff --git a/client/js/models/user_token.js b/client/js/models/user_token.js index 6e70a94b..e49f5aa0 100644 --- a/client/js/models/user_token.js +++ b/client/js/models/user_token.js @@ -11,16 +11,41 @@ class UserToken extends events.EventTarget { this._updateFromResponse({}); } - get token() { return this._token; } - get note() { return this._note; } - get enabled() { return this._enabled; } - get version() { return this._version; } - get expirationTime() { return this._expirationTime; } - get creationTime() { return this._creationTime; } - get lastEditTime() { return this._lastEditTime; } - get lastUsageTime() { return this._lastUsageTime; } + get token() { + return this._token; + } - set note(value) { this._note = value; } + get note() { + return this._note; + } + + get enabled() { + return this._enabled; + } + + get version() { + return this._version; + } + + get expirationTime() { + return this._expirationTime; + } + + get creationTime() { + return this._creationTime; + } + + get lastEditTime() { + return this._lastEditTime; + } + + get lastUsageTime() { + return this._lastUsageTime; + } + + set note(value) { + this._note = value; + } static fromResponse(response) { if (typeof response.results !== 'undefined') { @@ -98,14 +123,14 @@ class UserToken extends events.EventTarget { _updateFromResponse(response) { const map = { - _token: response.token, - _note: response.note, - _enabled: response.enabled, - _expirationTime: response.expirationTime, - _version: response.version, - _creationTime: response.creationTime, - _lastEditTime: response.lastEditTime, - _lastUsageTime: response.lastUsageTime, + _token: response.token, + _note: response.note, + _enabled: response.enabled, + _expirationTime: response.expirationTime, + _version: response.version, + _creationTime: response.creationTime, + _lastEditTime: response.lastEditTime, + _lastUsageTime: response.lastUsageTime, }; Object.assign(this, map); diff --git a/client/js/router.js b/client/js/router.js index dd9b9e15..b5b48552 100644 --- a/client/js/router.js +++ b/client/js/router.js @@ -51,7 +51,7 @@ class Context { replaceState() { history.replaceState(this.state, this.title, this.canonicalPath); } -}; +} class Route { constructor(path) { @@ -119,7 +119,7 @@ class Route { return true; } -}; +} class Router { constructor() { @@ -217,14 +217,14 @@ class Router { if (current === ctx.canonicalPath) { return; } - router.stop(); + this.stop(); location.href = ctx.canonicalPath; } get url() { return location.pathname + location.search + location.hash; } -}; +} const _onPopState = router => { let loaded = false; diff --git a/client/js/util/keyboard.js b/client/js/util/keyboard.js index c3b9543e..8ee6ee97 100644 --- a/client/js/util/keyboard.js +++ b/client/js/util/keyboard.js @@ -5,6 +5,7 @@ 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) { var self = this; if (paused) { @@ -28,6 +29,10 @@ function unbind(hotkey) { module.exports = { bind: bind, unbind: unbind, - pause: () => { paused = true; }, - unpause: () => { paused = false; }, + pause: () => { + paused = true; + }, + unpause: () => { + paused = false; + }, }; diff --git a/client/js/util/markdown.js b/client/js/util/markdown.js index f326ebb7..210280e8 100644 --- a/client/js/util/markdown.js +++ b/client/js/util/markdown.js @@ -48,7 +48,7 @@ class TildeWrapper extends BaseMarkdownWrapper { } } -//prevent ^#... from being treated as headers, due to tag permalinks +// prevent ^#... from being treated as headers, due to tag permalinks class TagPermalinkFixWrapper extends BaseMarkdownWrapper { preprocess(text) { return text.replace(/^#/g, '%%%#'); @@ -59,7 +59,7 @@ class TagPermalinkFixWrapper extends BaseMarkdownWrapper { } } -//post, user and tags permalinks +// post, user and tags permalinks class EntityPermalinkWrapper extends BaseMarkdownWrapper { preprocess(text) { // URL-based permalinks @@ -127,7 +127,7 @@ function createRenderer() { const renderer = new marked.Renderer(); renderer.image = (href, title, alt) => { let [_, url, width, height] = - /^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/.exec(href); + (/^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/).exec(href); let res = ' - 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) { @@ -157,10 +156,7 @@ function makeColorInput(options) { color: ${options.value}`, }); return makeElement( - 'label', {class: 'color'}, - textInput, - backgroundPreviewNode, - textPreviewNode); + 'label', {class: 'color'}, textInput, backgroundPreviewNode, textPreviewNode); } function makeNumericInput(options) { @@ -175,14 +171,12 @@ function makeDateInput(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) { @@ -335,26 +329,25 @@ function clearMessages(target) { function htmlToDom(html) { // code taken from jQuery + Krasimir Tsonev's blog const wrapMap = { - _: [1, '