diff options
| author | Greg <supahgreg@users.noreply.github.com> | 2025-10-13 23:39:24 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-13 23:39:24 -0500 |
| commit | 6505cbb592b91556ca25a2bf72ad1d8cb0b3bc2a (patch) | |
| tree | 8ab133cc17a329ef7d99d152b3f6b4edc3830509 | |
| parent | 0d2b1d601294802286aa26e5486c1c4fee92c05a (diff) | |
| parent | 8b46ab31a96b6b6129f624719ac33ddf761805f1 (diff) | |
Merge pull request #42 from tt-rss/bugfix/eslint-config-and-findings
Get ESLint 9.x working, make the new config stricter, address findings
40 files changed, 415 insertions, 620 deletions
diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 53184783a..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,300 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "es6": true, - "jquery": false, - "webextensions": false - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaVersion": 2020 - }, - "rules": { - "accessor-pairs": "error", - "array-bracket-newline": "off", - "array-bracket-spacing": "off", - "array-callback-return": "error", - "array-element-newline": "off", - "arrow-body-style": "error", - "arrow-parens": "error", - "arrow-spacing": "error", - "block-scoped-var": "off", - "block-spacing": [ - "error", - "always" - ], - "brace-style": "off", - "callback-return": "off", - "camelcase": "off", - "capitalized-comments": "off", - "class-methods-use-this": "error", - "comma-dangle": "off", - "comma-spacing": "off", - "comma-style": [ - "error", - "last" - ], - "complexity": "off", - "computed-property-spacing": [ - "error", - "never" - ], - "consistent-return": "off", - "consistent-this": "off", - "curly": "off", - "default-case": "off", - "dot-location": "off", - "dot-notation": "off", - "eol-last": "error", - "eqeqeq": "off", - "func-call-spacing": "error", - "func-name-matching": "error", - "func-names": "off", - "func-style": "off", - "function-paren-newline": "off", - "generator-star-spacing": "error", - "global-require": "error", - "guard-for-in": "off", - "handle-callback-err": "off", - "id-blacklist": "error", - "id-length": "off", - "id-match": "error", - "implicit-arrow-linebreak": "off", - "indent": "off", - "indent-legacy": "off", - "init-declarations": "off", - "jsx-quotes": "error", - "key-spacing": "off", - "keyword-spacing": [ - "error", - { - "after": true, - "before": true - } - ], - "line-comment-position": "off", - "linebreak-style": [ - "error", - "unix" - ], - "lines-around-comment": "off", - "lines-around-directive": "error", - "lines-between-class-members": "error", - "max-classes-per-file": "off", - "max-depth": "off", - "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": [ "warn", { "max" : 2 } ], - "multiline-comment-style": "off", - "multiline-ternary": "off", - "new-cap": "warn", - "new-parens": "error", - "newline-after-var": "off", - "newline-before-return": "off", - "newline-per-chained-call": "off", - "no-alert": "off", - "no-array-constructor": "error", - "no-async-promise-executor": "off", - "no-await-in-loop": "warn", - "no-bitwise": "off", - "no-buffer-constructor": "error", - "no-caller": "error", - "no-catch-shadow": "off", - "no-confusing-arrow": "error", - "no-continue": "off", - "no-console": "off", - "no-div-regex": "error", - "no-duplicate-imports": "error", - "no-else-return": "off", - "no-empty": [ - "error", - { - "allowEmptyCatch": true - } - ], - "no-empty-function": "error", - "no-eq-null": "off", - "no-eval": "error", - "no-extend-native": "off", - "no-extra-bind": "error", - "no-extra-label": "error", - "no-extra-parens": "off", - "no-floating-decimal": "error", - "no-implicit-globals": "off", - "no-implied-eval": "off", - "no-inline-comments": "off", - "no-inner-declarations": [ - "error", - "functions" - ], - "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-magic-numbers": "off", - "no-misleading-character-class": "off", - "no-mixed-operators": "off", - "no-mixed-requires": "error", - "no-multi-assign": "error", - "no-multi-spaces": "off", - "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": "warn", - "no-new-func": "error", - "no-new-object": "off", - "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-prototype-builtins": "warn", - "no-restricted-globals": "error", - "no-restricted-imports": "error", - "no-restricted-modules": "error", - "no-restricted-properties": "error", - "no-restricted-syntax": "error", - "no-return-assign": [ - "error", - "except-parens" - ], - "no-return-await": "error", - "no-script-url": "error", - "no-self-compare": "error", - "no-sequences": "error", - "no-shadow": "off", - "no-shadow-restricted-names": "error", - "no-spaced-func": "error", - "no-sync": "error", - "no-tabs": "off", - "no-template-curly-in-string": "error", - "no-ternary": "off", - "no-throw-literal": "error", - "no-trailing-spaces": "error", - "no-undef-init": "error", - "no-undefined": "off", - "no-undef": "warn", - "no-underscore-dangle": "off", - "no-unmodified-loop-condition": "error", - "no-unneeded-ternary": [ - "error", - { - "defaultAssignment": true - } - ], - "no-unused-expressions": "off", - "no-unused-vars": "warn", - "no-use-before-define": "off", - "no-useless-call": "error", - "no-useless-computed-key": "error", - "no-useless-concat": "error", - "no-useless-constructor": "error", - "no-useless-rename": "error", - "no-useless-return": "off", - "no-var": "warn", - "no-void": "error", - "no-warning-comments": "off", - "no-whitespace-before-property": "error", - "no-with": "error", - "nonblock-statement-body-position": [ - "error", - "any" - ], - "object-curly-newline": "off", - "object-curly-spacing": "off", - "object-property-newline": "off", - "object-shorthand": "off", - "one-var": "off", - "one-var-declaration-per-line": "error", - "operator-assignment": "off", - "operator-linebreak": [ - "error", - "after" - ], - "padded-blocks": "off", - "padding-line-between-statements": "error", - "prefer-arrow-callback": "off", - "prefer-const": "error", - "prefer-destructuring": "off", - "prefer-numeric-literals": "error", - "prefer-object-spread": "off", - "prefer-promise-reject-errors": "error", - "prefer-reflect": "off", - "prefer-rest-params": "error", - "prefer-spread": "error", - "prefer-template": "off", - "quote-props": "off", - "quotes": "off", - "radix": [ - "error", - "as-needed" - ], - "require-atomic-updates": "off", - "require-await": "warn", - "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": "off", - "space-before-blocks": "off", - "space-before-function-paren": "off", - "space-in-parens": "off", - "space-infix-ops": "off", - "space-unary-ops": [ - "error", - { - "nonwords": false, - "words": false - } - ], - "spaced-comment": "off", - "strict": [ - "off", - "never" - ], - "switch-colon-spacing": "error", - "symbol-description": "error", - "template-curly-spacing": "error", - "template-tag-spacing": "error", - "unicode-bom": [ - "error", - "never" - ], - "valid-jsdoc": "error", - "vars-on-top": "off", - "wrap-iife": "error", - "wrap-regex": "error", - "yield-star-spacing": "error", - "yoda": [ - "error", - "never" - ] - } -}; diff --git a/.github/workflows/javascipt-code-quality.yml b/.github/workflows/javascipt-code-quality.yml index a6a9e10eb..531693250 100644 --- a/.github/workflows/javascipt-code-quality.yml +++ b/.github/workflows/javascipt-code-quality.yml @@ -5,11 +5,9 @@ on: paths: - 'js/**.js' - 'plugins/**.js' + - 'eslint.config.js' - 'package.json' - 'package-lock.json' - - '.eslintrc.*' - - 'eslint.config.*' - - '.github/workflows/javascript-code-quality.yml' # Allow manual triggering workflow_dispatch: # Allow other workflows (e.g. Publish) to invoke this one. diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1a5e19e22..ce4bb81e9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -24,17 +24,21 @@ permissions: jobs: - test-docker: + docker-code-quality: uses: ./.github/workflows/docker-code-quality.yml - test-php: + javascript-code-quality: + uses: ./.github/workflows/javascript-code-quality.yml + + php-code-quality: uses: ./.github/workflows/php-code-quality.yml publish: name: Publish Docker image ${{ matrix.image.name }} needs: - - test-docker - - test-php + - docker-code-quality + - javascript-code-quality + - php-code-quality runs-on: ubuntu-latest permissions: contents: read diff --git a/.github/workflows/validate-sql.yml b/.github/workflows/validate-sql.yml index b165125ca..ab210cebe 100644 --- a/.github/workflows/validate-sql.yml +++ b/.github/workflows/validate-sql.yml @@ -5,7 +5,6 @@ on: paths: - 'sql/pgsql/schema.sql' - 'sql/pgsql/migrations/*.sql' - - '.github/workflows/validate-sql.yml' # Allow manual triggering workflow_dispatch: # Allow other workflows (e.g. Publish) to invoke this one. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..172f0ce21 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,43 @@ +import globals from 'globals'; +import js from '@eslint/js'; +import stylistic from '@stylistic/eslint-plugin'; + +export default [ + js.configs.recommended, + + { + files: ['js/**/*.js', 'plugins/**/*.js'], + languageOptions: { + ecmaVersion: 2022, + sourceType: 'script', + globals: { + ...globals.browser, + + // Dojo + dojo: 'readonly', + dijit: 'readonly' + } + }, + + plugins: { + '@stylistic/js': stylistic + }, + + rules: { + 'no-console': 'off', + 'prefer-const': 'error', + 'eqeqeq': ['error', 'always'], + 'no-empty': ['error', { 'allowEmptyCatch': true }], + + // Stylistic rules (replacing those deprecated in ESLint) + '@stylistic/js/linebreak-style': ['error', 'unix'], + '@stylistic/js/eol-last': 'error', + '@stylistic/js/no-trailing-spaces': 'error', + '@stylistic/js/no-multiple-empty-lines': ['error', { 'max': 2 }], + '@stylistic/js/keyword-spacing': ['error', { 'after': true, 'before': true }], + '@stylistic/js/block-spacing': ['error', 'always'], + '@stylistic/js/computed-property-spacing': ['error', 'never'], + '@stylistic/js/max-statements-per-line': ['warn', { 'max': 2 }] + } + } +]; @@ -1,8 +1,7 @@ 'use strict'; -/* eslint-disable new-cap */ /* global __, Article, Headlines, Filters, fox */ -/* global xhr, dojo, dijit, PluginHost, Notify, Feeds, Cookie */ +/* global xhr, PluginHost, Notify, Feeds, Cookie */ /* global CommonDialogs, Plugins */ const App = { @@ -75,7 +74,7 @@ const App = { return ` <select name="${name}" dojoType="fox.form.Select" id="${App.escapeHtml(id)}" ${this.attributes_to_string(attributes)}> ${values.map((v) => - `<option ${v == value ? 'selected="selected"' : ''} value="${App.escapeHtml(v)}">${App.escapeHtml(v)}</option>` + `<option ${v === value ? 'selected="selected"' : ''} value="${App.escapeHtml(v)}">${App.escapeHtml(v)}</option>` ).join("")} </select> ` @@ -89,7 +88,7 @@ const App = { return ` <select name="${name}" dojoType="fox.form.Select" id="${App.escapeHtml(id)}" ${this.attributes_to_string(attributes)}> ${keys.map((vk) => - `<option ${vk == value ? 'selected="selected"' : ''} value="${App.escapeHtml(vk)}">${App.escapeHtml(values[vk])}</option>` + `<option ${vk === value ? 'selected="selected"' : ''} value="${App.escapeHtml(vk)}">${App.escapeHtml(values[vk])}</option>` ).join("")} </select> ` @@ -197,7 +196,7 @@ const App = { mql.addEventListener("change", () => { this.nightModeChanged(mql.matches, App.byId("theme_auto_css")); }); - } catch (e) { + } catch { console.warn("exception while trying to set MQL event listener"); } @@ -277,7 +276,7 @@ const App = { try { const results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href); return decodeURIComponent(results[1].replace(/\+/g, " ")) || 0; - } catch (e) { + } catch { return 0; } }, @@ -332,8 +331,8 @@ const App = { const hotkeys_map = this.getInitParam("hotkeys"); for (const seq in hotkeys_map[1]) { - if (hotkeys_map[1].hasOwnProperty(seq)) { - if (seq == sequence) { + if (Object.prototype.hasOwnProperty.call(hotkeys_map[1], seq)) { + if (seq === sequence) { return hotkeys_map[1][seq]; } } @@ -345,11 +344,11 @@ const App = { const keycode = event.which; const keychar = String.fromCharCode(keycode); - if (keycode == 27) { // escape and drop prefix + if (keycode === 27) { // escape and drop prefix this.hotkey_prefix = false; } - if (!this.hotkey_prefix && hotkeys_map[0].indexOf(keychar) != -1) { + if (!this.hotkey_prefix && hotkeys_map[0].indexOf(keychar) !== -1) { this.hotkey_prefix = keychar; App.byId("cmdline").innerHTML = keychar; @@ -370,7 +369,7 @@ const App = { let hotkey_name = ""; - if (event.type == "keydown") { + if (event.type === 'keydown') { hotkey_name = "(" + keycode + ")"; // ensure ^*char notation @@ -423,7 +422,7 @@ const App = { '/': '/', }; - return p.replace(/[&<>"'\/]/g, m => map[m]); + return p.replace(/[&<>"'/]/g, m => map[m]); }, unescapeHtml: function(p) { if (typeof p !== 'string' || p.indexOf('&') === -1) @@ -473,20 +472,20 @@ const App = { const counters = reply['counters']; const runtime_info = reply['runtime-info']; - if (error && error.code && error.code != App.Error.E_SUCCESS) { + if (error && error.code && error.code !== App.Error.E_SUCCESS) { console.warn("handleRpcJson: fatal error", error); this.Error.fatal(error.code, error.params); return false; } - if (seq && this.get_seq() != seq) { + if (seq && this.get_seq() !== seq) { console.warn("handleRpcJson: sequence mismatch: ", seq, '!=', this.get_seq()); return false; } // not in preferences - if (typeof Feeds != "undefined") { - if (message == "UPDATE_COUNTERS") { + if (typeof Feeds !== 'undefined') { + if (message === 'UPDATE_COUNTERS') { console.log("need to refresh counters for", reply.feeds); Feeds.requestCounters(reply.feeds); } @@ -515,12 +514,12 @@ const App = { console.log("RI:", k, "=>", v); - if (k == "daemon_is_running" && v != 1) { + if (k === "daemon_is_running" && v !== 1) { Notify.error("Update daemon is not running.", true); return; } - if (k == "recent_log_events") { + if (k === "recent_log_events") { const alert = App.find(".log-alert"); if (alert) { @@ -528,14 +527,14 @@ const App = { } } - if (k == "daemon_stamp_ok" && v != 1) { + if (k === "daemon_stamp_ok" && v !== 1) { Notify.error("Update daemon is not updating feeds.", true); return; } - if (typeof Feeds != "undefined") { - if (k == "max_feed_id" || k == "num_feeds") { - if (this.getInitParam(k) && this.getInitParam(k) != v) { + if (typeof Feeds !== 'undefined') { + if (k === "max_feed_id" || k === "num_feeds") { + if (this.getInitParam(k) && this.getInitParam(k) !== v) { console.log("feed count changed, need to reload feedlist:", this.getInitParam(k), v); Feeds.reload(); } @@ -609,13 +608,13 @@ const App = { E_SCHEMA_MISMATCH: "E_SCHEMA_MISMATCH", E_URL_SCHEME_MISMATCH: "E_URL_SCHEME_MISMATCH", fatal: function (error, params = {}) { - if (error == App.Error.E_UNAUTHORIZED) { + if (error === App.Error.E_UNAUTHORIZED) { window.location.href = "index.php"; return; - } else if (error == App.Error.E_SCHEMA_MISMATCH) { + } else if (error === App.Error.E_SCHEMA_MISMATCH) { window.location.href = "public.php?op=dbupdate"; return; - } else if (error == App.Error.E_URL_SCHEME_MISMATCH) { + } else if (error === App.Error.E_URL_SCHEME_MISMATCH) { params.description = __("URL scheme reported by your browser (%a) doesn't match server-configured SELF_URL_PATH (%b), check X-Forwarded-Proto.") .replace("%a", params.client_scheme) .replace("%b", params.server_scheme); @@ -702,6 +701,7 @@ const App = { this.is_prefs = is_prefs; window.onerror = this.Error.onWindowError; + /* global __default_dark_theme, __default_light_theme */ this.setInitParam("csrf_token", __csrf_token); this.setInitParam("default_light_theme", __default_light_theme); this.setInitParam("default_dark_theme", __default_dark_theme); @@ -744,12 +744,12 @@ const App = { } }); - if (typeof Promise.allSettled == "undefined") { + if (typeof Promise.allSettled === "undefined") { errorMsg = `Browser check failed: <code>Promise.allSettled</code> is not defined.`; throw new Error(errorMsg); } - return errorMsg == ""; + return errorMsg === ""; }, updateRuntimeInfo: function() { xhr.json("backend.php", {op: "RPC", method: "getruntimeinfo"}, () => { @@ -902,18 +902,17 @@ const App = { document.title = tmp; }, hotkeyHandler: function(event) { - if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return; + if (event.target.nodeName === "INPUT" || event.target.nodeName === "TEXTAREA") return; // Arrow buttons and escape are not reported via keypress, handle them via keydown. // escape = 27, left = 37, up = 38, right = 39, down = 40, pgup = 33, pgdn = 34, insert = 45, delete = 46 - if (event.type == "keydown" && event.which != 27 && (event.which < 33 || event.which > 46)) return; - + if (event.type === "keydown" && event.which !== 27 && (event.which < 33 || event.which > 46)) return; const action_name = this.keyeventToAction(event); if (action_name) { const action_func = this.hotkey_actions[action_name]; - if (action_func != null) { + if (typeof action_func === 'function') { action_func(event); event.stopPropagation(); return false; @@ -1120,7 +1119,7 @@ const App = { } }; this.hotkey_actions["email_article"] = () => { - if (typeof Plugins.Mail != "undefined") { + if (typeof Plugins.Mail !== "undefined") { Plugins.Mail.onHotkey(Headlines.getSelected()); } else { alert(__("Please enable mail or mailto plugin first.")); @@ -1145,7 +1144,7 @@ const App = { Headlines.select('none'); }; this.hotkey_actions["feed_refresh"] = () => { - if (typeof Feeds.getActive() != "undefined") { + if (typeof Feeds.getActive() !== "undefined") { Feeds.open({feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()}); } }; @@ -1191,7 +1190,7 @@ const App = { CommonDialogs.editFeed(Feeds.getActive()); }; this.hotkey_actions["feed_catchup"] = () => { - if (typeof Feeds.getActive() != "undefined") { + if (typeof Feeds.getActive() !== "undefined") { Feeds.catchupCurrent(); } }; @@ -1254,7 +1253,7 @@ const App = { Feeds.toggle(); }; this.hotkey_actions["toggle_full_text"] = () => { - if (typeof Plugins.Af_Readability != "undefined") { + if (typeof Plugins.Af_Readability !== "undefined") { if (Article.getActive()) Plugins.Af_Readability.embed(Article.getActive()); } else { diff --git a/js/Article.js b/js/Article.js index a57454dec..67de59aea 100644 --- a/js/Article.js +++ b/js/Article.js @@ -1,7 +1,6 @@ 'use strict' -/* eslint-disable no-new */ -/* global __, ngettext, App, Headlines, xhr, dojo, dijit, PluginHost, Notify, fox */ +/* global __, ngettext, App, Headlines, xhr, PluginHost, Notify, fox */ const Article = { _scroll_reset_timeout: false, @@ -166,7 +165,7 @@ const Article = { `<div class='attachments-inline'> ${enclosures.entries.map((enc) => { if (!enclosures.inline_text_only) { - if (enc.content_type && enc.content_type.indexOf("image/") != -1) { + if (enc.content_type && enc.content_type.indexOf("image/") !== -1) { return `<p> <img loading="lazy" width="${enc.width ? enc.width : ''}" @@ -174,7 +173,7 @@ const Article = { src="${App.escapeHtml(enc.content_url)}" title="${App.escapeHtml(enc.title ? enc.title : enc.content_url)}"/> </p>` - } else if (enc.content_type && enc.content_type.indexOf("audio/") != -1 && App.audioCanPlay(enc.content_type)) { + } else if (enc.content_type && enc.content_type.indexOf("audio/") !== -1 && App.audioCanPlay(enc.content_type)) { return `<p class='inline-player' title="${App.escapeHtml(enc.content_url)}"> <audio preload="none" controls="controls"> <source type="${App.escapeHtml(enc.content_type)}" src="${App.escapeHtml(enc.content_url)}"/> @@ -221,7 +220,7 @@ const Article = { try { c.domNode.scrollTop = 0; - } catch (e) { + } catch { } c.attr('content', article); @@ -231,7 +230,7 @@ const Article = { try { c.focus(); - } catch (e) { + } catch { } }, formatComments: function(hl) { @@ -250,7 +249,7 @@ const Article = { return comments; }, unpack: function(row) { - if (row.getAttribute("data-is-packed") == "1") { + if (row.getAttribute("data-is-packed") === "1") { console.log("unpacking: " + row.id); const container = row.querySelector(".content-inner"); @@ -260,7 +259,7 @@ const Article = { dojo.parser.parse(container); // blank content element might screw up onclick selection and keyboard moving - if (container.textContent.length == 0) + if (container.textContent.length === 0) container.innerHTML += " "; // in expandable mode, save content for later, so that we can pack unfocused rows back @@ -273,7 +272,7 @@ const Article = { } }, pack: function(row) { - if (row.getAttribute("data-is-packed") != "1") { + if (row.getAttribute("data-is-packed") !== "1") { console.log("packing", row.id); row.setAttribute("data-is-packed", "1"); @@ -428,7 +427,7 @@ const Article = { } }, setActive: function (id) { - if (id != Article.getActive()) { + if (id !== Article.getActive()) { console.log("setActive", id, "was", Article.getActive()); App.findAll("div[id*=RROW][class*=active]").forEach((row) => { @@ -446,17 +445,13 @@ const Article = { row.removeClassName("Unread"); row.addClassName("active"); - PluginHost.run(PluginHost.HOOK_ARTICLE_SET_ACTIVE, row.getAttribute("data-article-id")); + PluginHost.run(PluginHost.HOOK_ARTICLE_SET_ACTIVE, parseInt(row.getAttribute('data-article-id'))); } } }, getActive: function () { const row = document.querySelector("#headlines-frame > div[id*=RROW][class*=active]"); - - if (row) - return row.getAttribute("data-article-id"); - else - return 0; + return row ? parseInt(row.getAttribute('data-article-id')) : 0; }, scrollByPages: function (page_offset) { App.Scrollable.scrollByPages(App.byId("content-insert"), page_offset); diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js index f1be94c7c..16c1f5f46 100644 --- a/js/CommonDialogs.js +++ b/js/CommonDialogs.js @@ -1,9 +1,6 @@ 'use strict' -/* eslint-disable new-cap */ -/* eslint-disable no-new */ - -/* global __, dojo, dijit, Notify, App, Feeds, xhr, Tables, fox */ +/* global __, Notify, App, Feeds, xhr, Tables, fox */ /* exported CommonDialogs */ const CommonDialogs = { @@ -184,7 +181,7 @@ const CommonDialogs = { select.addOption({value: '', label: __("Expand to select feed")}); for (const feedUrl in feeds) { - if (feeds.hasOwnProperty(feedUrl)) { + if (Object.prototype.hasOwnProperty.call(feeds, feedUrl)) { select.addOption({value: feedUrl, label: feeds[feedUrl]}); } } @@ -332,7 +329,7 @@ const CommonDialogs = { addLabel: function() { const caption = prompt(__("Please enter label caption:"), ""); - if (caption != undefined && caption.trim().length > 0) { + if (caption !== undefined && caption.trim().length > 0) { const query = {op: "Pref_Labels", method: "add", caption: caption.trim()}; @@ -351,7 +348,7 @@ const CommonDialogs = { const msg = __("Unsubscribe from %s?").replace("%s", title); - if (typeof title == "undefined" || confirm(msg)) { + if (typeof title === "undefined" || confirm(msg)) { Notify.progress("Removing feed..."); const query = {op: "Pref_Feeds", quiet: 1, method: "remove", ids: feed_id}; @@ -360,7 +357,7 @@ const CommonDialogs = { if (App.isPrefs()) { dijit.byId("feedTree").reload(); } else { - if (feed_id == Feeds.getActive()) + if (feed_id === Feeds.getActive()) setTimeout(() => { Feeds.openDefaultFeed(); }, @@ -396,10 +393,10 @@ const CommonDialogs = { } }, uploadIcon: function(input) { - if (input.files.length != 0) { + if (input.files.length !== 0) { const icon_file = input.files[0]; - if (icon_file.type.indexOf("image/") == -1) { + if (icon_file.type.indexOf("image/") === -1) { alert(__("Please select an image file.")); return; } @@ -501,7 +498,7 @@ const CommonDialogs = { xhr.json("backend.php", {op: "Pref_Feeds", method: "editfeed", id: feed_id}, (reply) => { const feed = reply.feed; - const is_readonly = reply.user.access_level == App.UserAccessLevels.ACCESS_LEVEL_READONLY; + const is_readonly = reply.user.access_level === App.UserAccessLevels.ACCESS_LEVEL_READONLY; // for unsub prompt dialog.feed_title = feed.title; diff --git a/js/CommonFilters.js b/js/CommonFilters.js index 6d40373d6..54df70266 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -1,9 +1,7 @@ 'use strict' -/* eslint-disable no-new */ - /* global __, App, Article, Lists, fox */ -/* global xhr, dojo, dijit, Notify, Feeds */ +/* global xhr, Notify, Feeds */ /* exported Filters */ const Filters = { @@ -61,7 +59,7 @@ const Filters = { // all done-- either the backend found no more pre-filtering entries, or test limits were reached test_dialog.domNode.querySelector(".loading-indicator").hide(); - if (test_dialog.results == 0) { + if (test_dialog.results === 0) { results_list.innerHTML = `<li class="text-center text-muted"> ${__('No recent articles matching this filter have been found.')}</li>`; @@ -132,9 +130,9 @@ const Filters = { insertAction: function(parentNode, replaceNode) { const form = document.forms["filter_new_action_form"]; - if (form.action_id.value == 7) { + if (form.action_id.value === '7') { form.action_param.value = form.action_param_label.value; - } else if (form.action_id.value == 9) { + } else if (form.action_id.value === '9') { form.action_param.value = form.action_param_plugin.value; } @@ -254,11 +252,11 @@ const Filters = { dijit.byId("filterDlg_actionParamPlugin").domNode.hide(); // if selected action supports parameters, enable params field - if (action == dialog.ACTION_LABEL) { + if (action === dialog.ACTION_LABEL) { dijit.byId("filterDlg_actionParamLabel").domNode.show(); - } else if (action == dialog.ACTION_PLUGIN) { + } else if (action === dialog.ACTION_PLUGIN) { dijit.byId("filterDlg_actionParamPlugin").domNode.show(); - } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) { + } else if (dialog.PARAM_ACTIONS.indexOf(action) !== -1) { dijit.byId("filterDlg_actionParam").domNode.show(); } }, @@ -531,7 +529,7 @@ const Filters = { // `selectedText` is always empty at this point (tested by selecting some article text). const selectedText = App.getSelectedText(); - if (selectedText != "") { + if (selectedText !== '') { const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) : Feeds.getActive(); const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1}; diff --git a/js/FeedStoreModel.js b/js/FeedStoreModel.js index befc441af..ef43357d0 100644 --- a/js/FeedStoreModel.js +++ b/js/FeedStoreModel.js @@ -1,4 +1,4 @@ -/* global define, dijit */ +/* global define */ define(["dojo/_base/declare", "dijit/tree/ForestStoreModel"], function (declare) { @@ -56,7 +56,7 @@ define(["dojo/_base/declare", "dijit/tree/ForestStoreModel"], function (declare) }, hasCats: function () { if (this.store && this.store._itemsByIdentity) - return this.store._itemsByIdentity['CAT:-1'] != undefined; + return this.store._itemsByIdentity['CAT:-1'] !== undefined; else return false; }, diff --git a/js/FeedTree.js b/js/FeedTree.js index 683205579..01755e7b4 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global __, dojo, dijit, define, App, Feeds, CommonDialogs */ +/* global __, define, App, Feeds, CommonDialogs */ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/cookie", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct, array, cookie) { @@ -26,7 +25,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co // var oreo = cookie(this.cookieName); let oreo = localStorage.getItem(this.cookieName); // migrate old data if nothing in localStorage - if (oreo == null || oreo === '') { + if (oreo === null || oreo === '') { oreo = cookie(this.cookieName); cookie(this.cookieName, null, { expires: -1 }); } @@ -50,7 +49,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co let iconNode; if (iconName) { - if (iconName.indexOf("/") == -1) { + if (iconName.indexOf("/") === -1) { iconNode = dojo.create("i", { className: "material-icons icon icon-" + iconName, innerHTML: iconName }); } else { iconNode = dojo.create('img', { className: 'icon' }); @@ -156,7 +155,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co domConstruct.place(tnode.loadingNode, tnode.expandoNode, 'only'); } - if (id.match("CAT:") && bare_id == -1) { + if (id.match("CAT:") && bare_id === -1) { const menu = new dijit.Menu(); menu.row_id = bare_id; @@ -205,33 +204,36 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co } }, getTooltip: function (item) { - return [item.updated, item.error].filter((x) => x && x != "").join(" - "); + // TODO: item.error is `[""]` for feeds. Need to look into what's happening on the frontend to cause that-- the backend sends a string. + // For now, just adding a check for `[""]`. + return [item.updated, item.error].filter((x) => x && x !== '' && !(Array.isArray(x) && x.length === 1 && x[0] === '')).join(' - '); }, getIconClass: function (item, opened) { - // eslint-disable-next-line no-nested-ternary return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feed-icon"; }, - getLabelClass: function (item/* , opened */) { + getLabelClass: function (item /*, opened */) { return (item.unread <= 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread"; }, - getRowClass: function (item/*, opened */) { + getRowClass: function (item /*, opened */) { let rc = "dijitTreeRow dijitTreeRowFlex"; - const is_cat = String(item.id).indexOf('CAT:') != -1; + const is_cat = String(item.id).indexOf('CAT:') !== -1; if (is_cat) rc += " Is_Cat"; else rc += " Is_Feed"; - if (!is_cat && item.error != '') rc += " Error"; + // TODO: item.error is `[""]` for feeds. Need to look into what's happening on the frontend to cause that-- the backend sends a string. + // For now, just adding a check for `[""]`. + if (!is_cat && item.error !== '' && !(Array.isArray(item.error) && item.error.length === 1 && item.error[0] === '')) rc += ' Error'; if (item.unread > 0) rc += " Unread"; if (item.auxcounter > 0) rc += " Has_Aux"; if (item.markedcounter > 0) rc += " Has_Marked"; if (item.publishedcounter > 0) rc += " Has_Published"; if (item.updates_disabled > 0) rc += " UpdatesDisabled"; - if (item.bare_id >= App.LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id == Feeds.FEED_ARCHIVED && !is_cat) rc += " Special"; - if (item.bare_id == Feeds.CATEGORY_SPECIAL && is_cat) rc += " AlwaysVisible"; + if (item.bare_id >= App.LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id === Feeds.FEED_ARCHIVED && !is_cat) rc += " Special"; + if (item.bare_id === Feeds.CATEGORY_SPECIAL && is_cat) rc += " AlwaysVisible"; if (item.bare_id < App.LABEL_BASE_INDEX) rc += " Label"; return rc; @@ -266,7 +268,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co const items = this.model.store._arrayOfTopLevelItems; for (let i = 0; i < items.length; i++) { - if (String(items[i].id) == test_id) { + if (String(items[i].id) === test_id) { this.expandParentNodes(feed, is_cat, parents); } else { this.findNodeParentsAndExpandThem(feed, is_cat, items[i], []); @@ -276,13 +278,13 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co parents.push(root); for (let i = 0; i < root.items.length; i++) { - if (String(root.items[i].id) == test_id) { + if (String(root.items[i].id) === test_id) { this.expandParentNodes(feed, is_cat, parents); } else { this.findNodeParentsAndExpandThem(feed, is_cat, root.items[i], parents.slice(0)); } } - } else if (String(root.id) == test_id) { + } else if (String(root.id) === test_id) { this.expandParentNodes(feed, is_cat, parents.slice(0)); } } catch (e) { @@ -423,7 +425,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co const items = this.model.store._arrayOfAllItems; const start = items.indexOf(treeItem); - if (start != -1) { + if (start !== -1) { let item = this._nextTreeItemFromIndex(start, unread_only); // let's try again from the top @@ -469,7 +471,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co const items = this.model.store._arrayOfAllItems; const start = items.indexOf(treeItem); - if (start != -1) { + if (start !== -1) { let item = this._prevTreeItemFromIndex(start, unread_only); // wrap from the bottom @@ -490,7 +492,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co _itemsByIdentity["FEED:" + feed])[0]. getParent().item.bare_id[0]; - } catch (e) { + } catch { return false; } }, diff --git a/js/Feeds.js b/js/Feeds.js index 71d9c29d4..790b64dd4 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -1,6 +1,6 @@ 'use strict' -/* global __, App, Headlines, xhr, dojo, dijit, fox, PluginHost, Notify, fox */ +/* global __, App, Headlines, xhr, fox, PluginHost, Notify, fox */ const Feeds = { FEED_ARCHIVED: 0, @@ -31,7 +31,7 @@ const Feeds = { entries.forEach((entry) => { //console.log('feeds',entry.target, entry.intersectionRatio); - if (entry.intersectionRatio == 0) + if (entry.intersectionRatio === 0) Feeds.onHide(entry); else Feeds.onShow(entry); @@ -50,7 +50,7 @@ const Feeds = { // If number of properties is different, // objects are not equivalent - if (aProps.length != bProps.length) { + if (aProps.length !== bProps.length) { return false; } @@ -87,13 +87,13 @@ const Feeds = { const ts = elems[l].ts; const updated = elems[l].updated; - if (id == "global-unread") { + if (id === "global-unread") { App.global_unread = ctr; App.updateTitle(); continue; } - if (id == "subscribed-feeds") { + if (id === "subscribed-feeds") { /* feeds_found = ctr; */ continue; } @@ -102,12 +102,14 @@ const Feeds = { (kind == "cat")) { }*/ - this.setUnread(id, (kind == "cat"), ctr); - this.setValue(id, (kind == "cat"), 'auxcounter', parseInt(elems[l].auxcounter)); - this.setValue(id, (kind == "cat"), 'markedcounter', parseInt(elems[l].markedcounter)); - this.setValue(id, (kind == "cat"), 'publishedcounter', parseInt(elems[l].publishedcounter)); + const is_cat = (kind === 'cat'); - if (kind != "cat") { + this.setUnread(id, is_cat, ctr); + this.setValue(id, is_cat, 'auxcounter', parseInt(elems[l].auxcounter)); + this.setValue(id, is_cat, 'markedcounter', parseInt(elems[l].markedcounter)); + this.setValue(id, is_cat, 'publishedcounter', parseInt(elems[l].publishedcounter)); + + if (!is_cat) { this.setValue(id, false, 'error', error); this.setValue(id, false, 'updated', updated); @@ -130,7 +132,7 @@ const Feeds = { PluginHost.run(PluginHost.HOOK_COUNTERS_PROCESSED, elems); }, reloadCurrent: function(method) { - if (this.getActive() != undefined) { + if (this.getActive() !== undefined) { console.log("reloadCurrent", this.getActive(), this.activeIsCat(), method); this.open({feed: this.getActive(), is_cat: this.activeIsCat(), method: method}); @@ -274,7 +276,7 @@ const Feeds = { if (hash.query) this._search_query = {query: hash.query, search_language: hash.search_language}; - if (hash.f != undefined) { + if (hash.f !== undefined) { this.open({feed: parseInt(hash.f), is_cat: parseInt(hash.c)}); } else { this.openDefaultFeed(); @@ -332,6 +334,10 @@ const Feeds = { setActive: function(id, is_cat) { console.log('setActive', id, is_cat); + // id might be a tag string, so check if we have something int-ish + if (Number.isInteger(Number(id))) + id = parseInt(id); + window.requestIdleCallback(() => { App.Hash.set({ f: id, @@ -389,7 +395,7 @@ const Feeds = { // this is used to quickly switch between feeds, sets active but xhr is on a timeout const delayed = params.delayed || false; - if (offset != 0) { + if (offset !== 0) { if (this.infscroll_in_progress) return; @@ -419,9 +425,9 @@ const Feeds = { query = Object.assign(query, this._search_query); } - if (offset != 0) { + if (offset !== 0) { query.skip = offset; - } else if (!is_cat && feed == this.getActive() && !params.method) { + } else if (!is_cat && feed === this.getActive() && !params.method) { query.m = "ForceUpdate"; } @@ -450,7 +456,7 @@ const Feeds = { catchupAll: function() { const str = __("Mark all articles as read?"); - if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(str)) { + if (App.getInitParam("confirm_feed_catchup") !== 1 || confirm(str)) { Notify.progress("Marking all feeds as read..."); @@ -509,7 +515,7 @@ const Feeds = { if (next_feed !== false) { this.open({feed: next_feed, is_cat: next_is_cat}); } - } else if (feed == this.getActive() && is_cat == this.activeIsCat()) { + } else if (feed === this.getActive() && is_cat === this.activeIsCat()) { this.reloadCurrent(); } @@ -524,7 +530,7 @@ const Feeds = { const str = __("Mark all articles in %s as read?").replace("%s", title); - if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(str)) { + if (App.getInitParam("confirm_feed_catchup") !== 1 || confirm(str)) { const rows = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread][data-orig-feed-id='" + id + "']"); @@ -540,7 +546,7 @@ const Feeds = { if (tree && tree.model) return tree.model.getFeedUnread(feed, is_cat); - } catch (e) { + } catch { // } @@ -553,7 +559,7 @@ const Feeds = { if (tree && tree.model) return tree.getFeedCategory(feed); - } catch (e) { + } catch { // } @@ -580,7 +586,7 @@ const Feeds = { if (tree && tree.model) return tree.model.setFeedValue(feed, is_cat, key, value); - } catch (e) { + } catch { // } }, @@ -591,7 +597,7 @@ const Feeds = { if (tree && tree.model) return tree.model.getFeedValue(feed, is_cat, key); - } catch (e) { + } catch { // } return ''; diff --git a/js/Headlines.js b/js/Headlines.js index 74b8ca00d..7ce1e63ba 100755 --- a/js/Headlines.js +++ b/js/Headlines.js @@ -1,7 +1,7 @@ 'use strict'; /* global __, ngettext, Article, App */ -/* global dojo, dijit, PluginHost, Notify, xhr, Feeds */ +/* global PluginHost, Notify, xhr, Feeds */ /* global CommonDialogs */ const Headlines = { @@ -16,7 +16,7 @@ const Headlines = { default_move_on_expand: true, line_scroll_offset: 120, /* px */ sticky_header_observer: new IntersectionObserver( - (entries, observer) => { + (entries) => { entries.forEach((entry) => { const header = entry.target.closest('.cdm').querySelector(".header"); @@ -32,7 +32,7 @@ const Headlines = { {threshold: [0, 1], root: document.querySelector("#headlines-frame")} ), sticky_content_observer: new IntersectionObserver( - (entries, observer) => { + (entries) => { entries.forEach((entry) => { const header = entry.target.closest('.cdm').querySelector(".header"); @@ -44,7 +44,7 @@ const Headlines = { {threshold: [0, 1], root: document.querySelector("#headlines-frame")} ), unpack_observer: new IntersectionObserver( - (entries, observer) => { + (entries) => { entries.forEach((entry) => { if (entry.intersectionRatio > 0) Article.unpack(entry.target); @@ -56,10 +56,10 @@ const Headlines = { const modified = []; mutations.forEach((m) => { - if (m.type == 'attributes' && ['class', 'data-score'].indexOf(m.attributeName) != -1) { + if (m.type === 'attributes' && ['class', 'data-score'].indexOf(m.attributeName) !== -1) { const row = m.target; - const id = row.getAttribute("data-article-id"); + const id = parseInt(row.getAttribute('data-article-id')); if (Headlines.headlines[id]) { const hl = Headlines.headlines[id]; @@ -105,22 +105,22 @@ const Headlines = { }; modified.forEach(function (m) { - if (m.old.marked != m.new.marked) + if (m.old.marked !== m.new.marked) ops.tmark.push(m.id); - if (m.old.published != m.new.published) + if (m.old.published !== m.new.published) ops.tpub.push(m.id); - if (m.old.unread != m.new.unread) + if (m.old.unread !== m.new.unread) m.new.unread ? ops.unread.push(m.id) : ops.read.push(m.id); - if (m.old.selected != m.new.selected) + if (m.old.selected !== m.new.selected) m.new.selected ? ops.select.push(m.row) : ops.deselect.push(m.row); - if (m.old.active != m.new.active) + if (m.old.active !== m.new.active) m.new.active ? ops.activate.push(m.row) : ops.deactivate.push(m.row); - if (m.old.score != m.new.score) { + if (m.old.score !== m.new.score) { const score = m.new.score; ops.rescore[score] = ops.rescore[score] || []; @@ -158,25 +158,25 @@ const Headlines = { const promises = []; - if (ops.tmark.length != 0) + if (ops.tmark.length !== 0) promises.push(xhr.post("backend.php", {op: "RPC", method: "markSelected", "ids[]": ops.tmark, cmode: 2})); - if (ops.tpub.length != 0) + if (ops.tpub.length !== 0) promises.push(xhr.post("backend.php", {op: "RPC", method: "publishSelected", "ids[]": ops.tpub, cmode: 2})); - if (ops.read.length != 0) + if (ops.read.length !== 0) promises.push(xhr.post("backend.php", {op: "RPC", method: "catchupSelected", "ids[]": ops.read, cmode: 0})); - if (ops.unread.length != 0) + if (ops.unread.length !== 0) promises.push(xhr.post("backend.php", {op: "RPC", method: "catchupSelected", "ids[]": ops.unread, cmode: 1})); const scores = Object.keys(ops.rescore); - if (scores.length != 0) { + if (scores.length !== 0) { scores.forEach((score) => { promises.push(xhr.post("backend.php", {op: "Article", method: "setScore", "ids[]": ops.rescore[score], score: score})); @@ -228,7 +228,6 @@ const Headlines = { } else if (event.ctrlKey) { Headlines.select('invert', id); } else { - // eslint-disable-next-line no-lonely-if if (App.isCombinedMode()) { if (event.altKey && !in_body) { @@ -236,7 +235,7 @@ const Headlines = { Article.openInNewWindow(id); Headlines.toggleUnread(id, 0); - } else if (Article.getActive() != id) { + } else if (Article.getActive() !== id) { Headlines.select('none'); @@ -268,7 +267,6 @@ const Headlines = { return in_body; } else { - // eslint-disable-next-line no-lonely-if if (event.altKey) { Article.openInNewWindow(id); Headlines.toggleUnread(id, 0); @@ -309,7 +307,7 @@ const Headlines = { offset = unread_in_buffer; break; case "adaptive": - if (!(Feeds.getActive() == Feeds.FEED_STARRED && !Feeds.activeIsCat())) + if (!(Feeds.getActive() === Feeds.FEED_STARRED && !Feeds.activeIsCat())) offset = num_unread > 0 ? unread_in_buffer : num_all; break; } @@ -328,7 +326,7 @@ const Headlines = { const row = rows[i]; if (this.isChildVisible(row)) { - return row.getAttribute("data-article-id"); + return parseInt(row.getAttribute('data-article-id')); } } }, @@ -352,7 +350,8 @@ const Headlines = { const last_row = hsp.previousSibling; // invoke lazy load if last article in buffer is nearly visible OR is active - if (Article.getActive() == last_row.getAttribute("data-article-id") || last_row.offsetTop - 250 <= container.scrollTop + container.offsetHeight) { + if (Article.getActive() === parseInt(last_row.getAttribute('data-article-id')) + || last_row.offsetTop - 250 <= container.scrollTop + container.offsetHeight) { hsp.innerHTML = `<span class='text-muted text-small text-center'><img class="icon-three-dots" src="${App.getInitParam('icon_three_dots')}"> ${__("Loading, please wait...")}</span>`; Headlines.loadMore(); @@ -417,7 +416,7 @@ const Headlines = { Headlines.setCommonClasses(this.headlines.filter((h) => h.id).length); App.findAll("#headlines-frame > div[id*=RROW]").forEach((row) => { - const id = row.getAttribute("data-article-id"); + const id = parseInt(row.getAttribute('data-article-id')); const hl = this.headlines[id]; if (hl) { @@ -466,7 +465,7 @@ const Headlines = { if (hl.unread) row_class += " Unread"; if (headlines.vfeed_group_enabled) row_class += " vgrlf"; - if (headlines.vfeed_group_enabled && hl.feed_title && this.vgroup_last_feed != hl.feed_id) { + if (headlines.vfeed_group_enabled && hl.feed_title && this.vgroup_last_feed !== hl.feed_id) { const vgrhdr = `<div data-feed-id='${hl.feed_id}' class='feed-title'> <div class="pull-right icon-feed" title="${App.escapeHtml(hl.feed_title)}" onclick="Feeds.open({feed:${hl.feed_id}})">${Feeds.renderIcon(hl.feed_id, hl.has_icon)}</div> @@ -635,7 +634,7 @@ const Headlines = { target.destroyDescendants(); - if (tb && typeof tb == 'object') { + if (tb && typeof tb === 'object') { target.attr('innerHTML', ` <span class='left'> @@ -672,7 +671,7 @@ const Headlines = { <option></option> <option value='headlines_catchupSelection'>${__('Mark as read')}</option> <option value='article_selectionSetScore'>${__('Set score')}</option> - ${tb.plugin_menu_items != '' ? + ${tb.plugin_menu_items !== '' ? ` <option></option> ${tb.plugin_menu_items} @@ -747,7 +746,7 @@ const Headlines = { feed_id = reply['headlines']['id']; Feeds.last_search_query = reply['headlines']['search_query']; - if (feed_id != Feeds.FEED_ERROR && (feed_id != Feeds.getActive() || is_cat != Feeds.activeIsCat())) + if (feed_id !== Feeds.FEED_ERROR && (feed_id !== Feeds.getActive() || is_cat !== Feeds.activeIsCat())) return; const headlines_count = reply['headlines-info']['count']; @@ -758,7 +757,7 @@ const Headlines = { console.log('received', headlines_count, 'headlines'); if (!append) { - Feeds.infscroll_disabled = parseInt(headlines_count) != 30; + Feeds.infscroll_disabled = parseInt(headlines_count) !== 30; console.log('infscroll_disabled=', Feeds.infscroll_disabled); // also called in renderAgain() after view mode switch @@ -790,7 +789,7 @@ const Headlines = { Headlines.renderToolbar(reply['headlines']); - if (typeof reply['headlines']['content'] == 'string') { + if (typeof reply['headlines']['content'] === 'string') { App.byId("headlines-frame").innerHTML = reply['headlines']['content']; } else { App.byId("headlines-frame").innerHTML = ''; @@ -831,7 +830,7 @@ const Headlines = { Headlines.updateCurrentUnread(); - } else if (headlines_count > 0 && feed_id == Feeds.getActive() && is_cat == Feeds.activeIsCat()) { + } else if (headlines_count > 0 && feed_id === Feeds.getActive() && is_cat === Feeds.activeIsCat()) { const c = dijit.byId("headlines-frame"); let hsp = App.byId("headlines-spacer"); @@ -841,7 +840,7 @@ const Headlines = { let headlines_appended = 0; - if (typeof reply['headlines']['content'] == 'string') { + if (typeof reply['headlines']['content'] === 'string') { App.byId("headlines-frame").innerHTML = reply['headlines']['content']; } else { for (let i = 0; i < reply['headlines']['content'].length; i++) { @@ -856,7 +855,7 @@ const Headlines = { } } - Feeds.infscroll_disabled = headlines_appended == 0; + Feeds.infscroll_disabled = headlines_appended === 0; console.log('appended', headlines_appended, 'headlines, infscroll_disabled=', Feeds.infscroll_disabled); @@ -931,7 +930,7 @@ const Headlines = { const toolbar = dijit.byId("toolbar-main"); let order_by = toolbar.getValues().order_by; - if (order_by != "date_reverse") + if (order_by !== "date_reverse") order_by = "date_reverse"; else order_by = App.getInitParam("default_view_order_by"); @@ -939,11 +938,11 @@ const Headlines = { toolbar.setValues({order_by: order_by}); }, selectionToggleUnread: function (params = {}) { - const cmode = params.cmode != undefined ? params.cmode : 2; + const cmode = params.cmode !== undefined ? params.cmode : 2; const no_error = params.no_error || false; const ids = params.ids || Headlines.getSelected(); - if (ids.length == 0) { + if (ids.length === 0) { if (!no_error) alert(__("No articles selected.")); @@ -970,7 +969,7 @@ const Headlines = { selectionToggleMarked: function (ids) { ids = ids || Headlines.getSelected(); - if (ids.length == 0) { + if (ids.length === 0) { alert(__("No articles selected.")); return; } @@ -982,7 +981,7 @@ const Headlines = { selectionTogglePublished: function (ids) { ids = ids || Headlines.getSelected(); - if (ids.length == 0) { + if (ids.length === 0) { alert(__("No articles selected.")); return; } @@ -1022,13 +1021,13 @@ const Headlines = { const rows = Headlines.getLoaded(); for (let i = 0; i < rows.length; i++) { - if (rows[i] == current_id) { + if (rows[i] === current_id) { // Account for adjacent identical article ids. if (i > 0) prev_id = rows[i - 1]; for (let j = i + 1; j < rows.length; j++) { - if (rows[j] != current_id) { + if (rows[j] !== current_id) { next_id = rows[j]; break; } @@ -1059,7 +1058,7 @@ const Headlines = { const next = row.nextSibling; // hsp has half-screen height in auto catchup mode therefore we use its first child (normally A element) - if (next && Element.visible(next) && next.id == "headlines-spacer" && next.firstChild) { + if (next && Element.visible(next) && next.id === "headlines-spacer" && next.firstChild) { const offset = App.byId("headlines-spacer").offsetTop - App.byId("headlines-frame").offsetHeight + next.firstChild.offsetHeight; // don't jump back either @@ -1107,7 +1106,7 @@ const Headlines = { const row = App.byId(`RROW-${id}`); if (row) { - if (typeof cmode == "undefined") cmode = 2; + if (typeof cmode === "undefined") cmode = 2; switch (cmode) { case 0: @@ -1125,7 +1124,7 @@ const Headlines = { selectionRemoveLabel: function (id, ids) { if (!ids) ids = Headlines.getSelected(); - if (ids.length == 0) { + if (ids.length === 0) { alert(__("No articles selected.")); return; } @@ -1142,7 +1141,7 @@ const Headlines = { selectionAssignLabel: function (id, ids) { if (!ids) ids = Headlines.getSelected(); - if (ids.length == 0) { + if (ids.length === 0) { alert(__("No articles selected.")); return; } @@ -1159,7 +1158,7 @@ const Headlines = { deleteSelection: function () { const rows = Headlines.getSelected(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No articles selected.")); return; } @@ -1167,7 +1166,7 @@ const Headlines = { const fn = Feeds.getName(Feeds.getActive(), Feeds.activeIsCat()); let str; - if (Feeds.getActive() != 0) { + if (Feeds.getActive() !== 0) { str = ngettext("Delete %d selected article in %s?", "Delete %d selected articles in %s?", rows.length); } else { str = ngettext("Delete %d selected article?", "Delete %d selected articles?", rows.length); @@ -1191,7 +1190,7 @@ const Headlines = { App.findAll("#headlines-frame > div[id*=RROW][class*=Selected]").forEach( function (child) { - rv.push(child.getAttribute("data-article-id")); + rv.push(parseInt(child.getAttribute('data-article-id'))); }); // consider active article a honorary member of selected articles @@ -1207,7 +1206,7 @@ const Headlines = { children.forEach(function (child) { if (Element.visible(child)) { - rv.push(child.getAttribute("data-article-id")); + rv.push(parseInt(child.getAttribute('data-article-id'))); } }); @@ -1229,7 +1228,7 @@ const Headlines = { } }, getRange: function (start, stop) { - if (start == stop) + if (start === stop) return [start]; const rows = App.findAll("#headlines-frame > div[id*=RROW]"); @@ -1238,9 +1237,9 @@ const Headlines = { for (let i = 0; i < rows.length; i++) { const row = rows[i]; - const id = row.getAttribute('data-article-id'); + const id = parseInt(row.getAttribute('data-article-id')); - if (id == start || id == stop) { + if (id === start || id === stop) { if (!collecting) { collecting = true; } else { @@ -1296,7 +1295,7 @@ const Headlines = { catchupSelection: function () { const rows = Headlines.getSelected(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No articles selected.")); return; } @@ -1329,7 +1328,7 @@ const Headlines = { if (!below) { for (let i = 0; i < visible_ids.length; i++) { - if (visible_ids[i] != id) { + if (visible_ids[i] !== id) { const e = App.byId(`RROW-${visible_ids[i]}`); if (e && e.hasClassName("Unread")) { @@ -1341,7 +1340,7 @@ const Headlines = { } } else { for (let i = visible_ids.length - 1; i >= 0; i--) { - if (visible_ids[i] != id) { + if (visible_ids[i] !== id) { const e = App.byId(`RROW-${visible_ids[i]}`); if (e && e.hasClassName("Unread")) { @@ -1353,12 +1352,12 @@ const Headlines = { } } - if (ids_to_mark.length == 0) { + if (ids_to_mark.length === 0) { alert(__("No articles found to mark")); } else { const msg = ngettext("Mark %d article as read?", "Mark %d articles as read?", ids_to_mark.length).replace("%d", ids_to_mark.length); - if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) { + if (App.getInitParam("confirm_feed_catchup") !== 1 || confirm(msg)) { for (let i = 0; i < ids_to_mark.length; i++) { const e = App.byId(`RROW-${ids_to_mark[i]}`); @@ -1417,14 +1416,16 @@ const Headlines = { menu.addChild(new dijit.MenuItem({ label: __("Open original article"), onClick: function (/* event */) { - Article.openInNewWindow(this.getParent().currentTarget.getAttribute("data-article-id")); + const id = parseInt(this.getParent().currentTarget.getAttribute('data-article-id')); + Article.openInNewWindow(id); } })); menu.addChild(new dijit.MenuItem({ label: __("Display article URL"), onClick: function (/* event */) { - Article.displayUrl(this.getParent().currentTarget.getAttribute("data-article-id")); + const id = parseInt(this.getParent().currentTarget.getAttribute('data-article-id')); + Article.displayUrl(id); } })); @@ -1433,11 +1434,10 @@ const Headlines = { menu.addChild(new dijit.MenuItem({ label: __("Toggle unread"), onClick: function () { + const id = parseInt(this.getParent().currentTarget.getAttribute('data-article-id')); let ids = Headlines.getSelected(); - // cast to string - const id = (this.getParent().currentTarget.getAttribute("data-article-id")) + ""; - ids = ids.length != 0 && ids.indexOf(id) != -1 ? ids : [id]; + ids = ids.includes(id) ? ids : [id]; Headlines.selectionToggleUnread({ids: ids, no_error: 1}); } @@ -1446,10 +1446,10 @@ const Headlines = { menu.addChild(new dijit.MenuItem({ label: __("Toggle starred"), onClick: function () { + const id = parseInt(this.getParent().currentTarget.getAttribute('data-article-id')); + let ids = Headlines.getSelected(); - // cast to string - const id = (this.getParent().currentTarget.getAttribute("data-article-id")) + ""; - ids = ids.length != 0 && ids.indexOf(id) != -1 ? ids : [id]; + ids = ids.includes(id) ? ids : [id]; Headlines.selectionToggleMarked(ids); } @@ -1458,10 +1458,10 @@ const Headlines = { menu.addChild(new dijit.MenuItem({ label: __("Toggle published"), onClick: function () { + const id = parseInt(this.getParent().currentTarget.getAttribute('data-article-id')); + let ids = Headlines.getSelected(); - // cast to string - const id = (this.getParent().currentTarget.getAttribute("data-article-id")) + ""; - ids = ids.length != 0 && ids.indexOf(id) != -1 ? ids : [id]; + ids = ids.includes(id) ? ids : [id]; Headlines.selectionTogglePublished(ids); } @@ -1472,14 +1472,14 @@ const Headlines = { menu.addChild(new dijit.MenuItem({ label: __("Mark above as read"), onClick: function () { - Headlines.catchupRelativeTo(0, this.getParent().currentTarget.getAttribute("data-article-id")); + Headlines.catchupRelativeTo(0, parseInt(this.getParent().currentTarget.getAttribute('data-article-id'))); } })); menu.addChild(new dijit.MenuItem({ label: __("Mark below as read"), onClick: function () { - Headlines.catchupRelativeTo(1, this.getParent().currentTarget.getAttribute("data-article-id")); + Headlines.catchupRelativeTo(1, parseInt(this.getParent().currentTarget.getAttribute('data-article-id'))); } })); @@ -1501,12 +1501,10 @@ const Headlines = { label: name, labelId: bare_id, onClick: function () { + const id = parseInt(this.getParent().ownerMenu.currentTarget.getAttribute('data-article-id')); let ids = Headlines.getSelected(); - // cast to string - const id = (this.getParent().ownerMenu.currentTarget.getAttribute("data-article-id")) + ""; - - ids = ids.length != 0 && ids.indexOf(id) != -1 ? ids : [id]; + ids = ids.includes(id) ? ids : [id]; Headlines.selectionAssignLabel(this.labelId, ids); } @@ -1516,11 +1514,10 @@ const Headlines = { label: name, labelId: bare_id, onClick: function () { - let ids = Headlines.getSelected(); - // cast to string - const id = (this.getParent().ownerMenu.currentTarget.getAttribute("data-article-id")) + ""; + const id = parseInt(this.getParent().ownerMenu.currentTarget.getAttribute('data-article-id')); - ids = ids.length != 0 && ids.indexOf(id) != -1 ? ids : [id]; + let ids = Headlines.getSelected(); + ids = ids.includes(id) ? ids : [id]; Headlines.selectionRemoveLabel(this.labelId, ids); } diff --git a/js/PluginHost.js b/js/PluginHost.js index 513429e4a..e770c7050 100644 --- a/js/PluginHost.js +++ b/js/PluginHost.js @@ -24,7 +24,7 @@ const PluginHost = { HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2: 19, hooks: [], register: function (name, callback) { - if (typeof(this.hooks[name]) == 'undefined') + if (typeof(this.hooks[name]) === 'undefined') this.hooks[name] = []; this.hooks[name].push(callback); @@ -32,7 +32,7 @@ const PluginHost = { run: function (name, args) { //console.warn('PluginHost.run', name); - if (typeof(this.hooks[name]) != 'undefined') + if (typeof(this.hooks[name]) !== 'undefined') for (let i = 0; i < this.hooks[name].length; i++) { this.hooks[name][i](args); } @@ -40,9 +40,9 @@ const PluginHost = { run_until: function (name, check, ...args) { //console.warn('PluginHost.run_until', name, check, args); - if (typeof(this.hooks[name]) != 'undefined') + if (typeof(this.hooks[name]) !== 'undefined') for (let i = 0; i < this.hooks[name].length; i++) { - if (this.hooks[name][i](args) == check) + if (this.hooks[name][i](args) === check) return true; } @@ -50,7 +50,7 @@ const PluginHost = { }, unregister: function (name, callback) { for (let i = 0; i < this.hooks[name].length; i++) - if (this.hooks[name][i] == callback) + if (this.hooks[name][i] === callback) this.hooks[name].splice(i, 1); } }; diff --git a/js/PrefFeedStore.js b/js/PrefFeedStore.js index 348cbd995..d03169acb 100644 --- a/js/PrefFeedStore.js +++ b/js/PrefFeedStore.js @@ -1,4 +1,4 @@ -/* global define, dojo */ +/* global define */ define(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare) { diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js index f1729382c..4e9cb58a5 100644 --- a/js/PrefFeedTree.js +++ b/js/PrefFeedTree.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global __, lib, dijit, define, dojo, CommonDialogs, Notify, Tables, xhr, fox, App */ +/* global __, lib, define, CommonDialogs, Notify, Tables, xhr, fox, App */ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_base/array", "dojo/cookie"], function (declare, domConstruct, checkBoxTree, array, cookie) { @@ -49,7 +48,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b // var oreo = cookie(this.cookieName); let oreo = localStorage.getItem(this.cookieName); // migrate old data if nothing in localStorage - if (oreo == null || oreo === '') { + if (oreo === null || oreo === '') { oreo = cookie(this.cookieName); cookie(this.cookieName, null, { expires: -1 }); } @@ -133,9 +132,8 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b this.inherited(arguments); this.tree.model.store.save(); }, - // eslint-disable-next-line no-unused-vars - getRowClass: function (item, opened) { - let rc = (!item.error || item.error == '') ? "dijitTreeRow" : + getRowClass: function (item /*, opened */) { + let rc = (!item.error || item.error === '') ? "dijitTreeRow" : "dijitTreeRow Error"; if (item.updates_disabled > 0) rc += " UpdatesDisabled"; @@ -143,8 +141,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b return rc; }, getIconClass: function (item, opened) { - // eslint-disable-next-line no-nested-ternary - return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feed-icon"; + return (!item || this.model.store.getValue(item, 'type') === 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feed-icon"; }, reload: function() { const searchElem = App.byId("feed_search"); @@ -175,11 +172,11 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b //console.log(id + " " + position + " " + source_id); if (source_id.match("FEED:")) { - return ((id.match("CAT:") && position == "over") || - (id.match("FEED:") && position != "over")); + return ((id.match("CAT:") && position === "over") || + (id.match("FEED:") && position !== "over")); } else if (source_id.match("CAT:")) { return ((id.match("CAT:") && !id.match("CAT:0")) || - (id.match("root") && position == "over")); + (id.match("root") && position === "over")); } }, resetFeedOrder: function() { @@ -293,7 +290,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b editSelectedFeed: function() { const rows = this.getSelectedFeeds(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No feeds selected.")); return; } @@ -309,7 +306,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b editMultiple: function() { const rows = this.getSelectedFeeds(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No feeds selected.")); return; } @@ -340,7 +337,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b target.attr('disabled', !checkbox.attr('checked')); console.log(target, target.attr('type')); - if (target.attr('type') == "checkbox") { + if (target.attr('type') === "checkbox") { const label = checkbox.domNode.closest("label"); if (checkbox.attr('checked')) @@ -358,7 +355,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b Object.keys(query).forEach((key) => { const val = query[key]; - if (typeof val == "object" && val.length == 0) + if (typeof val === "object" && val.length === 0) query[key] = ["off"]; }); @@ -384,12 +381,12 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b }, editCategory: function(id, item) { // uncategorized - if (String(item.id) == "CAT:0") + if (String(item.id) === "CAT:0") return; const new_name = prompt(__('Rename category to:'), item.name); - if (new_name && new_name != item.name) { + if (new_name && new_name !== item.name) { Notify.progress("Loading, please wait..."); diff --git a/js/PrefFilterStore.js b/js/PrefFilterStore.js index f1192374a..f4cb8d0dd 100644 --- a/js/PrefFilterStore.js +++ b/js/PrefFilterStore.js @@ -1,4 +1,4 @@ -/* global define, dojo */ +/* global define */ define(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare) { diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js index e63dd5797..4b077259a 100644 --- a/js/PrefFilterTree.js +++ b/js/PrefFilterTree.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global __, define, lib, dijit, dojo, xhr, App, Notify, Filters */ +/* global __, define, lib, xhr, App, Notify, Filters */ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], function (declare, domConstruct) { @@ -29,7 +28,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio if (param) { param = dojo.doc.createElement('ul'); - param.className = (enabled != false) ? 'actions_summary' : 'actions_summary filterDisabled'; + param.className = (enabled !== false) ? 'actions_summary' : 'actions_summary filterDisabled'; param.innerHTML = args.item.param[0]; domConstruct.place(param, tnode.rowNode, 'first'); } @@ -71,10 +70,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio return label; }, getIconClass: function (item, opened) { - // eslint-disable-next-line no-nested-ternary return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible"; }, - getRowClass: function (item, opened) { + getRowClass: function (item /*, opened */) { const enabled = this.model.store.getValue(item, 'enabled'); return enabled ? "dijitTreeRow" : "dijitTreeRow filterDisabled"; @@ -85,7 +83,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio // disable copying items source.copyState = function() { return false; }; - return position != 'over'; + return position !== 'over'; }, onDndDrop: function() { this.inherited(arguments); @@ -132,7 +130,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio joinSelectedFilters: function() { const rows = this.getSelectedFilters(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No filters selected.")); return; } diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js index cf822d987..cf3f03bf2 100644 --- a/js/PrefHelpers.js +++ b/js/PrefHelpers.js @@ -1,7 +1,6 @@ 'use strict'; -/* eslint-disable no-new */ -/* global __, dijit, dojo, Tables, Notify, xhr, App, fox */ +/* global __, Tables, Notify, xhr, App, fox */ const Helpers = { AppPasswords: { @@ -15,7 +14,7 @@ const Helpers = { removeSelected: function() { const rows = this.getSelected(); - if (rows.length == 0) { + if (rows.length === 0) { alert("No passwords selected."); } else if (confirm(__("Remove selected app passwords?"))) { @@ -131,7 +130,7 @@ const Helpers = { cloneSelected: function() { const sel_rows = this.getSelectedProfiles(); - if (sel_rows.length == 1) { + if (sel_rows.length === 1) { const new_title = prompt(__("Name for cloned profile:")); if (new_title) { @@ -238,7 +237,7 @@ const Helpers = { execute: function () { const sel_rows = this.getSelectedProfiles(); - if (sel_rows.length == 1) { + if (sel_rows.length === 1) { if (confirm(__("Activate selected profile?"))) { Notify.progress("Loading, please wait..."); @@ -386,11 +385,11 @@ const Helpers = { this._list_of_plugins.plugins.forEach((plugin) => { - if (search_tokens.length == 0 || + if (search_tokens.length === 0 || Object.values(plugin).filter((pval) => search_tokens.filter((stoken) => - (pval.toString().indexOf(stoken) != -1 ? stoken : null) - ).length == search_tokens.length).length > 0) { + (pval.toString().indexOf(stoken) !== -1 ? stoken : null) + ).length === search_tokens.length).length > 0) { ++results_rendered; @@ -433,7 +432,7 @@ const Helpers = { } }); - if (results_rendered == 0) { + if (results_rendered === 0) { container.innerHTML += `<li class='text-center text-info'>${__("Could not find any plugins for this search query.")}</li>`; } @@ -456,7 +455,7 @@ const Helpers = { Notify.progress("Loading, please wait..."); xhr.json("backend.php", {op: "Pref_Prefs", method: "uninstallPlugin", plugin: plugin}, (reply) => { - if (reply && reply.status == 1) + if (reply?.status === true) Helpers.Plugins.reload(); else { Notify.error("Plugin uninstallation failed."); @@ -562,11 +561,11 @@ const Helpers = { const is_installed = (dialog.installed_plugins .filter((p) => plugin.topics.map((t) => t.replace(/-/g, "_")).includes(p))).length > 0; - if (search_tokens.length == 0 || + if (search_tokens.length === 0 || Object.values(plugin).filter((pval) => search_tokens.filter((stoken) => - (pval.indexOf(stoken) != -1 ? stoken : null) - ).length == search_tokens.length).length > 0) { + (pval.indexOf(stoken) !== -1 ? stoken : null) + ).length === search_tokens.length).length > 0) { ++results_rendered; @@ -592,7 +591,7 @@ const Helpers = { } }); - if (results_rendered == 0) { + if (results_rendered === 0) { container.innerHTML = `<li class='text-center text-info'>${__("Could not find any plugins for this search query.")}</li>`; } @@ -664,7 +663,7 @@ const Helpers = { container.innerHTML = ""; reply.forEach((p) => { - if (p.rv.git_status == 0) + if (p.rv.git_status === 0) dialog.need_refresh = true; else enable_update_btn = true; @@ -704,7 +703,7 @@ const Helpers = { dialog.attr('title', __("No updates available")); dijit.getEnclosingWidget(dialog.domNode.querySelector(".update-btn")) - .attr('disabled', num_updated == 0); + .attr('disabled', num_updated === 0); } }, @@ -735,7 +734,7 @@ const Helpers = { update_button.domNode.show(); } - if (p.rv.need_update || p.rv.git_status != 0) { + if (p.rv.need_update || p.rv.git_status !== 0) { container.innerHTML += ` <li><h3>${p.plugin}</h3> @@ -787,7 +786,7 @@ const Helpers = { import: function() { const opml_file = App.byId("opml_file"); - if (opml_file.value.length == 0) { + if (opml_file.value.length === 0) { alert(__("Please choose an OPML file first.")); return false; } else { diff --git a/js/PrefLabelTree.js b/js/PrefLabelTree.js index 582e5a9b9..a4540deec 100644 --- a/js/PrefLabelTree.js +++ b/js/PrefLabelTree.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global __, define, lib, dijit, dojo, xhr, Notify, fox, App */ +/* global __, define, lib, xhr, Notify, fox, App */ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/form/DropDownButton"], function (declare, domConstruct) { @@ -19,7 +18,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f const type = this.model.store.getValue(args.item, 'type'); //const bare_id = this.model.store.getValue(args.item, 'bare_id'); - if (type == 'label') { + if (type === 'label') { const label = dojo.doc.createElement('i'); //const fg_color = args.item.fg_color[0]; const bg_color = String(args.item.bg_color); @@ -40,7 +39,6 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f return tnode; }, getIconClass: function (item, opened) { - // eslint-disable-next-line no-nested-ternary return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible"; }, getSelectedLabels: function() { diff --git a/js/PrefUsers.js b/js/PrefUsers.js index e8f4a7489..73e48b52f 100644 --- a/js/PrefUsers.js +++ b/js/PrefUsers.js @@ -1,6 +1,6 @@ 'use strict' -/* global __, xhr, dijit, Notify, Tables, App, fox */ +/* global __, xhr, Notify, Tables, App, fox */ const Users = { reload: function(sort) { @@ -32,7 +32,7 @@ const Users = { edit: function(id) { xhr.json('backend.php', {op: 'Pref_Users', method: 'edit', id: id}, (reply) => { const user = reply.user; - const admin_disabled = (user.id == 1); + const admin_disabled = (user.id === 1); const dialog = new fox.SingleUseDialog({ id: "userEditDlg", @@ -132,7 +132,7 @@ const Users = { resetSelected: function() { const rows = this.getSelection(); - if (rows.length == 0) { + if (rows.length === 0) { alert(__("No users selected.")); return; } diff --git a/js/SingleUseDialog.js b/js/SingleUseDialog.js index 2de6f83ff..a207c0c44 100644 --- a/js/SingleUseDialog.js +++ b/js/SingleUseDialog.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global dijit, define */ +/* global define */ define(["dojo/_base/declare", "dijit/Dialog"], function (declare) { return declare("fox.SingleUseDialog", dijit.Dialog, { create: function(params) { diff --git a/js/Toolbar.js b/js/Toolbar.js index d4993e713..b7c2a0898 100755 --- a/js/Toolbar.js +++ b/js/Toolbar.js @@ -1,4 +1,4 @@ -/* global dijit, define */ +/* global define */ define(["dojo/_base/declare", "dijit/Toolbar"], function (declare) { return declare("fox.Toolbar", dijit.Toolbar, { diff --git a/js/common.js b/js/common.js index 99cf52fa1..48a42b95a 100755 --- a/js/common.js +++ b/js/common.js @@ -1,11 +1,10 @@ 'use strict'; -/* global dijit, App, dojo, __csrf_token */ -/* eslint-disable no-new */ +/* global App, __csrf_token */ /* exported __ */ function __(msg) { - if (typeof App != "undefined") { + if (typeof App !== "undefined") { return App.l10n.__(msg); } else { return msg; @@ -99,59 +98,59 @@ Element.prototype.fadeOut = function() { if ((self.style.opacity -= 0.1) < 0) { self.style.display = "none"; } else { - requestAnimationFrame(fade); + window.requestAnimationFrame(fade); } }()); }; Element.prototype.fadeIn = function(display = undefined){ this.style.opacity = 0; - this.style.display = display == undefined ? "block" : display; + this.style.display = display === undefined ? "block" : display; const self = this; (function fade() { let val = parseFloat(self.style.opacity); if (!((val += 0.1) > 1)) { self.style.opacity = val; - requestAnimationFrame(fade); + window.requestAnimationFrame(fade); } }()); }; Element.prototype.visible = function() { - return window.getComputedStyle(this).display != "none"; //&& this.offsetHeight != 0 && this.offsetWidth != 0; + return window.getComputedStyle(this).display !== "none"; //&& this.offsetHeight !== 0 && this.offsetWidth !== 0; } Element.visible = function(elem) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); return elem.visible(); } Element.show = function(elem) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); return elem.show(); } Element.hide = function(elem) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); return elem.hide(); } Element.toggle = function(elem) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); return elem.toggle(); } Element.hasClassName = function (elem, className) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); return elem.hasClassName(className); @@ -159,7 +158,7 @@ Element.hasClassName = function (elem, className) { Array.prototype.remove = function(s) { for (let i=0; i < this.length; i++) { - if (s == this[i]) this.splice(i, 1); + if (s === this[i]) this.splice(i, 1); } }; @@ -176,14 +175,14 @@ const xhr = { console.log('xhr.post', '>>>', params); return new Promise((resolve, reject) => { - if (typeof __csrf_token != "undefined") + if (typeof __csrf_token !== "undefined") params = {...params, ...{csrf_token: __csrf_token}}; dojo.xhrPost({url: url, postData: dojo.objectToQuery(params), handleAs: "text", error: function(error) { - if (failed != undefined) + if (failed !== undefined) failed(error); reject(error); @@ -191,7 +190,7 @@ const xhr = { load: function(data, ioargs) { console.log('xhr.post', '<<<', ioargs.xhr, (new Date().getTime() - xhr._ts) + " ms"); - if (complete != undefined) + if (typeof complete === 'function') complete(data, ioargs.xhr); resolve(data) @@ -209,7 +208,7 @@ const xhr = { } catch (e) { console.error("xhr.json", e, xhr); - if (failed != undefined) + if (typeof failed === 'function') failed(e); reject(e); @@ -218,21 +217,22 @@ const xhr = { console.log('xhr.json', '<<<', obj, (new Date().getTime() - xhr._ts) + " ms"); - if (obj && typeof App != "undefined") + if (obj && typeof App !== 'undefined') { if (!App.handleRpcJson(obj)) { - if (failed != undefined) + if (typeof failed === 'function') failed(obj); reject(obj); return; } + } - if (complete != undefined) complete(obj); + if (typeof complete === 'function') + complete(obj); resolve(obj); - } - )); + })); } }; @@ -241,7 +241,7 @@ function xhrPost(url, params = {}, complete = undefined) { console.log("xhrPost:", params); return new Promise((resolve, reject) => { - if (typeof __csrf_token != "undefined") + if (typeof __csrf_token !== "undefined") params = {...params, ...{csrf_token: __csrf_token}}; dojo.xhrPost({url: url, @@ -251,7 +251,7 @@ function xhrPost(url, params = {}, complete = undefined) { reject(error); }, load: function(data, ioargs) { - if (complete != undefined) + if (complete !== undefined) complete(ioargs.xhr); resolve(ioargs.xhr) @@ -279,7 +279,7 @@ const Lists = { checked ? row.addClassName("Selected") : row.removeClassName("Selected"); }, select: function(elem, selected) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); elem.querySelectorAll("li").forEach((row) => { @@ -300,7 +300,7 @@ const Lists = { getSelected: function(elem) { const rv = []; - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); elem.querySelectorAll("li").forEach((row) => { @@ -337,7 +337,7 @@ const Tables = { }, select: function(elem, selected) { - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); elem.querySelectorAll("tr").forEach((row) => { @@ -358,7 +358,7 @@ const Tables = { getSelected: function(elem) { const rv = []; - if (typeof elem == "string") + if (typeof elem === "string") elem = document.getElementById(elem); elem.querySelectorAll("tr").forEach((row) => { @@ -394,8 +394,8 @@ const Cookie = { const ca = document.cookie.split(';'); for (let i=0; i < ca.length; i++) { let c = ca[i]; - while (c.charAt(0) == ' ') c = c.substring(1); - if (c.indexOf(name) == 0) return decodeURIComponent(c.substring(name.length, c.length)); + while (c.charAt(0) === ' ') c = c.substring(1); + if (c.indexOf(name) === 0) return decodeURIComponent(c.substring(name.length, c.length)); } return ""; }, @@ -455,7 +455,7 @@ const Notify = { } if (icon) - if (icon.indexOf("data:image") != -1) + if (icon.indexOf("data:image") !== -1) msgfmt = "<img src=\"%s\">".replace("%s", icon) + msgfmt; else msgfmt = "<i class='material-icons icon-notify'>%s</i>".replace("%s", icon) + msgfmt; diff --git a/js/form/ComboButton.js b/js/form/ComboButton.js index 2ad4bf123..98386eead 100755 --- a/js/form/ComboButton.js +++ b/js/form/ComboButton.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global dijit, define */ +/* global define */ define(["dojo/_base/declare", "dijit/form/ComboButton"], function (declare) { return declare("fox.form.ComboButton", dijit.form.ComboButton, { startup: function() { diff --git a/js/form/DropDownButton.js b/js/form/DropDownButton.js index d5ea39726..60d8e86ef 100755 --- a/js/form/DropDownButton.js +++ b/js/form/DropDownButton.js @@ -1,5 +1,4 @@ -/* eslint-disable prefer-rest-params */ -/* global dijit, define */ +/* global define */ define(["dojo/_base/declare", "dijit/form/DropDownButton"], function (declare) { return declare("fox.form.DropDownButton", dijit.form.DropDownButton, { startup: function() { diff --git a/js/form/Select.js b/js/form/Select.js index 0c73cd52c..c44674e2a 100755 --- a/js/form/Select.js +++ b/js/form/Select.js @@ -1,4 +1,3 @@ -/* eslint-disable prefer-rest-params */ /* global define */ // FIXME: there probably is a better, more dojo-like notation for custom data- properties define(["dojo/_base/declare", @@ -15,7 +14,7 @@ define(["dojo/_base/declare", startup: function() { this.inherited(arguments); - if (this.attr('data-dropdown-skip-first') == 'true') { + if (this.attr('data-dropdown-skip-first') === 'true') { aspect.before(this, "_loadChildren", () => { this.options = this.options.splice(1); }); @@ -25,8 +24,8 @@ define(["dojo/_base/declare", onItemClick: function(/*item, menu*/) { // }, - _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ - if (this.attr('data-prevent-value-change') == 'true' && newValue != '') + _setValueAttr: function(/*anything*/ newValue, /*Boolean? priorityChange */){ + if (this.attr('data-prevent-value-change') === 'true' && newValue !== '') return; this.inherited(arguments); diff --git a/js/form/ValidationMultiSelect.js b/js/form/ValidationMultiSelect.js index 4e7263c61..5a7918271 100644 --- a/js/form/ValidationMultiSelect.js +++ b/js/form/ValidationMultiSelect.js @@ -6,12 +6,12 @@ define(["dojo/_base/declare", "dojo/_base/lang", "dijit/form/MultiSelect", ], function(declare, lang, MultiSelect) { return declare('fox.form.ValidationMultiSelect', [MultiSelect], { - constructor: function(params){ + constructor: function(/* params */) { this.constraints = {}; this.baseClass += ' dijitValidationMultiSelect'; }, - validate: function(/*Boolean*/ isFocused){ - if (this.required && this.attr('value').length == 0) + validate: function(/*Boolean isFocused */) { + if (this.required && this.attr('value').length === 0) return false; return true; diff --git a/js/form/ValidationTextArea.js b/js/form/ValidationTextArea.js index c53260f40..a71a490c1 100644 --- a/js/form/ValidationTextArea.js +++ b/js/form/ValidationTextArea.js @@ -1,16 +1,14 @@ // https://stackoverflow.com/questions/19317258/how-to-use-dijit-textarea-validation-dojo-1-9 -/* eslint-disable no-new */ /* global define */ define(["dojo/_base/declare", "dojo/_base/lang", "dijit/form/SimpleTextarea", "dijit/form/ValidationTextBox"], function(declare, lang, SimpleTextarea, ValidationTextBox) { return declare('fox.form.ValidationTextArea', [SimpleTextarea, ValidationTextBox], { - constructor: function(params){ + constructor: function(/* params */) { this.constraints = {}; this.baseClass += ' dijitValidationTextArea'; }, - // eslint-disable-next-line no-template-curly-in-string templateString: "<textarea ${!nameAttrSetting} data-dojo-attach-point='focusNode,containerNode,textbox' autocomplete='off'></textarea>", validator: function(value, constraints) { //console.log(this, value, constraints); @@ -21,7 +19,7 @@ define(["dojo/_base/declare", "dojo/_base/lang", "dijit/form/SimpleTextarea", "d if (this.validregexp) { try { new RegExp("/" + value + "/"); - } catch (e) { + } catch { return false; } } diff --git a/js/prefs.js b/js/prefs.js index 8f4f45700..0fb70f710 100755 --- a/js/prefs.js +++ b/js/prefs.js @@ -63,7 +63,7 @@ require(["dojo/_base/kernel", try { App.init(parser, true); } catch (e) { - if (typeof App != "undefined" && App.Error) + if (typeof App !== "undefined" && App.Error) App.Error.report(e); else alert(e + "\n\n" + e.stack); diff --git a/js/tt-rss.js b/js/tt-rss.js index 10fafc447..2af9d32ff 100644 --- a/js/tt-rss.js +++ b/js/tt-rss.js @@ -1,6 +1,6 @@ 'use strict' -/* global require, App, dojo */ +/* global require, App */ /* exported Plugins */ const Plugins = {}; @@ -61,7 +61,7 @@ require(["dojo/_base/kernel", try { App.init(parser, false); } catch (e) { - if (typeof App != "undefined" && App.Error) + if (typeof App !== "undefined" && App.Error) App.Error.report(e); else alert(e + "\n\n" + e.stack); diff --git a/js/utility.js b/js/utility.js index 2e27c4fe6..0a9b59454 100644 --- a/js/utility.js +++ b/js/utility.js @@ -7,8 +7,9 @@ window.addEventListener("load", function() { apply_night_mode: function (is_night, link) { console.log("night mode changed to", is_night); - const light_theme = typeof __default_light_theme != 'undefined' ? __default_light_theme : 'themes/light.css'; - const dark_theme = typeof __default_dark_theme != 'undefined' ? __default_dark_theme : 'themes/night.css'; + /* global __default_dark_theme, __default_light_theme */ + const light_theme = typeof __default_light_theme !== 'undefined' ? __default_light_theme : 'themes/light.css'; + const dark_theme = typeof __default_dark_theme !== 'undefined' ? __default_dark_theme : 'themes/night.css'; if (link) { const css_override = is_night ? dark_theme : light_theme; @@ -27,7 +28,7 @@ window.addEventListener("load", function() { link.onload = function() { document.querySelector("body").removeClassName("css_loading"); - if (typeof UtilityApp != "undefined") + if (typeof UtilityApp !== "undefined") UtilityApp.init(); }; @@ -35,7 +36,7 @@ window.addEventListener("load", function() { mql.addEventListener("change", () => { UtilityJS.apply_night_mode(mql.matches, link); }); - } catch (e) { + } catch { console.warn("exception while trying to set MQL event listener"); } diff --git a/package-lock.json b/package-lock.json index 3ac0644fd..017cac879 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,9 @@ "name": "tt-rss", "version": "1.0.0", "devDependencies": { + "@stylistic/eslint-plugin": "^5.4.0", "eslint": "^9.37.0", + "globals": "^16.4.0", "gulp": "^5.0.1", "gulp-less": "^5.0.0", "gulp-touch-fd": "^2.0.0", @@ -122,6 +124,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { "version": "9.37.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", @@ -234,6 +249,40 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.4.0.tgz", + "integrity": "sha512-UG8hdElzuBDzIbjG1QDwnYH0MQ73YLXDFHgZzB4Zh/YJfnw8XNsloVtytqzx0I2Qky9THSdpTmi8Vjn/pf/Lew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.0", + "@typescript-eslint/types": "^8.44.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -248,6 +297,20 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz", + "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -1360,9 +1423,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 3eb8d6851..a2d6daefe 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "tt-rss", + "description": "A free, flexible, open-source, web-based news feed (RSS/Atom/other) reader and aggregator.", "version": "1.0.0", - "description": "", + "type": "module", "devDependencies": { + "@stylistic/eslint-plugin": "^5.4.0", "eslint": "^9.37.0", + "globals": "^16.4.0", "gulp": "^5.0.1", "gulp-less": "^5.0.0", "gulp-touch-fd": "^2.0.0", diff --git a/plugins/af_psql_trgm/init.js b/plugins/af_psql_trgm/init.js index f3662a389..e57f11564 100644 --- a/plugins/af_psql_trgm/init.js +++ b/plugins/af_psql_trgm/init.js @@ -1,4 +1,4 @@ -/* global dijit, dojo, Plugins, xhr, __ */ +/* global Plugins, xhr, __ */ Plugins.Psql_Trgm = { showRelated: function (id) { diff --git a/plugins/hotkeys_force_top/init.js b/plugins/hotkeys_force_top/init.js index 8d6280fc9..242d14ecf 100644 --- a/plugins/hotkeys_force_top/init.js +++ b/plugins/hotkeys_force_top/init.js @@ -1,3 +1,5 @@ +/* global Headlines, require */ + require(['dojo/_base/kernel', 'dojo/ready'], function (dojo, ready) { ready(function () { Headlines.default_force_to_top = true; diff --git a/plugins/share/share.js b/plugins/share/share.js index 1be9db682..f27e06678 100644 --- a/plugins/share/share.js +++ b/plugins/share/share.js @@ -1,4 +1,4 @@ -/* global dojo, Plugins, App, Notify, fox, xhr, __ */ +/* global Plugins, App, Notify, fox, xhr, __ */ Plugins.Share = { shareArticle: function(id) { diff --git a/plugins/share/share_prefs.js b/plugins/share/share_prefs.js index d974af618..e2151065f 100644 --- a/plugins/share/share_prefs.js +++ b/plugins/share/share_prefs.js @@ -1,4 +1,4 @@ -/* global Plugins, Notify, xhr, App */ +/* global __, Plugins, Notify, xhr, App */ Plugins.Share = { clearKeys: function() { diff --git a/plugins/shorten_expanded/init.js b/plugins/shorten_expanded/init.js index bc3e35ff6..a89fe8e92 100644 --- a/plugins/shorten_expanded/init.js +++ b/plugins/shorten_expanded/init.js @@ -1,4 +1,4 @@ -/* global Plugins, __, require, PluginHost, App, dojo */ +/* global Plugins, __, require, PluginHost, App */ Plugins.Shorten_Expanded = { threshold: 1.5, // of window height diff --git a/plugins/toggle_sidebar/init.js b/plugins/toggle_sidebar/init.js index 9efb06193..6ac74d3c3 100644 --- a/plugins/toggle_sidebar/init.js +++ b/plugins/toggle_sidebar/init.js @@ -1,3 +1,5 @@ +/* global Plugins, Feeds */ + Plugins.Toggle_Sidebar = { toggle: function() { Feeds.toggle(); |