chore: update transmission-web package (#7003)

* chore: update minor versions

* chore: bump to `style-loader@4`

major version change

* refactor: combine `#mainwin-toolbar:nth-last-child(2)` rule

* refactor: cleanup scss definitions

Notes: `.single-file` is no longer used in code

* chore: bump `esbuild-sass-plugin@3` `esbuild@0.25`

* chore: uninstall unused `stylelint-config-standard`

In fact, it was never used since added to `package.json`.

* chore: bump `stylelint@16` `stylelint-config-sass-guidelines@12`

* chore: bump `eslint@9` `eslint-plugin-sonarjs@1` `eslint-plugin-unicorn@61`

* chore: enable prettier for whole `transmission-web` package

* chore: bump `@primer/stylelint-config@13`

* chore: update minor versions

* build: remove lint config files from CMake dependency

* chore: bump minor versions

* chore: bump `eslint-plugin-sonarjs@3`

* ci: use `actions/setup-node@v4` to install Node.js

So that there's no risk of the OS package manager's Node.js version being too low.

Except in Alpine, which does not work with `actions/setup-node@v4`. Ref: https://github.com/actions/setup-node/issues/387

* chore: replace `lodash.isEqual` with `fast-deep-equal`

* chore: bump minor versions

* chore: re-generate package-lock.json

* chore: fix lint errors
This commit is contained in:
Yat Ho
2025-10-26 01:09:36 +08:00
committed by GitHub
parent 0715897fc8
commit d31e77a494
26 changed files with 4402 additions and 2877 deletions

View File

@@ -76,8 +76,6 @@ jobs:
runs-on: ubuntu-22.04
needs: [ what-to-make ]
if: ${{ needs.what-to-make.outputs.test-style == 'true' }}
env:
NODE_PATH: /usr/lib/nodejs:/usr/share/nodejs
steps:
- name: Show Configuration
run: |
@@ -93,7 +91,11 @@ jobs:
set -ex
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main"
sudo apt-get install -y clang-format-17 npm
sudo apt-get install -y clang-format-17
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Check for style diffs
id: check-for-diffs
working-directory: .
@@ -122,8 +124,6 @@ jobs:
runs-on: ubuntu-22.04
needs: [ what-to-make ]
if: ${{ needs.what-to-make.outputs.make-tests == 'true' }}
env:
NODE_PATH: /usr/lib/nodejs:/usr/share/nodejs
steps:
- name: Show Configuration
run: |
@@ -147,8 +147,7 @@ jobs:
libnatpmp-dev \
libpsl-dev \
libssl-dev \
ninja-build \
npm
ninja-build
- name: Get Source
uses: actions/checkout@v4
with:
@@ -249,8 +248,11 @@ jobs:
libnatpmp-dev \
libpsl-dev \
libssl-dev \
ninja-build \
npm
ninja-build
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Get Source
uses: actions/checkout@v4
with:
@@ -769,8 +771,6 @@ jobs:
needs: [ make-source-tarball, what-to-make ]
if: ${{ needs.what-to-make.outputs.make-cli == 'true' || needs.what-to-make.outputs.make-daemon == 'true' || needs.what-to-make.outputs.make-gtk == 'true' || needs.what-to-make.outputs.make-qt == 'true' || needs.what-to-make.outputs.make-tests == 'true' || needs.what-to-make.outputs.make-utils == 'true' }}
runs-on: ubuntu-22.04
env:
NODE_PATH: /usr/lib/nodejs:/usr/share/nodejs
container:
image: debian:11-slim
steps:
@@ -849,8 +849,6 @@ jobs:
needs: [ make-source-tarball, what-to-make ]
if: ${{ needs.what-to-make.outputs.make-cli == 'true' || needs.what-to-make.outputs.make-daemon == 'true' || needs.what-to-make.outputs.make-gtk == 'true' || needs.what-to-make.outputs.make-qt == 'true' || needs.what-to-make.outputs.make-tests == 'true' || needs.what-to-make.outputs.make-utils == 'true' }}
runs-on: ubuntu-22.04
env:
NODE_PATH: /usr/lib/nodejs:/usr/share/nodejs
container:
image: fedora:39
steps:
@@ -876,10 +874,13 @@ jobs:
libpsl-devel \
miniupnpc-devel \
ninja-build \
npm \
openssl-devel \
pkgconf-pkg-config \
xz
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Get Dependencies (GTK)
if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }}
run: dnf install -y glibmm2.68-devel gtkmm4.0-devel
@@ -952,8 +953,11 @@ jobs:
libnatpmp-dev \
libpsl-dev \
libssl-dev \
ninja-build \
npm
ninja-build
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Get Dependencies (GTK)
if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }}
run: sudo apt-get install -y --no-install-recommends libglibmm-2.4-dev libgtkmm-3.0-dev

View File

@@ -59,11 +59,10 @@ jobs:
steps:
- name: Get source
uses: actions/checkout@v4
- name: Get dependencies
run: |
set -e # abort if any command fails
sudo apt-get update
sudo apt-get install -y npm
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Check for style diffs
id: check-for-diffs
run: |
@@ -127,10 +126,10 @@ jobs:
- name: Show env
run: |
env | sort
- name: Get dependencies
run: |
set -e # abort if any command fails
sudo apt-get install -y npm
- name: Get NPM
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Get source
uses: actions/checkout@v4
with:

View File

@@ -51,7 +51,7 @@ set(GTKMM3_MINIMUM 3.24.0)
set(GTKMM4_MINIMUM 4.11.1)
set(OPENSSL_MINIMUM 1.1.0)
set(MBEDTLS_MINIMUM 1.3)
set(NPM_MINIMUM 8.1.307) # Node.js 14
set(NPM_MINIMUM 10.2.3) # Node.js 20.10 (eslint-plugin-unicorn)
set(PSL_MINIMUM 0.21.1)
set(QT_MINIMUM 5.6)

View File

@@ -1,127 +0,0 @@
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:sonarjs/recommended",
"plugin:unicorn/recommended"
],
"plugins": [
"sonarjs",
"unicorn"
],
"rules": {
"accessor-pairs": "error",
"array-callback-return": "error",
"arrow-spacing": "error",
"block-scoped-var": "error",
"class-methods-use-this": "error",
"consistent-return": "error",
"curly": "error",
"default-case": "error",
"default-case-last": "error",
"default-param-last": "error",
"eqeqeq": "error",
"grouped-accessor-pairs": "error",
"guard-for-in": "error",
"init-declarations": "error",
"no-array-constructor": "error",
"no-caller": "error",
"no-confusing-arrow": "error",
"no-constructor-return": "error",
"no-delete-var": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"no-else-return": "error",
"no-empty-function": "error",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-floating-decimal": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-loss-of-precision": "error",
"no-multi-str": "error",
"no-nested-ternary": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-promise-executor-return": "error",
"no-proto": "error",
"no-redeclare": "error",
"no-restricted-exports": "error",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-properties": "error",
"no-return-assign": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-undef-init": "error",
"no-undefined": "error",
"no-unmodified-loop-condition": "error",
"no-unreachable-loop": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-unused-vars": "error",
"no-use-before-define": "error",
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-escape": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-void": "error",
"no-with": "error",
"object-shorthand": "error",
"prefer-arrow-callback": "error",
"prefer-const": "error",
"prefer-destructuring": "error",
"prefer-exponentiation-operator": "error",
"prefer-numeric-literals": "error",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"radix": "error",
"require-atomic-updates": "error",
"require-await": "error",
"semi": "error",
"sonarjs/cognitive-complexity": "off",
"sonarjs/no-duplicate-string": "off",
"sort-keys": "error",
"strict": "error",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-array-reduce": "off",
"unicorn/no-fn-reference-in-iterator": "off",
"unicorn/no-null": "off",
"unicorn/no-reduce": "off",
"unicorn/no-unused-properties": "off",
"unicorn/prevent-abbreviations": "off",
"unicorn/switch-case-braces": "off"
}
};

2
web/.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
public_html/
!public_html/index.html

View File

@@ -61,8 +61,6 @@ add_custom_command(
"${CMAKE_CURRENT_SOURCE_DIR}/esbuild.mjs"
"${CMAKE_CURRENT_SOURCE_DIR}/package-lock.json"
"${CMAKE_CURRENT_SOURCE_DIR}/package.json"
"${CMAKE_CURRENT_SOURCE_DIR}/prettier.config.cjs"
"${CMAKE_CURRENT_SOURCE_DIR}/stylelint.config.cjs"
"${CMAKE_CURRENT_BINARY_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/assets" "assets"

View File

@@ -244,8 +244,9 @@ html,
body {
background-color: var(--color-bg-primary);
color: var(--color-fg-primary);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
height: 100%;
margin: 0;
}
@@ -346,11 +347,11 @@ a {
border-left: 1px solid var(--color-border-default);
height: 25px;
margin: 0 6px 0 0;
}
:nth-last-child(2) {
border: 0;
flex-grow: 1;
&:last-of-type {
border: 0;
flex-grow: 1;
}
}
}
@@ -1056,6 +1057,16 @@ a {
&.skip {
opacity: 0.5;
> .inspector-torrent-file-list-entry-name {
color: var(--color-fg-disabled);
}
}
&.complete {
> .file-wanted-control {
cursor: default;
}
}
}
@@ -1071,23 +1082,11 @@ a {
overflow-wrap: anywhere;
}
.inspector-torrent-file-list-entry.skip
> .inspector-torrent-file-list-entry-name {
color: var(--color-fg-disabled);
}
.inspector-torrent-file-list-entry-progress {
color: var(--color-fg-secondary);
font-size: 12px;
grid-area: info;
}
.single-file .inspector-torrent-file-list-entry,
.inspector-torrent-file-list-entry.complete {
> .file-wanted-control {
cursor: default;
}
}
}
#inspector-header {

View File

@@ -1,6 +1,6 @@
import * as esbuild from 'esbuild';
import * as process from 'node:process';
import {sassPlugin} from 'esbuild-sass-plugin';
import { sassPlugin } from 'esbuild-sass-plugin';
const ctx = await esbuild.context({
bundle: true,
@@ -8,7 +8,8 @@ const ctx = await esbuild.context({
legalComments: 'external',
loader: {
'.png': 'dataurl',
'.svg': 'dataurl' },
'.svg': 'dataurl',
},
minify: true,
outfile: './public_html/transmission-app.js',
plugins: [sassPlugin()],

139
web/eslint.config.js Normal file
View File

@@ -0,0 +1,139 @@
import js from '@eslint/js';
import sonarjs from 'eslint-plugin-sonarjs';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import globals from 'globals';
export default [
js.configs.recommended,
sonarjs.configs.recommended,
eslintPluginUnicorn.configs['flat/recommended'],
{
ignores: ['public_html/'],
},
{
files: ['*.js', '*.mjs'],
languageOptions: {
globals: { ...globals.node },
},
},
{
files: ['src/*.js'],
languageOptions: {
globals: { ...globals.browser, ...globals.es2015 },
},
},
{
rules: {
'accessor-pairs': 'error',
'array-callback-return': 'error',
'arrow-spacing': 'error',
'block-scoped-var': 'error',
'class-methods-use-this': 'error',
'consistent-return': 'error',
curly: 'error',
'default-case': 'error',
'default-case-last': 'error',
'default-param-last': 'error',
eqeqeq: 'error',
'grouped-accessor-pairs': 'error',
'guard-for-in': 'error',
'init-declarations': 'error',
'no-array-constructor': 'error',
'no-caller': 'error',
'no-confusing-arrow': 'error',
'no-constructor-return': 'error',
'no-delete-var': 'error',
'no-dupe-class-members': 'error',
'no-duplicate-imports': 'error',
'no-else-return': 'error',
'no-empty-function': 'error',
'no-eq-null': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-extra-label': 'error',
'no-floating-decimal': 'error',
'no-implicit-coercion': 'error',
'no-implicit-globals': 'error',
'no-implied-eval': 'error',
'no-invalid-this': 'error',
'no-iterator': 'error',
'no-label-var': 'error',
'no-labels': 'error',
'no-lone-blocks': 'error',
'no-loop-func': 'error',
'no-loss-of-precision': 'error',
'no-multi-str': 'error',
'no-nested-ternary': 'error',
'no-new': 'error',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-promise-executor-return': 'error',
'no-proto': 'error',
'no-redeclare': 'error',
'no-restricted-exports': 'error',
'no-restricted-globals': 'error',
'no-restricted-imports': 'error',
'no-restricted-properties': 'error',
'no-return-assign': 'error',
'no-script-url': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow': 'error',
'no-template-curly-in-string': 'error',
'no-this-before-super': 'error',
'no-throw-literal': 'error',
'no-undef-init': 'error',
'no-undefined': 'error',
'no-unmodified-loop-condition': 'error',
'no-unreachable-loop': 'error',
'no-unused-expressions': 'error',
'no-unused-labels': 'error',
'no-unused-vars': 'error',
'no-use-before-define': 'error',
'no-useless-backreference': 'error',
'no-useless-call': 'error',
'no-useless-catch': 'error',
'no-useless-computed-key': 'error',
'no-useless-concat': 'error',
'no-useless-constructor': 'error',
'no-useless-escape': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'error',
'no-void': 'error',
'no-with': 'error',
'object-shorthand': 'error',
'prefer-arrow-callback': 'error',
'prefer-const': 'error',
'prefer-destructuring': 'error',
'prefer-exponentiation-operator': 'error',
'prefer-numeric-literals': 'error',
'prefer-object-spread': 'error',
'prefer-promise-reject-errors': 'error',
'prefer-regex-literals': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
radix: 'error',
'require-atomic-updates': 'error',
'require-await': 'error',
semi: 'error',
'sonarjs/cognitive-complexity': 'off',
'sonarjs/no-duplicate-string': 'off',
'sonarjs/todo-tag': 'off',
'sort-keys': 'error',
strict: 'error',
'unicorn/consistent-function-scoping': 'off',
'unicorn/no-array-reduce': 'off',
'unicorn/no-fn-reference-in-iterator': 'off',
'unicorn/no-null': 'off',
'unicorn/no-reduce': 'off',
'unicorn/no-unused-properties': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/switch-case-braces': 'off',
},
},
];

6730
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,29 +10,30 @@
"generate-buildonly": "node generate-buildonly.js",
"lint": "run-p --silent lint:eslint lint:stylelint lint:prettier",
"lint:fix": "run-s lint:eslint:fix lint:stylelint:fix lint:prettier:fix",
"lint:eslint": "eslint src/*.js",
"lint:eslint:fix": "eslint --fix src/*.js",
"lint:prettier": "prettier --log-level warn --check package.json public_html/index.html assets/css/*scss src/*.js",
"lint:prettier:fix": "prettier --log-level warn -w package.json public_html/index.html assets/css/*scss src/*.js",
"lint:eslint": "eslint",
"lint:eslint:fix": "eslint --fix",
"lint:prettier": "prettier --log-level warn --check .",
"lint:prettier:fix": "prettier --log-level warn -w .",
"lint:stylelint": "stylelint assets/css/*scss",
"lint:stylelint:fix": "stylelint --fix assets/css/*scss"
},
"devDependencies": {
"esbuild": "^0.19.7",
"esbuild-sass-plugin": "^2.16.0",
"@primer/stylelint-config": "^12.8.0",
"eslint": "^8.45.0",
"eslint-plugin-sonarjs": "^0.19.0",
"eslint-plugin-unicorn": "^47.0.0",
"@eslint/js": "^9.7.0",
"@primer/stylelint-config": "^13.4.0",
"esbuild": "^0.25.11",
"esbuild-sass-plugin": "^3.3.1",
"eslint": "^9.38.0",
"eslint-plugin-sonarjs": "^3.0.5",
"eslint-plugin-unicorn": "^61.0.2",
"globals": "^16.4.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.0",
"sass": "^1.63.6",
"style-loader": "^3.3.3",
"stylelint": "^15.10.1",
"stylelint-config-sass-guidelines": "^10.0.0",
"stylelint-config-standard": "^34.0.0"
"prettier": "^3.6.2",
"sass": "^1.89.2",
"style-loader": "^4.0.0",
"stylelint": "^16.25.0",
"stylelint-config-sass-guidelines": "^12.1.0"
},
"dependencies": {
"lodash.isequal": "^4.5.0"
"fast-deep-equal": "^3.1.3"
}
}

View File

@@ -1,3 +0,0 @@
module.exports = {
"singleQuote": true,
};

3
web/prettier.config.js Normal file
View File

@@ -0,0 +1,3 @@
export default {
singleQuote: true,
};

View File

@@ -54,7 +54,10 @@ export class LabelsDialog extends EventTarget {
const { elements } = this;
const { entry } = elements;
const { value } = entry;
const labels = value.split(/ *, */).filter((l) => l.length > 0);
const labels = value
.split(',')
.map((l) => l.trim())
.filter((l) => l.length > 0);
remote.setLabels(ids, labels, (response) => {
if (response.result === 'success') {

View File

@@ -20,8 +20,8 @@ function main() {
const scroll_soon = debounce(() =>
transmission.elements.torrent_list.scrollTo(0, 1),
);
window.addEventListener('load', scroll_soon);
window.addEventListener('orientationchange', scroll_soon);
globalThis.addEventListener('load', scroll_soon);
globalThis.addEventListener('orientationchange', scroll_soon);
}
document.addEventListener('DOMContentLoaded', main);

View File

@@ -7,7 +7,8 @@ import { AlertDialog } from './alert-dialog.js';
import { Formatter } from './formatter.js';
import { createDialogContainer, makeUUID } from './utils.js';
const is_ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
const is_ios =
/iPad|iPhone|iPod/.test(navigator.userAgent) && !globalThis.MSStream;
const is_safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
// https://github.com/transmission/transmission/pull/6320#issuecomment-1896968904
// https://caniuse.com/input-file-accept
@@ -145,7 +146,7 @@ export class OpenDialog extends EventTarget {
input.id = input_id;
input.multiple = true;
if (can_use_input_accept) {
input.accept = ".torrent,application/x-bittorrent";
input.accept = '.torrent,application/x-bittorrent';
}
workarea.append(input);
elements.file_input = input;

View File

@@ -326,7 +326,7 @@ export class OverflowMenu extends EventTarget {
...new Set(speeds)
.add(`${session_properties[RPC._UpSpeedLimit]}`)
.values(),
].sort((a, b) => a - b)) {
].toSorted((a, b) => a - b)) {
const option = document.createElement('option');
option.value = speed;
option.textContent =
@@ -370,7 +370,7 @@ export class OverflowMenu extends EventTarget {
...new Set(speeds)
.add(`${session_properties[RPC._DownSpeedLimit]}`)
.values(),
].sort((a, b) => a - b)) {
].toSorted((a, b) => a - b)) {
const option = document.createElement('option');
option.value = speed;
option.textContent =

View File

@@ -239,7 +239,7 @@ export class PrefsDialog extends EventTarget {
}
static _toggleProtocolHandler(button) {
const handlerUrl = new URL(window.location.href);
const handlerUrl = new URL(globalThis.location.href);
handlerUrl.search = 'addtorrent=%s';
if (this._getProtocolHandlerRegistered()) {
navigator.unregisterProtocolHandler?.('magnet', handlerUrl.toString());

View File

@@ -128,7 +128,8 @@ Prefs.SortMode = 'sort-mode';
Prefs._Defaults = {
[Prefs.AltSpeedEnabled]: false,
[Prefs.DisplayMode]: Prefs.DisplayFull,
[Prefs.ContrastMode]: window.matchMedia('(prefers-contrast: more)').matches
[Prefs.ContrastMode]: globalThis.matchMedia('(prefers-contrast: more)')
.matches
? Prefs.ContrastMore
: Prefs.ContrastLess,
[Prefs.FilterMode]: Prefs.FilterAll,

View File

@@ -21,11 +21,12 @@ export const RPC = {
};
export class Remote {
_connection_alert = null;
_session_id = '';
// TODO: decouple from controller
constructor(controller) {
this._connection_alert = null;
this._controller = controller;
this._session_id = '';
}
sendRequest(data, callback, context) {

View File

@@ -54,7 +54,7 @@ export class ShortcutsDialog extends EventTarget {
o[sortKey] = { name, shortcut };
}
for (const [, values] of Object.entries(o).sort()) {
for (const [, values] of Object.entries(o).toSorted()) {
const { name, shortcut } = values;
tr = document.createElement('tr');
tbody.append(tr);

View File

@@ -164,7 +164,7 @@ export class Torrent extends EventTarget {
return this.fields.id;
}
getLabels() {
return this.fields.labels.sort();
return this.fields.labels.toSorted();
}
getLastActivity() {
return this.fields.activityDate;

View File

@@ -50,7 +50,7 @@ export class Transmission extends EventTarget {
this.refilterAllSoon = debounce(() => this._refilter(true));
this.pointer_device = Object.seal({
is_touch_device: 'ontouchstart' in window,
is_touch_device: 'ontouchstart' in globalThis,
long_press_callback: null,
x: 0,
y: 0,
@@ -328,14 +328,14 @@ export class Transmission extends EventTarget {
_openTorrentFromUrl() {
setTimeout(() => {
const addTorrent = new URLSearchParams(window.location.search).get(
const addTorrent = new URLSearchParams(globalThis.location.search).get(
'addtorrent',
);
if (addTorrent) {
this.setCurrentPopup(new OpenDialog(this, this.remote, addTorrent));
const newUrl = new URL(window.location);
const newUrl = new URL(globalThis.location);
newUrl.search = '';
window.history.pushState('', '', newUrl.toString());
globalThis.history.pushState('', '', newUrl.toString());
}
}, 0);
}
@@ -385,8 +385,7 @@ export class Transmission extends EventTarget {
}
case Prefs.ContrastMode: {
// Add custom class to the body/html element to get the appropriate contrast color scheme
document.body.classList.remove('contrast-more');
document.body.classList.remove('contrast-less');
document.body.classList.remove('contrast-more', 'contrast-less');
document.body.classList.add(`contrast-${value}`);
// this.refilterAllSoon();
break;
@@ -822,7 +821,7 @@ TODO: fix this when notifications get fixed
if (event_.shiftKey) {
this._selectRange(row);
// Need to deselect any selected text
window.focus();
globalThis.focus();
// Apple-Click, not selected
} else if (!row.isSelected() && meta_key) {
@@ -941,7 +940,7 @@ TODO: fix this when notifications get fixed
///
_updateGuiFromSession(o) {
const [, version, checksum] = o.version.match(/(.*)\s\(([\da-f]+)\)/);
const [, version, checksum] = o.version.match(/^(.*)\s\(([\da-f]+)\)/);
this.version_info = {
checksum,
version,
@@ -980,7 +979,7 @@ TODO: fix this when notifications get fixed
_updateFilterSelect() {
const trackers = this._getTrackerCounts();
const sitenames = Object.keys(trackers).sort();
const sitenames = Object.keys(trackers).toSorted();
// build the new html
let string = '';
@@ -1027,6 +1026,9 @@ TODO: fix this when notifications get fixed
let filter_text = null;
let labels = null;
// TODO: This regex is wrong and is about to be removed in https://github.com/transmission/transmission/pull/7008,
// so it is left alone for now.
// eslint-disable-next-line sonarjs/slow-regex
const m = /^labels:([\w,-\s]*)(.*)$/.exec(this.filterText);
if (m) {
filter_text = m[2].trim();

View File

@@ -3,7 +3,7 @@
or any future license endorsed by Mnemosyne LLC.
License text can be found in the licenses/ folder. */
import isEqual from 'lodash.isequal';
import equal from 'fast-deep-equal/es6';
export const Utils = {
/** Given a numerator and denominator, return a ratio string */
@@ -207,7 +207,7 @@ export function debounce(callback, wait = 100) {
}
export function deepEqual(a, b) {
return isEqual(a, b);
return equal(a, b);
}
function setOrDeleteAttribute(element, attribute, b) {

View File

@@ -1,47 +0,0 @@
module.exports = {
"extends": [
"stylelint-config-sass-guidelines"
],
"plugins": [
"@primer/stylelint-config/plugins/no-undefined-vars",
"@primer/stylelint-config/plugins/no-unused-vars"
],
"rules": {
"block-no-empty": true,
"color-no-invalid-hex": true,
"comment-no-empty": true,
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"font-family-no-duplicate-names": true,
"function-calc-no-unspaced-operator": true,
"function-linear-gradient-no-nonstandard-direction": true,
"max-nesting-depth": null,
"media-feature-name-no-unknown": true,
"no-duplicate-at-import-rules": true,
"no-duplicate-selectors": null,
"no-empty-source": true,
"no-invalid-double-slash-comments": true,
"primer/no-undefined-vars": true,
"primer/no-unused-vars": true,
"property-no-unknown": true,
"property-no-vendor-prefix": null,
"scss/at-rule-no-unknown": true,
"selector-attribute-quotes": null,
"selector-max-compound-selectors": null,
"selector-max-id": null,
"selector-no-qualifying-type": [
true,
{
"ignore": [
"attribute"
]
}
],
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-element-no-unknown": true,
"selector-type-no-unknown": true,
"string-no-newline": true,
"unit-no-unknown": true,
}
};

40
web/stylelint.config.js Normal file
View File

@@ -0,0 +1,40 @@
/** @type {import('stylelint').Config} */
export default {
extends: ['stylelint-config-sass-guidelines'],
rules: {
'@stylistic/function-parentheses-space-inside': 'never-single-line',
'block-no-empty': true,
'color-no-invalid-hex': true,
'comment-no-empty': true,
'declaration-block-no-duplicate-properties': true,
'declaration-block-no-shorthand-property-overrides': true,
'font-family-no-duplicate-names': true,
'function-calc-no-unspaced-operator': true,
'function-linear-gradient-no-nonstandard-direction': true,
'max-nesting-depth': null,
'media-feature-name-no-unknown': true,
'no-duplicate-at-import-rules': true,
'no-duplicate-selectors': null,
'no-empty-source': true,
'no-invalid-double-slash-comments': true,
'no-unknown-custom-properties': true,
// TODO: add back rule for unused variables?
'property-no-unknown': true,
'property-no-vendor-prefix': null,
'scss/at-rule-no-unknown': true,
'selector-attribute-quotes': null,
'selector-max-compound-selectors': null,
'selector-max-id': null,
'selector-no-qualifying-type': [
true,
{
ignore: ['attribute'],
},
],
'selector-pseudo-class-no-unknown': true,
'selector-pseudo-element-no-unknown': true,
'selector-type-no-unknown': true,
'string-no-newline': true,
'unit-no-unknown': true,
},
};