summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg <supahgreg@users.noreply.github.com>2025-10-13 23:39:24 -0500
committerGitHub <noreply@github.com>2025-10-13 23:39:24 -0500
commit6505cbb592b91556ca25a2bf72ad1d8cb0b3bc2a (patch)
tree8ab133cc17a329ef7d99d152b3f6b4edc3830509
parent0d2b1d601294802286aa26e5486c1c4fee92c05a (diff)
parent8b46ab31a96b6b6129f624719ac33ddf761805f1 (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
-rw-r--r--.eslintrc.js300
-rw-r--r--.github/workflows/javascipt-code-quality.yml4
-rw-r--r--.github/workflows/publish.yml12
-rw-r--r--.github/workflows/validate-sql.yml1
-rw-r--r--eslint.config.js43
-rw-r--r--js/App.js69
-rw-r--r--js/Article.js27
-rw-r--r--js/CommonDialogs.js19
-rw-r--r--js/CommonFilters.js18
-rw-r--r--js/FeedStoreModel.js4
-rwxr-xr-xjs/FeedTree.js40
-rw-r--r--js/Feeds.js50
-rwxr-xr-xjs/Headlines.js151
-rw-r--r--js/PluginHost.js10
-rw-r--r--js/PrefFeedStore.js2
-rw-r--r--js/PrefFeedTree.js31
-rw-r--r--js/PrefFilterStore.js2
-rw-r--r--js/PrefFilterTree.js12
-rw-r--r--js/PrefHelpers.js35
-rw-r--r--js/PrefLabelTree.js6
-rw-r--r--js/PrefUsers.js6
-rw-r--r--js/SingleUseDialog.js3
-rwxr-xr-xjs/Toolbar.js2
-rwxr-xr-xjs/common.js62
-rwxr-xr-xjs/form/ComboButton.js3
-rwxr-xr-xjs/form/DropDownButton.js3
-rwxr-xr-xjs/form/Select.js7
-rw-r--r--js/form/ValidationMultiSelect.js6
-rw-r--r--js/form/ValidationTextArea.js6
-rwxr-xr-xjs/prefs.js2
-rw-r--r--js/tt-rss.js4
-rw-r--r--js/utility.js9
-rw-r--r--package-lock.json69
-rw-r--r--package.json5
-rw-r--r--plugins/af_psql_trgm/init.js2
-rw-r--r--plugins/hotkeys_force_top/init.js2
-rw-r--r--plugins/share/share.js2
-rw-r--r--plugins/share/share_prefs.js2
-rw-r--r--plugins/shorten_expanded/init.js2
-rw-r--r--plugins/toggle_sidebar/init.js2
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 }]
+ }
+ }
+];
diff --git a/js/App.js b/js/App.js
index 33bd81d9a..e305ce998 100644
--- a/js/App.js
+++ b/js/App.js
@@ -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 = {
'/': '&#x2F;',
};
- 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 += "&nbsp;";
// 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();