chore: update eslint and stylelint configs and re-sync modern-normalize (#38982)

- update the vendored `modern-normalize` to v3.0.1
- require descriptions for lint disables in TS and CSS, same as we
already have in Go.
- disable core rules covered by `regexp/*` and `unicorn/*`, and ones
that cannot fire
- stop applying vitest rules to the playwright files in `tests/e2e`
- enable 7 stylelint rules, mostly `no-unknown` and `no-invalid` checks
- drop 2 unnecessary vendor prefixes (safari v17+, chrome v120+)
- look up ids via `querySelector` with `CSS.escape` instead of
`getElementById`
- remove stale doc about `@ts-expect-error`, it's forbidden
- misc dev doc fixes

Every declaration that `modern-normalize` v3 removes was checked against
chromium, webkit and firefox defaults first. The `hr` color and the
`:-moz-focusring` outline are kept as documented deviations, dropping
those does change rendering.

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
silverwind
2026-08-20 09:57:56 -04:00
committed by GitHub
co-authored by wxiaoguang
parent c778c6c920
commit 61be9fcdfa
32 changed files with 97 additions and 137 deletions
+9 -6
View File
@@ -6,7 +6,7 @@ and testing see [development.md](development.md) and [testing.md](testing.md).
## Background ## Background
The frontend uses [Vue 3](https://vuejs.org/), [Fomantic-UI](https://fomantic-ui.com/) (built on jQuery) The frontend uses [Vue 3](https://vuejs.org/), hard-forked Fomantic-UI (built on jQuery)
and [Tailwind CSS](https://tailwindcss.com/). Pages are rendered with Go HTML templates. and [Tailwind CSS](https://tailwindcss.com/). Pages are rendered with Go HTML templates.
Source files live in: Source files live in:
@@ -44,8 +44,10 @@ Gitea uses Vue 3 **without** JSX to keep HTML and JavaScript separate.
## Gitea-specific conventions ## Gitea-specific conventions
- Keep features in their own files or directories. - Keep features in their own files or directories.
- Use kebab-case for HTML `id`s and classes, ideally with 2-3 feature keywords. - Use kebab-case for HTML `id`s and classes with 2-3 feature keywords.
- Prefix classes to avoid short-name conflicts between different frameworks. - Prefix classes to avoid short-name conflicts between different frameworks.
- Our framework can automatically link "input" and "label" if they are the children of a `.field` element,
no need to write `id`/`for` attributes for them unless there are reasons to do so.
- Create a new class name when overriding framework styles instead of editing the framework's own classes, - Create a new class name when overriding framework styles instead of editing the framework's own classes,
or fix the framework's source to fix all cases. or fix the framework's source to fix all cases.
- Prefer semantic elements such as `<button>` over generic `<div>`s. - Prefer semantic elements such as `<button>` over generic `<div>`s.
@@ -68,17 +70,18 @@ Write class attributes as a single readable unit in templates:
## TypeScript ## TypeScript
- Use `import type` for type-only imports. - Use `import type` for type-only imports.
- Prefer `@ts-expect-error` over `@ts-ignore`.
- Use the `!` non-null assertion (rather than `?.`/`??`) when a value is known to always exist. - Use the `!` non-null assertion (rather than `?.`/`??`) when a value is known to always exist.
- Only mark a function `async` when it actually uses `await` or returns a `Promise`. - Only mark a function `async` when it actually uses `await` or returns a `Promise`.
Avoid async event listeners; if unavoidable, call `e.preventDefault()` before the Avoid async event listeners; if unavoidable, call `e.preventDefault()` before the first `await`.
first `await`. For a deliberately un-awaited call, assign it: `const _promise = asyncFoo()`.
## Data fetching ## Data fetching
Use the `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` wrappers from Use the `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` wrappers from
[`web_src/js/modules/fetch.ts`](../web_src/js/modules/fetch.ts). [`web_src/js/modules/fetch.ts`](../web_src/js/modules/fetch.ts).
Prefer to use our [`fetch-action.ts`](../web_src/js/modules/fetch-action.ts) framework
for form submissions, button clicks and network requests, which provides a consistent UX and error handling.
## DOM attributes ## DOM attributes
Avoid `node.dataset` because of its camel-casing behavior; use `node.getAttribute` Avoid `node.dataset` because of its camel-casing behavior; use `node.getAttribute`
@@ -86,7 +89,7 @@ in new code. Never bind user-provided data directly onto DOM nodes.
## Showing and hiding elements ## Showing and hiding elements
- In Vue, use `v-if` and `v-show`. - In Vue, use `v-if` and `v-show`. If an element contains unmanaged DOM, use `v-show` to avoid losing the DOM state.
- In Go templates and plain JavaScript, use the `.tw-hidden` class together with the - In Go templates and plain JavaScript, use the `.tw-hidden` class together with the
`showElem()`, `hideElem()`, and `toggleElem()` helpers from `showElem()`, `hideElem()`, and `toggleElem()` helpers from
[`web_src/js/utils/dom.ts`](../web_src/js/utils/dom.ts). [`web_src/js/utils/dom.ts`](../web_src/js/utils/dom.ts).
+7 -6
View File
@@ -79,7 +79,7 @@ export default defineConfig([
'@eslint-community/eslint-comments/no-unlimited-disable': [2], '@eslint-community/eslint-comments/no-unlimited-disable': [2],
'@eslint-community/eslint-comments/no-unused-enable': [2], '@eslint-community/eslint-comments/no-unused-enable': [2],
'@eslint-community/eslint-comments/no-use': [0], '@eslint-community/eslint-comments/no-use': [0],
'@eslint-community/eslint-comments/require-description': [0], '@eslint-community/eslint-comments/require-description': [2, {ignore: ['eslint', 'eslint-enable', 'eslint-env', 'exported', 'global', 'globals']}],
'@stylistic/array-bracket-newline': [0], '@stylistic/array-bracket-newline': [0],
'@stylistic/array-bracket-spacing': [2, 'never'], '@stylistic/array-bracket-spacing': [2, 'never'],
'@stylistic/array-element-newline': [0], '@stylistic/array-element-newline': [0],
@@ -258,7 +258,7 @@ export default defineConfig([
'@typescript-eslint/prefer-function-type': [2], '@typescript-eslint/prefer-function-type': [2],
'@typescript-eslint/prefer-includes': [2], '@typescript-eslint/prefer-includes': [2],
'@typescript-eslint/prefer-literal-enum-member': [0], '@typescript-eslint/prefer-literal-enum-member': [0],
'@typescript-eslint/prefer-namespace-keyword': [2], '@typescript-eslint/prefer-namespace-keyword': [0], // handled by @typescript-eslint/no-namespace
'@typescript-eslint/prefer-nullish-coalescing': [0], '@typescript-eslint/prefer-nullish-coalescing': [0],
'@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}], '@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}],
'@typescript-eslint/prefer-promise-reject-errors': [2], '@typescript-eslint/prefer-promise-reject-errors': [2],
@@ -531,8 +531,8 @@ export default defineConfig([
'no-nonoctal-decimal-escape': [2], 'no-nonoctal-decimal-escape': [2],
'no-obj-calls': [2], 'no-obj-calls': [2],
'no-object-constructor': [2], 'no-object-constructor': [2],
'no-octal-escape': [2], 'no-octal-escape': [0], // parse error under strict mode
'no-octal': [2], 'no-octal': [0], // parse error under strict mode
'no-param-reassign': [0], 'no-param-reassign': [0],
'no-plusplus': [0], 'no-plusplus': [0],
'no-promise-executor-return': [0], 'no-promise-executor-return': [0],
@@ -581,7 +581,7 @@ export default defineConfig([
'no-useless-call': [2], 'no-useless-call': [2],
'no-useless-catch': [2], 'no-useless-catch': [2],
'no-useless-computed-key': [2], 'no-useless-computed-key': [2],
'no-useless-concat': [2], 'no-useless-concat': [0], // handled by unicorn/no-useless-concat
'no-useless-constructor': [2], 'no-useless-constructor': [2],
'no-useless-escape': [2], 'no-useless-escape': [2],
'no-useless-rename': [2], 'no-useless-rename': [2],
@@ -592,7 +592,7 @@ export default defineConfig([
'no-with': [0], // handled by no-restricted-syntax 'no-with': [0], // handled by no-restricted-syntax
'object-shorthand': [2, 'always'], 'object-shorthand': [2, 'always'],
'one-var': [0], 'one-var': [0],
'operator-assignment': [2, 'always'], 'operator-assignment': [0], // handled by unicorn/operator-assignment
'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}], 'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}],
'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}], 'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}],
'prefer-destructuring': [0], 'prefer-destructuring': [0],
@@ -1096,6 +1096,7 @@ export default defineConfig([
}, },
{ {
files: ['**/*.test.ts', 'web_src/js/vitest.setup.ts'], files: ['**/*.test.ts', 'web_src/js/vitest.setup.ts'],
ignores: ['tests/e2e/**'],
plugins: {vitest}, plugins: {vitest},
languageOptions: {globals: globals.vitest}, languageOptions: {globals: globals.vitest},
rules: { rules: {
+8
View File
@@ -12,6 +12,7 @@ export default {
reportUnscopedDisables: true, reportUnscopedDisables: true,
reportNeedlessDisables: true, reportNeedlessDisables: true,
reportInvalidScopeDisables: true, reportInvalidScopeDisables: true,
reportDescriptionlessDisables: true,
plugins: [ plugins: [
'stylelint-declaration-strict-value', 'stylelint-declaration-strict-value',
'stylelint-declaration-block-no-ignored-properties', 'stylelint-declaration-block-no-ignored-properties',
@@ -81,6 +82,7 @@ export default {
'@stylistic/no-eol-whitespace': true, '@stylistic/no-eol-whitespace': true,
'@stylistic/no-extra-semicolons': true, '@stylistic/no-extra-semicolons': true,
'@stylistic/no-missing-end-of-source-newline': null, '@stylistic/no-missing-end-of-source-newline': null,
'@stylistic/no-multiple-whitespaces': true,
'@stylistic/number-leading-zero': null, '@stylistic/number-leading-zero': null,
'@stylistic/number-no-trailing-zeros': null, '@stylistic/number-no-trailing-zeros': null,
'@stylistic/property-case': 'lower', '@stylistic/property-case': 'lower',
@@ -108,13 +110,17 @@ export default {
'@stylistic/value-list-max-empty-lines': 0, '@stylistic/value-list-max-empty-lines': 0,
'at-rule-no-unknown': [true, {ignoreAtRules: ['tailwind']}], 'at-rule-no-unknown': [true, {ignoreAtRules: ['tailwind']}],
'at-rule-no-vendor-prefix': true, 'at-rule-no-vendor-prefix': true,
'block-no-redundant-nested-style-rules': true,
'color-no-invalid-hex': true,
'csstools/value-no-unknown-custom-properties': [true, {importFrom: cssVarFiles}], 'csstools/value-no-unknown-custom-properties': [true, {importFrom: cssVarFiles}],
'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}], 'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}],
'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow', 'grid-template']}], 'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow', 'grid-template']}],
'declaration-property-unit-disallowed-list': null, 'declaration-property-unit-disallowed-list': null,
'declaration-property-value-disallowed-list': {'word-break': ['break-word']}, 'declaration-property-value-disallowed-list': {'word-break': ['break-word']},
'font-family-name-quotes': 'always-where-recommended', 'font-family-name-quotes': 'always-where-recommended',
'function-linear-gradient-no-nonstandard-direction': true,
'function-name-case': 'lower', 'function-name-case': 'lower',
'function-no-unknown': true,
'function-url-quotes': 'always', 'function-url-quotes': 'always',
'import-notation': 'string', 'import-notation': 'string',
'length-zero-no-unit': [true, {ignore: ['custom-properties'], ignoreFunctions: ['var']}], 'length-zero-no-unit': [true, {ignore: ['custom-properties'], ignoreFunctions: ['var']}],
@@ -125,6 +131,7 @@ export default {
'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting 'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting
'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting 'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting
'plugin/declaration-block-no-ignored-properties': true, 'plugin/declaration-block-no-ignored-properties': true,
'property-no-vendor-prefix': true,
'scale-unlimited/declaration-strict-value': [['/color$/', 'fill', 'stroke', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}], 'scale-unlimited/declaration-strict-value': [['/color$/', 'fill', 'stroke', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}],
'selector-attribute-quotes': 'always', 'selector-attribute-quotes': 'always',
'selector-no-vendor-prefix': true, 'selector-no-vendor-prefix': true,
@@ -132,6 +139,7 @@ export default {
'selector-type-case': 'lower', 'selector-type-case': 'lower',
'selector-type-no-unknown': [true, {ignore: ['custom-elements']}], 'selector-type-no-unknown': [true, {ignore: ['custom-elements']}],
'shorthand-property-no-redundant-values': true, 'shorthand-property-no-redundant-values': true,
'unit-no-unknown': true,
'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}], 'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}],
}, },
} satisfies Config; } satisfies Config;
+1 -1
View File
@@ -3,7 +3,7 @@ import {expect, test} from '@playwright/test';
import {apiCreateRepo, apiCreateFile, assertFlushWithParent, assertNoJsError, login, randomString} from './utils.ts'; import {apiCreateRepo, apiCreateFile, assertFlushWithParent, assertNoJsError, login, randomString} from './utils.ts';
test('3d model file', async ({page, request, browserName}) => { test('3d model file', async ({page, request, browserName}) => {
test.skip(browserName === 'firefox', 'unclear firefox-only CI-only failure'); // eslint-disable-line playwright/no-skipped-test test.skip(browserName === 'firefox', 'unclear firefox-only CI-only failure'); // eslint-disable-line playwright/no-skipped-test -- conditional skip, the reason is in the message
const repoName = `e2e-3d-render-${randomString(8)}`; const repoName = `e2e-3d-render-${randomString(8)}`;
const owner = env.GITEA_TEST_E2E_USER; const owner = env.GITEA_TEST_E2E_USER;
await apiCreateRepo(request, {name: repoName}); await apiCreateRepo(request, {name: repoName});
+1 -1
View File
@@ -19,7 +19,7 @@ async function signInWithPassword(page: Page, username: string) {
// regression: credProtect level 3 hid the credential from the second-factor login // regression: credProtect level 3 hid the credential from the second-factor login
test('security key survives credProtect', async ({page, request, browserName}) => { test('security key survives credProtect', async ({page, request, browserName}) => {
test.skip(browserName !== 'chromium', 'only the CDP authenticator emulates credProtect'); // eslint-disable-line playwright/no-skipped-test test.skip(browserName !== 'chromium', 'only the CDP authenticator emulates credProtect'); // eslint-disable-line playwright/no-skipped-test -- conditional skip, the reason is in the message
const username = `e2e-credprotect-${randomString(8)}`; const username = `e2e-credprotect-${randomString(8)}`;
await apiCreateUser(request, username); await apiCreateUser(request, username);
@@ -1,6 +1,6 @@
// MIT license, Copyright (c) GitHub, Inc. // MIT license, Copyright (c) GitHub, Inc.
// https://github.com/github/eslint-plugin-github/blob/main/lib/rules/unescaped-html-literal.js // https://github.com/github/eslint-plugin-github/blob/main/lib/rules/unescaped-html-literal.js
/* eslint-disable no-template-curly-in-string */ /* eslint-disable no-template-curly-in-string -- the fixtures are template literal sources inside plain strings */
import rule from './unescaped-html-literal.ts'; import rule from './unescaped-html-literal.ts';
import {RuleTester} from 'eslint'; import {RuleTester} from 'eslint';
-1
View File
@@ -269,7 +269,6 @@ relative-time::part(root)::selection {
.lines-commit .blame-info, .lines-commit .blame-info,
.ellipsis-button { .ellipsis-button {
-webkit-touch-callout: none; -webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none; user-select: none;
} }
+20 -20
View File
@@ -51,7 +51,7 @@
local("SourceHanSans-Light"), local("Yu Gothic Regular"), local("SourceHanSans-Light"), local("Yu Gothic Regular"),
local("YuGothic Regular"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Regular"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -66,7 +66,7 @@
local("SourceHanSans-Regular"), local("Yu Gothic Medium"), local("SourceHanSans-Regular"), local("Yu Gothic Medium"),
local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -81,7 +81,7 @@
local("SourceHanSans-Medium"), local("Yu Gothic Medium"), local("SourceHanSans-Medium"), local("Yu Gothic Medium"),
local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -95,7 +95,7 @@
local("NotoSansCJKJP-Bold"), local("Source Han Sans Bold"), local("NotoSansCJKJP-Bold"), local("Source Han Sans Bold"),
local("SourceHanSans-Bold"), local("Yu Gothic Bold"), local("YuGothic Bold"), local("SourceHanSans-Bold"), local("Yu Gothic Bold"), local("YuGothic Bold"),
local("Droid Sans Japanese"), local("Meiryo Bold"), local("MS PGothic"); local("Droid Sans Japanese"), local("Meiryo Bold"), local("MS PGothic");
font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -124,7 +124,7 @@
local("NotoSansCJKSC-Light"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Light"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei Light"), local("Hiragino Sans GB W3"), local("Microsoft YaHei Light"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -137,7 +137,7 @@
local("NotoSansCJKSC-Regular"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Regular"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei"), local("Hiragino Sans GB W3"), local("Microsoft YaHei"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -150,7 +150,7 @@
local("NotoSansCJKSC-Medium"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Medium"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei"), local("Hiragino Sans GB W3"), local("Microsoft YaHei"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -163,7 +163,7 @@
local("NotoSansCJKSC-Bold"), local("HiraginoSansGB-W6"), local("NotoSansCJKSC-Bold"), local("HiraginoSansGB-W6"),
local("Hiragino Sans GB W6"), local("Microsoft YaHei Bold"), local("Hiragino Sans GB W6"), local("Microsoft YaHei Bold"),
local("Heiti SC Medium"), local("SimHei"); local("Heiti SC Medium"), local("SimHei");
font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -192,7 +192,7 @@
local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -205,7 +205,7 @@
local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -218,7 +218,7 @@
local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -231,7 +231,7 @@
local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"), local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"),
local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"), local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"),
local("Heiti TC Medium"), local("PMingLiU"); local("Heiti TC Medium"), local("PMingLiU");
font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -262,7 +262,7 @@
local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -277,7 +277,7 @@
local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -292,7 +292,7 @@
local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -307,7 +307,7 @@
local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"), local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"),
local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"), local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"),
local("Heiti TC Medium"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Medium"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -335,7 +335,7 @@
local("SourceHanSansK-Light"), local("Noto Sans CJK KR Light"), local("SourceHanSansK-Light"), local("Noto Sans CJK KR Light"),
local("NotoSansCJKKR-Light"), local("NanumBarunGothic Light"), local("NotoSansCJKKR-Light"), local("NanumBarunGothic Light"),
local("Malgun Gothic Semilight"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic Semilight"), local("Nanum Gothic"), local("Dotum");
font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -347,7 +347,7 @@
local("SourceHanSansK-Regular"), local("Noto Sans CJK KR Regular"), local("SourceHanSansK-Regular"), local("Noto Sans CJK KR Regular"),
local("NotoSansCJKKR-Regular"), local("NanumBarunGothic"), local("NotoSansCJKKR-Regular"), local("NanumBarunGothic"),
local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum");
font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -359,7 +359,7 @@
local("SourceHanSansK-Medium"), local("Noto Sans CJK KR Medium"), local("SourceHanSansK-Medium"), local("Noto Sans CJK KR Medium"),
local("NotoSansCJKKR-Medium"), local("NanumBarunGothic"), local("NotoSansCJKKR-Medium"), local("NanumBarunGothic"),
local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum");
font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@@ -371,7 +371,7 @@
local("SourceHanSansK-Bold"), local("Noto Sans CJK KR Bold"), local("SourceHanSansK-Bold"), local("Noto Sans CJK KR Bold"),
local("NotoSansCJKKR-Bold"), local("NanumBarunGothic Bold"), local("NotoSansCJKKR-Bold"), local("NanumBarunGothic Bold"),
local("Malgun Gothic Bold"), local("Nanum Gothic Bold"), local("Dotum"); local("Malgun Gothic Bold"), local("Nanum Gothic Bold"), local("Dotum");
font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */ font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value -- @font-face descriptors do not accept var() */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
+1 -1
View File
@@ -103,7 +103,7 @@
} }
/* reference sizes (not exactly at the moment): normal: padding-x=21, height=38 ; compact: padding-x=15, height=32 */ /* reference sizes (not exactly at the moment): normal: padding-x=21, height=38 ; compact: padding-x=15, height=32 */
.ui.button { /* stylelint-disable-line no-duplicate-selectors */ .ui.button { /* stylelint-disable-line no-duplicate-selectors -- deliberate second block for the reference sizes */
gap: var(--gap-block); gap: var(--gap-block);
min-height: 38px; min-height: 38px;
padding: 0.57em /* around 8px */ 1.43em /* around 20px */; padding: 0.57em /* around 8px */ 1.43em /* around 20px */;
-1
View File
@@ -401,7 +401,6 @@ input:-webkit-autofill,
input:-webkit-autofill:focus, input:-webkit-autofill:focus,
input:-webkit-autofill:hover, input:-webkit-autofill:hover,
input:-webkit-autofill:active { input:-webkit-autofill:active {
-webkit-background-clip: text;
-webkit-text-fill-color: var(--color-text); -webkit-text-fill-color: var(--color-text);
box-shadow: 0 0 0 100px var(--color-primary-light-6) inset !important; box-shadow: 0 0 0 100px var(--color-primary-light-6) inset !important;
border-color: var(--color-primary-light-4) !important; border-color: var(--color-primary-light-4) !important;
+13 -52
View File
@@ -5,9 +5,12 @@
- Remove html tab-size, we set our own - Remove html tab-size, we set our own
- Remove b,strong font-weight, we set our own - Remove b,strong font-weight, we set our own
- Remove b,code,samp,pre font-size, we set our own - Remove b,code,samp,pre font-size, we set our own
- Keep the browser's default line-height on html, it is font-dependent and roughly 1.2
- Keep the hr color that v3 dropped, it keeps the separator colored like the surrounding text
- Keep the :-moz-focusring outline that v3 dropped, checkboxes and radios have no other focus style
*/ */
/*! modern-normalize v2.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */
/* /*
Document Document
@@ -25,7 +28,8 @@ Use a better box model (opinionated).
} }
html { html {
line-height: normal; /* 1. (not following the "modern-normalize") Do not change the browser's default line-height, the default value is font-dependent and roughly 1.2 */ line-height: normal;
/* stylelint-disable-next-line property-no-vendor-prefix -- no unprefixed support in Safari or Firefox */
-webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */ -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */
} }
@@ -43,14 +47,8 @@ Grouping content
================ ================
*/ */
/**
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
*/
hr { hr {
height: 0; /* 1 */ color: inherit;
color: inherit; /* 2 */
} }
/* /*
@@ -58,14 +56,6 @@ Text-level semantics
==================== ====================
*/ */
/**
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr[title] {
text-decoration: underline dotted;
}
/** /**
Add the correct font size in all browsers. Add the correct font size in all browsers.
*/ */
@@ -100,13 +90,11 @@ Tabular data
*/ */
/** /**
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016)
2. Correct table border color inheritance in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
*/ */
table { table {
text-indent: 0; /* 1 */ border-color: currentcolor;
border-color: inherit; /* 2 */
} }
/* /*
@@ -130,15 +118,6 @@ textarea {
margin: 0; /* 2 */ margin: 0; /* 2 */
} }
/**
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/** /**
Correct the inability to style clickable types in iOS and Safari. Correct the inability to style clickable types in iOS and Safari.
*/ */
@@ -147,35 +126,14 @@ button,
[type="button"], [type="button"],
[type="reset"], [type="reset"],
[type="submit"] { [type="submit"] {
/* stylelint-disable-next-line property-no-vendor-prefix -- upstream v3.0.1 still ships the prefix */
-webkit-appearance: button; -webkit-appearance: button;
} }
/**
Remove the inner border and padding in Firefox.
*/
::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
Restore the focus styles unset by the previous rule.
*/
:-moz-focusring { :-moz-focusring {
outline: 1px dotted ButtonText; outline: 1px dotted ButtonText;
} }
/**
Remove the additional ':invalid' styles in Firefox.
See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737
*/
:-moz-ui-invalid {
box-shadow: none;
}
/** /**
Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.
*/ */
@@ -207,6 +165,7 @@ Correct the cursor style of increment and decrement buttons in Safari.
*/ */
[type="search"] { [type="search"] {
/* stylelint-disable-next-line property-no-vendor-prefix -- upstream v3.0.1 still ships the prefix */
-webkit-appearance: textfield; /* 1 */ -webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */ outline-offset: -2px; /* 2 */
} }
@@ -216,6 +175,7 @@ Remove the inner padding in Chrome and Safari on macOS.
*/ */
::-webkit-search-decoration { ::-webkit-search-decoration {
/* stylelint-disable-next-line property-no-vendor-prefix -- upstream v3.0.1 still ships the prefix */
-webkit-appearance: none; -webkit-appearance: none;
} }
@@ -225,6 +185,7 @@ Remove the inner padding in Chrome and Safari on macOS.
*/ */
::-webkit-file-upload-button { ::-webkit-file-upload-button {
/* stylelint-disable-next-line property-no-vendor-prefix -- upstream v3.0.1 still ships the prefix */
-webkit-appearance: button; /* 1 */ -webkit-appearance: button; /* 1 */
font: inherit; /* 2 */ font: inherit; /* 2 */
} }
+1 -1
View File
@@ -3,7 +3,7 @@ import {POST} from '../../modules/fetch.ts';
import {registerGlobalInitFunc} from '../../modules/observer.ts'; import {registerGlobalInitFunc} from '../../modules/observer.ts';
import {queryElems} from '../../utils/dom.ts'; import {queryElems} from '../../utils/dom.ts';
import {errorMessage} from '../../modules/errors.ts'; import {errorMessage} from '../../modules/errors.ts';
import {submitFormFetchAction} from '../common-fetch-action.ts'; import {submitFormFetchAction} from '../../modules/fetch-action.ts';
import {cutString} from '../../utils/string.ts'; import {cutString} from '../../utils/string.ts';
const {appSubUrl} = window.config; const {appSubUrl} = window.config;
+5 -8
View File
@@ -71,19 +71,16 @@ export function initGlobalDropdown() {
action: 'hide', action: 'hide',
onShow() { onShow() {
// hide associated tooltip while dropdown is open // hide associated tooltip while dropdown is open
this._tippy?.hide(); el._tippy?.hide();
this._tippy?.disable(); el._tippy?.disable();
}, },
onHide() { onHide() {
this._tippy?.enable(); el._tippy?.enable();
// eslint-disable-next-line unicorn/no-this-assignment
const elDropdown = this;
// hide all tippy elements of items after a while. eg: use Enter to click "Copy Link" in the Issue Context Menu // hide all tippy elements of items after a while, in case some items have tooltip popup.
setTimeout(() => { setTimeout(() => {
const $dropdown = fomanticQuery(elDropdown);
if ($dropdown.dropdown('is hidden')) { if ($dropdown.dropdown('is hidden')) {
queryElems(elDropdown, '.menu > .item', (el) => el._tippy?.hide()); queryElems(el, '.menu > .item', (item) => item._tippy?.hide());
} }
}, 2000); }, 2000);
}, },
+1 -1
View File
@@ -13,7 +13,7 @@ export function replaceTextareaSelection(textarea: HTMLTextAreaElement, text: st
textarea.focus(); textarea.focus();
let success = false; let success = false;
try { try {
success = document.execCommand('insertText', false, text); // eslint-disable-line @typescript-eslint/no-deprecated success = document.execCommand('insertText', false, text); // eslint-disable-line @typescript-eslint/no-deprecated -- no replacement keeps the undo history
} catch {} } catch {}
// fall back to regular replacement // fall back to regular replacement
+1 -1
View File
@@ -1,6 +1,6 @@
import {toggleElem} from '../../utils/dom.ts'; import {toggleElem} from '../../utils/dom.ts';
import {showFomanticModal} from '../../modules/fomantic/modal.ts'; import {showFomanticModal} from '../../modules/fomantic/modal.ts';
import {submitFormFetchAction} from '../common-fetch-action.ts'; import {submitFormFetchAction} from '../../modules/fetch-action.ts';
function nameHasScope(name: string): boolean { function nameHasScope(name: string): boolean {
return /.*[^/]\/[^/].*/.test(name); return /.*[^/]\/[^/].*/.test(name);
+2 -4
View File
@@ -11,7 +11,7 @@ import {createTippy} from '../modules/tippy.ts';
import {invertFileFolding} from './file-fold.ts'; import {invertFileFolding} from './file-fold.ts';
import {parseDom} from '../utils.ts'; import {parseDom} from '../utils.ts';
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts'; import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts';
import {performFetchActionTrigger} from './common-fetch-action.ts'; import {performFetchActionTrigger} from '../modules/fetch-action.ts';
import {initImageDiff} from './imagediff.ts'; import {initImageDiff} from './imagediff.ts';
function initDiffFileViewToggle(el: HTMLElement) { function initDiffFileViewToggle(el: HTMLElement) {
@@ -206,9 +206,7 @@ async function onLocationHashChange() {
const targetElementId = currentHash.substring(1); const targetElementId = currentHash.substring(1);
while (currentHash === window.location.hash) { while (currentHash === window.location.hash) {
// use getElementById to avoid querySelector throws an error when the hash is invalid const targetElement = document.querySelector<HTMLElement>(`#${CSS.escape(targetElementId)}`);
// eslint-disable-next-line unicorn/prefer-query-selector
const targetElement = document.getElementById(targetElementId);
if (targetElement) { if (targetElement) {
// need to change hash to re-trigger ":target" CSS selector, let's manually scroll to it // need to change hash to re-trigger ":target" CSS selector, let's manually scroll to it
targetElement.scrollIntoView(); targetElement.scrollIntoView();
+1 -1
View File
@@ -6,7 +6,7 @@ import {POST} from '../modules/fetch.ts';
import {initDropzone} from './dropzone.ts'; import {initDropzone} from './dropzone.ts';
import {confirmModal} from './comp/ConfirmModal.ts'; import {confirmModal} from './comp/ConfirmModal.ts';
import {applyAreYouSure, ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts'; import {applyAreYouSure, ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts';
import {submitFormFetchAction} from './common-fetch-action.ts'; import {submitFormFetchAction} from '../modules/fetch-action.ts';
import {dirname} from '../utils.ts'; import {dirname} from '../utils.ts';
import {pathEscapeSegments} from '../utils/url.ts'; import {pathEscapeSegments} from '../utils/url.ts';
import {showErrorToast} from '../modules/toast.ts'; import {showErrorToast} from '../modules/toast.ts';
+1 -1
View File
@@ -4,7 +4,7 @@ import {confirmModal} from './comp/ConfirmModal.ts';
import {createSortable} from '../modules/sortable.ts'; import {createSortable} from '../modules/sortable.ts';
import {DELETE, POST} from '../modules/fetch.ts'; import {DELETE, POST} from '../modules/fetch.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts'; import {fomanticQuery} from '../modules/fomantic/base.ts';
import {performFetchAction} from './common-fetch-action.ts'; import {performFetchAction} from '../modules/fetch-action.ts';
import type {SortableEvent} from 'sortablejs'; import type {SortableEvent} from 'sortablejs';
function initRepoIssueListCheckboxes() { function initRepoIssueListCheckboxes() {
+3 -3
View File
@@ -48,7 +48,7 @@ async function initRepoProjectSortable(): Promise<void> {
handle: '.project-column-header', handle: '.project-column-header',
delayOnTouchOnly: true, delayOnTouchOnly: true,
delay: 500, delay: 500,
onSort: async () => { // eslint-disable-line @typescript-eslint/no-misused-promises onSort: async () => { // eslint-disable-line @typescript-eslint/no-misused-promises -- Sortable ignores the returned promise, the body catches its own errors
boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column'); boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
const columnSorting = { const columnSorting = {
@@ -72,8 +72,8 @@ async function initRepoProjectSortable(): Promise<void> {
const boardCardList = boardColumn.querySelector<HTMLElement>('.cards')!; const boardCardList = boardColumn.querySelector<HTMLElement>('.cards')!;
createSortable(boardCardList, { createSortable(boardCardList, {
group: 'shared', group: 'shared',
onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises -- Sortable ignores the returned promise, moveIssue catches its own errors
onUpdate: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises onUpdate: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises -- Sortable ignores the returned promise, moveIssue catches its own errors
delayOnTouchOnly: true, delayOnTouchOnly: true,
delay: 500, delay: 500,
}); });
+1 -1
View File
@@ -32,7 +32,7 @@ export async function attachTribute(element: HTMLElement) {
}; };
const mentionCollection: TributeCollection<Mention> = { const mentionCollection: TributeCollection<Mention> = {
values: async (_query: string, cb: (matches: Mention[]) => void) => { // eslint-disable-line @typescript-eslint/no-misused-promises values: async (_query: string, cb: (matches: Mention[]) => void) => { // eslint-disable-line @typescript-eslint/no-misused-promises -- tributejs ignores the returned promise, results arrive via the callback
cb(mentionsUrl ? await fetchMentions(mentionsUrl) : []); cb(mentionsUrl ? await fetchMentions(mentionsUrl) : []);
}, },
requireLeadingSpace: true, requireLeadingSpace: true,
+1 -1
View File
@@ -1,4 +1,4 @@
import jquery from 'jquery'; // eslint-disable-line no-restricted-imports import jquery from 'jquery'; // eslint-disable-line no-restricted-imports -- this is where the global $ comes from
// Some users still use inline scripts and expect jQuery to be available globally. // Some users still use inline scripts and expect jQuery to be available globally.
// To avoid breaking existing users and custom plugins, import jQuery globally without ES module. // To avoid breaking existing users and custom plugins, import jQuery globally without ES module.
+1 -1
View File
@@ -55,7 +55,7 @@ import {initRepositorySearch} from './features/repo-search.ts';
import {initColorPickers} from './features/colorpicker.ts'; import {initColorPickers} from './features/colorpicker.ts';
import {initAdminSelfCheck} from './features/admin/selfcheck.ts'; import {initAdminSelfCheck} from './features/admin/selfcheck.ts';
import {initOAuth2SettingsDisableCheckbox} from './features/oauth2-settings.ts'; import {initOAuth2SettingsDisableCheckbox} from './features/oauth2-settings.ts';
import {initGlobalFetchAction} from './features/common-fetch-action.ts'; import {initGlobalFetchAction} from './modules/fetch-action.ts';
import {initCommmPageComponents, initGlobalComponent, initGlobalDropdown, initGlobalInput} from './features/common-page.ts'; import {initCommmPageComponents, initGlobalComponent, initGlobalDropdown, initGlobalInput} from './features/common-page.ts';
import {initGlobalButtonClickOnEnter, initGlobalButtons} from './features/common-button.ts'; import {initGlobalButtonClickOnEnter, initGlobalButtons} from './features/common-button.ts';
import {initGlobalComboMarkdownEditor, initGlobalEnterQuickSubmit, initGlobalFormDirtyLeaveConfirm} from './features/common-form.ts'; import {initGlobalComboMarkdownEditor, initGlobalEnterQuickSubmit, initGlobalFormDirtyLeaveConfirm} from './features/common-form.ts';
+2 -4
View File
@@ -29,15 +29,13 @@ function scrollToAnchor(encodedId?: string): void {
if (!elemId) return; if (!elemId) return;
const prefixedId = addPrefix(elemId); const prefixedId = addPrefix(elemId);
// eslint-disable-next-line unicorn/prefer-query-selector let el = document.querySelector<HTMLElement>(`#${CSS.escape(prefixedId)}`);
let el = document.getElementById(prefixedId);
// check for matching user-generated `a[name]` // check for matching user-generated `a[name]`
el = el ?? document.querySelector(`a[name="${CSS.escape(prefixedId)}"]`); el = el ?? document.querySelector(`a[name="${CSS.escape(prefixedId)}"]`);
// compat for links with old 'user-content-' prefixed hashes // compat for links with old 'user-content-' prefixed hashes
// eslint-disable-next-line unicorn/prefer-query-selector el = (!el && hasPrefix(elemId)) ? document.querySelector<HTMLElement>(`#${CSS.escape(elemId)}`) : el;
el = (!el && hasPrefix(elemId)) ? document.getElementById(elemId) : el;
el?.scrollIntoView(); el?.scrollIntoView();
} }
+1 -1
View File
@@ -24,7 +24,7 @@ describe('navigateToIframeLink', () => {
const navigations = captureNavigations(); const navigations = captureNavigations();
const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null); const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined); const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
// eslint-disable-next-line no-script-url // eslint-disable-next-line no-script-url -- the test asserts that javascript: links are rejected
navigateToIframeLink('javascript:void(0);', '_blank'); navigateToIframeLink('javascript:void(0);', '_blank');
navigateToIframeLink('data:image/svg+xml;utf8,<svg></svg>', ''); navigateToIframeLink('data:image/svg+xml;utf8,<svg></svg>', '');
expect(openSpy).toHaveBeenCalledTimes(0); expect(openSpy).toHaveBeenCalledTimes(0);
@@ -1,4 +1,4 @@
import {execPseudoSelectorCommands, handleFetchActionErrorFields, handleFetchActionSuccessJson} from './common-fetch-action.ts'; import {execPseudoSelectorCommands, handleFetchActionErrorFields, handleFetchActionSuccessJson} from './fetch-action.ts';
import {createElementFromHTML} from '../utils/dom.ts'; import {createElementFromHTML} from '../utils/dom.ts';
import {captureNavigations, normalizeTestHtml} from '../utils/testhelper.ts'; import {captureNavigations, normalizeTestHtml} from '../utils/testhelper.ts';
@@ -1,10 +1,10 @@
import {GET, request} from '../modules/fetch.ts'; import {GET, request} from './fetch.ts';
import {hideToastsAll, showErrorToast} from '../modules/toast.ts'; import {hideToastsAll, showErrorToast} from './toast.ts';
import {activePageTimerRefresh, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts'; import {activePageTimerRefresh, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts';
import {errorMessage, errorName} from '../modules/errors.ts'; import {errorMessage, errorName} from './errors.ts';
import {confirmModal, createConfirmModal} from './comp/ConfirmModal.ts'; import {confirmModal, createConfirmModal} from '../features/comp/ConfirmModal.ts';
import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts'; import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts';
import {registerGlobalSelectorFunc} from '../modules/observer.ts'; import {registerGlobalSelectorFunc} from './observer.ts';
import {Idiomorph} from 'idiomorph'; import {Idiomorph} from 'idiomorph';
import {parseDom} from '../utils.ts'; import {parseDom} from '../utils.ts';
import {html} from '../utils/html.ts'; import {html} from '../utils/html.ts';
@@ -233,9 +233,8 @@ export async function submitFormFetchAction(elForm: HTMLFormElement, opts: Submi
async function confirmFetchAction(el: HTMLElement) { async function confirmFetchAction(el: HTMLElement) {
let elModal: HTMLElement | null = null; let elModal: HTMLElement | null = null;
const dataModalConfirm = el.getAttribute('data-modal-confirm') || ''; const dataModalConfirm = el.getAttribute('data-modal-confirm') || '';
if (dataModalConfirm.startsWith('#')) { if (dataModalConfirm.startsWith('#') && dataModalConfirm.length > 1) {
// eslint-disable-next-line unicorn/prefer-query-selector elModal = document.querySelector<HTMLElement>(`#${CSS.escape(dataModalConfirm.substring(1))}`);
elModal = document.getElementById(dataModalConfirm.substring(1));
if (elModal) { if (elModal) {
elModal = createElementFromHTML(elModal.outerHTML); elModal = createElementFromHTML(elModal.outerHTML);
elModal.removeAttribute('id'); elModal.removeAttribute('id');
@@ -350,8 +349,7 @@ async function fetchActionReloadOutdatedElements() {
const newPageHtml = await resp.text(); const newPageHtml = await resp.text();
const newPageDom = parseDom(newPageHtml, 'text/html'); const newPageDom = parseDom(newPageHtml, 'text/html');
for (const oldEl of outdatedElems) { for (const oldEl of outdatedElems) {
// eslint-disable-next-line unicorn/prefer-query-selector const newEl = newPageDom.querySelector<HTMLElement>(`#${CSS.escape(oldEl.id)}`);
const newEl = newPageDom.getElementById(oldEl.id);
if (newEl) { if (newEl) {
oldEl.replaceWith(newEl); oldEl.replaceWith(newEl);
} else { } else {
+1 -1
View File
@@ -18,7 +18,7 @@ export function request(url: string, {method = 'GET', data, headers = {}, ...oth
if (!headers.has('content-type') && contentType) { if (!headers.has('content-type') && contentType) {
headers.set('content-type', contentType); headers.set('content-type', contentType);
} }
return fetch(url, { // eslint-disable-line no-restricted-globals return fetch(url, { // eslint-disable-line no-restricted-globals -- this is the wrapper the rule points to
method, method,
headers, headers,
...other, ...other,
+1 -1
View File
@@ -1,4 +1,4 @@
/* eslint-disable no-restricted-globals */ /* eslint-disable no-restricted-globals -- this is the wrapper the rule points to */
// Some people deploy Gitea under a subpath, so it needs prefix to avoid local storage key conflicts. // Some people deploy Gitea under a subpath, so it needs prefix to avoid local storage key conflicts.
// And these keys are for user settings only, it also needs a specific prefix, // And these keys are for user settings only, it also needs a specific prefix,
// in case in the future there are other uses of local storage, and/or we need to clear some keys when the quota is exceeded. // in case in the future there are other uses of local storage, and/or we need to clear some keys when the quota is exceeded.
+1 -1
View File
@@ -24,7 +24,7 @@ let lastWorker: MockSharedWorker;
class MockSharedWorker { class MockSharedWorker {
port = new MockMessagePort(); port = new MockMessagePort();
// eslint-disable-next-line unicorn/no-this-assignment // eslint-disable-next-line unicorn/no-this-assignment -- the test needs a handle on the instance the module constructs
constructor() { lastWorker = this } constructor() { lastWorker = this }
addEventListener() {} addEventListener() {}
} }
+1 -1
View File
@@ -4,7 +4,7 @@ import {initSwaggerUI} from './render/swagger.ts';
async function initGiteaAPIViewer() { async function initGiteaAPIViewer() {
const elSwaggerUi = document.querySelector<HTMLElement>('#swagger-ui')!; const elSwaggerUi = document.querySelector<HTMLElement>('#swagger-ui')!;
const url = elSwaggerUi.getAttribute('data-source')!; const url = elSwaggerUi.getAttribute('data-source')!;
const res = await fetch(url); // eslint-disable-line no-restricted-globals const res = await fetch(url); // eslint-disable-line no-restricted-globals -- standalone entry, it must not pull in main site modules
// HINT: SWAGGER-CSS-IMPORT: this is used in the standalone page which already has the related CSS imported by `<link>` // HINT: SWAGGER-CSS-IMPORT: this is used in the standalone page which already has the related CSS imported by `<link>`
await initSwaggerUI(elSwaggerUi, {specText: await res.text()}); await initSwaggerUI(elSwaggerUi, {specText: await res.text()});
} }
+1 -1
View File
@@ -5,7 +5,7 @@ const pngPhys = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91
const pngEmpty = 'data:image/png;base64,'; const pngEmpty = 'data:image/png;base64,';
async function dataUriToBlob(datauri: string) { async function dataUriToBlob(datauri: string) {
return await (await globalThis.fetch(datauri)).blob(); // eslint-disable-line no-restricted-properties return await (await globalThis.fetch(datauri)).blob(); // eslint-disable-line no-restricted-properties -- decodes a data URI, the fetch wrapper adds nothing here
} }
test('pngChunks', async () => { test('pngChunks', async () => {
+1 -3
View File
@@ -236,9 +236,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
// check whether the mandatory `.overflow-menu-items` element is present initially which happens // check whether the mandatory `.overflow-menu-items` element is present initially which happens
// with Vue which renders differently than browsers. If it's not there, like in the case of browser // with Vue which renders differently than browsers. If it's not there, like in the case of browser
// template rendering, wait for its addition. // template rendering, wait for its addition.
// The eslint rule is not sophisticated enough or aware of this problem, see const menuItemsEl = this.querySelector<HTMLElement>('.overflow-menu-items'); // eslint-disable-line wc/no-child-traversal-in-connectedcallback -- the observer below covers the case the rule warns about, see https://github.com/43081j/eslint-plugin-wc/pull/130
// https://github.com/43081j/eslint-plugin-wc/pull/130
const menuItemsEl = this.querySelector<HTMLElement>('.overflow-menu-items'); // eslint-disable-line wc/no-child-traversal-in-connectedcallback
if (menuItemsEl) { if (menuItemsEl) {
this.menuItemsEl = menuItemsEl; this.menuItemsEl = menuItemsEl;
this.init(); this.init();