summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig14
-rw-r--r--.github/workflows/integration.yml3
-rw-r--r--.nvmrc2
-rw-r--r--.tool-versions4
-rw-r--r--client/simple/biome.json2
-rw-r--r--client/simple/package-lock.json1842
-rw-r--r--client/simple/package.json26
-rw-r--r--client/simple/src/js/head/00_init.js19
-rw-r--r--client/simple/src/js/main/00_toolkit.js178
-rw-r--r--client/simple/src/js/main/00_toolkit.ts118
-rw-r--r--client/simple/src/js/main/index.ts13
-rw-r--r--client/simple/src/js/main/infinite_scroll.js84
-rw-r--r--client/simple/src/js/main/infinite_scroll.ts108
-rw-r--r--client/simple/src/js/main/keyboard.js473
-rw-r--r--client/simple/src/js/main/keyboard.ts469
-rw-r--r--client/simple/src/js/main/mapresult.js77
-rw-r--r--client/simple/src/js/main/mapresult.ts89
-rw-r--r--client/simple/src/js/main/preferences.js52
-rw-r--r--client/simple/src/js/main/preferences.ts71
-rw-r--r--client/simple/src/js/main/results.js182
-rw-r--r--client/simple/src/js/main/results.ts181
-rw-r--r--client/simple/src/js/main/search.js197
-rw-r--r--client/simple/src/js/main/search.ts233
-rw-r--r--client/simple/src/js/pkg/ol.ts26
-rw-r--r--client/simple/src/js/searxng.head.js1
-rw-r--r--client/simple/src/js/searxng.js7
-rw-r--r--client/simple/src/less/code.less1
-rw-r--r--client/simple/theme_icons.ts (renamed from client/simple/theme_icons.js)25
-rw-r--r--client/simple/tools/img.ts (renamed from client/simple/tools/img.js)38
-rw-r--r--client/simple/tools/jinja_svg_catalog.ts (renamed from client/simple/tools/jinja_svg_catalog.js)105
-rw-r--r--client/simple/tools/plg.js44
-rw-r--r--client/simple/tools/plg.ts43
-rw-r--r--client/simple/tsconfig.json40
-rw-r--r--client/simple/vite.config.ts (renamed from client/simple/vite.config.js)134
-rw-r--r--docs/dev/makefile.rst6
-rw-r--r--package.json1
-rw-r--r--searx/templates/simple/base.html16
-rwxr-xr-xutils/lib_nvm.sh4
-rwxr-xr-xutils/lib_sxng_node.sh2
39 files changed, 2551 insertions, 2379 deletions
diff --git a/.editorconfig b/.editorconfig
index 8c626c425..cdacd2d2d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -36,12 +36,24 @@ indent_size = 2
[*.js]
indent_size = 2
+[*.ts]
+indent_size = 2
+
[*.json]
indent_size = 2
insert_final_newline = ignore
+[*.map]
+indent_size = ignore
+insert_final_newline = ignore
+
# Minified JavaScript files shouldn't be changed
-[**.min.js]
+[*.min.js]
+indent_style = ignore
+insert_final_newline = ignore
+
+# Minified CSS files shouldn't be changed
+[*.min.css]
indent_style = ignore
insert_final_newline = ignore
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 0dde34f66..8aa40bc3d 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -92,5 +92,8 @@ jobs:
- name: Setup venv
run: make V=1 install
+ - name: Lint
+ run: make themes.lint
+
- name: Build
run: make themes.all
diff --git a/.nvmrc b/.nvmrc
index 696e6df35..a45fd52cc 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v23.5 \ No newline at end of file
+24
diff --git a/.tool-versions b/.tool-versions
index 1b928297d..5548f7707 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,4 +1,4 @@
-nodejs 23.5.0
+nodejs 24.3.0
python 3.13.1
shellcheck 0.10.0
-sqlite 3.47.2 \ No newline at end of file
+sqlite 3.47.2
diff --git a/client/simple/biome.json b/client/simple/biome.json
index ebe7ee7dc..5f27799c1 100644
--- a/client/simple/biome.json
+++ b/client/simple/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.1.1/schema.json",
"files": {
"includes": ["**", "!dist/**", "!node_modules/**"],
"ignoreUnknown": true
diff --git a/client/simple/package-lock.json b/client/simple/package-lock.json
index a910835ea..e04f87f5f 100644
--- a/client/simple/package-lock.json
+++ b/client/simple/package-lock.json
@@ -7,20 +7,25 @@
"name": "simple",
"license": "AGPL-3.0",
"devDependencies": {
- "@biomejs/biome": "~2.0.6",
+ "@biomejs/biome": "~2.1.0",
+ "@types/node": "^24.0.0",
+ "browserslist": "^4.25.1",
+ "browserslist-to-esbuild": "^2.1.1",
"edge.js": "^6.2.1",
"ionicons": "^8.0.10",
- "leaflet": "^1.9.4",
"less": "^4.3.0",
+ "lightningcss": "^1.30.1",
"normalize.css": "^8.0.1",
- "sharp": "^0.34.2",
+ "ol": "^10.6.1",
+ "sharp": "^0.34.3",
"sort-package-json": "^3.4.0",
"stylelint": "^16.21.1",
"stylelint-config-standard-less": "^3.0.1",
"stylelint-prettier": "^5.0.3",
"svgo": "^4.0.0",
"swiped-events": "^1.2.0",
- "vite": "^7.0.2",
+ "typescript": "~5.8.3",
+ "vite": "npm:rolldown-vite@~7.0.8",
"vite-plugin-static-copy": "^3.1.0"
}
},
@@ -50,9 +55,9 @@
}
},
"node_modules/@biomejs/biome": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.0.6.tgz",
- "integrity": "sha512-RRP+9cdh5qwe2t0gORwXaa27oTOiQRQvrFf49x2PA1tnpsyU7FIHX4ZOFMtBC4QNtyWsN7Dqkf5EDbg4X+9iqA==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.1.1.tgz",
+ "integrity": "sha512-HFGYkxG714KzG+8tvtXCJ1t1qXQMzgWzfvQaUjxN6UeKv+KvMEuliInnbZLJm6DXFXwqVi6446EGI0sGBLIYng==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
@@ -66,20 +71,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "2.0.6",
- "@biomejs/cli-darwin-x64": "2.0.6",
- "@biomejs/cli-linux-arm64": "2.0.6",
- "@biomejs/cli-linux-arm64-musl": "2.0.6",
- "@biomejs/cli-linux-x64": "2.0.6",
- "@biomejs/cli-linux-x64-musl": "2.0.6",
- "@biomejs/cli-win32-arm64": "2.0.6",
- "@biomejs/cli-win32-x64": "2.0.6"
+ "@biomejs/cli-darwin-arm64": "2.1.1",
+ "@biomejs/cli-darwin-x64": "2.1.1",
+ "@biomejs/cli-linux-arm64": "2.1.1",
+ "@biomejs/cli-linux-arm64-musl": "2.1.1",
+ "@biomejs/cli-linux-x64": "2.1.1",
+ "@biomejs/cli-linux-x64-musl": "2.1.1",
+ "@biomejs/cli-win32-arm64": "2.1.1",
+ "@biomejs/cli-win32-x64": "2.1.1"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.0.6.tgz",
- "integrity": "sha512-AzdiNNjNzsE6LfqWyBvcL29uWoIuZUkndu+wwlXW13EKcBHbbKjNQEZIJKYDc6IL+p7bmWGx3v9ZtcRyIoIz5A==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.1.1.tgz",
+ "integrity": "sha512-2Muinu5ok4tWxq4nu5l19el48cwCY/vzvI7Vjbkf3CYIQkjxZLyj0Ad37Jv2OtlXYaLvv+Sfu1hFeXt/JwRRXQ==",
"cpu": [
"arm64"
],
@@ -94,9 +99,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.0.6.tgz",
- "integrity": "sha512-wJjjP4E7bO4WJmiQaLnsdXMa516dbtC6542qeRkyJg0MqMXP0fvs4gdsHhZ7p9XWTAmGIjZHFKXdsjBvKGIJJQ==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.1.1.tgz",
+ "integrity": "sha512-cC8HM5lrgKQXLAK+6Iz2FrYW5A62pAAX6KAnRlEyLb+Q3+Kr6ur/sSuoIacqlp1yvmjHJqjYfZjPvHWnqxoEIA==",
"cpu": [
"x64"
],
@@ -111,9 +116,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.0.6.tgz",
- "integrity": "sha512-ZSVf6TYo5rNMUHIW1tww+rs/krol7U5A1Is/yzWyHVZguuB0lBnIodqyFuwCNqG9aJGyk7xIMS8HG0qGUPz0SA==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.1.1.tgz",
+ "integrity": "sha512-tw4BEbhAUkWPe4WBr6IX04DJo+2jz5qpPzpW/SWvqMjb9QuHY8+J0M23V8EPY/zWU4IG8Ui0XESapR1CB49Q7g==",
"cpu": [
"arm64"
],
@@ -128,9 +133,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.6.tgz",
- "integrity": "sha512-CVPEMlin3bW49sBqLBg2x016Pws7eUXA27XYDFlEtponD0luYjg2zQaMJ2nOqlkKG9fqzzkamdYxHdMDc2gZFw==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.1.1.tgz",
+ "integrity": "sha512-/7FBLnTswu4jgV9ttI3AMIdDGqVEPIZd8I5u2D4tfCoj8rl9dnjrEQbAIDlWhUXdyWlFSz8JypH3swU9h9P+2A==",
"cpu": [
"arm64"
],
@@ -145,9 +150,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.0.6.tgz",
- "integrity": "sha512-geM1MkHTV1Kh2Cs/Xzot9BOF3WBacihw6bkEmxkz4nSga8B9/hWy5BDiOG3gHDGIBa8WxT0nzsJs2f/hPqQIQw==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.1.1.tgz",
+ "integrity": "sha512-3WJ1GKjU7NzZb6RTbwLB59v9cTIlzjbiFLDB0z4376TkDqoNYilJaC37IomCr/aXwuU8QKkrYoHrgpSq5ffJ4Q==",
"cpu": [
"x64"
],
@@ -162,9 +167,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.6.tgz",
- "integrity": "sha512-mKHE/e954hR/hSnAcJSjkf4xGqZc/53Kh39HVW1EgO5iFi0JutTN07TSjEMg616julRtfSNJi0KNyxvc30Y4rQ==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.1.1.tgz",
+ "integrity": "sha512-kUu+loNI3OCD2c12cUt7M5yaaSjDnGIksZwKnueubX6c/HWUyi/0mPbTBHR49Me3F0KKjWiKM+ZOjsmC+lUt9g==",
"cpu": [
"x64"
],
@@ -179,9 +184,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.0.6.tgz",
- "integrity": "sha512-290V4oSFoKaprKE1zkYVsDfAdn0An5DowZ+GIABgjoq1ndhvNxkJcpxPsiYtT7slbVe3xmlT0ncdfOsN7KruzA==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.1.1.tgz",
+ "integrity": "sha512-vEHK0v0oW+E6RUWLoxb2isI3rZo57OX9ZNyyGH701fZPj6Il0Rn1f5DMNyCmyflMwTnIQstEbs7n2BxYSqQx4Q==",
"cpu": [
"arm64"
],
@@ -196,9 +201,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.0.6.tgz",
- "integrity": "sha512-bfM1Bce0d69Ao7pjTjUS+AWSZ02+5UHdiAP85Th8e9yV5xzw6JrHXbL5YWlcEKQ84FIZMdDc7ncuti1wd2sdbw==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.1.1.tgz",
+ "integrity": "sha512-i2PKdn70kY++KEF/zkQFvQfX1e8SkA8hq4BgC+yE9dZqyLzB/XStY2MvwI3qswlRgnGpgncgqe0QYKVS1blksg==",
"cpu": [
"x64"
],
@@ -313,446 +318,44 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/@emnapi/runtime": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
- "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
+ "node_modules/@emnapi/core": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.4.tgz",
+ "integrity": "sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
+ "@emnapi/wasi-threads": "1.0.3",
"tslib": "^2.4.0"
}
},
- "node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
- "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
- "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
- "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
- "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
- "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
- "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
- "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
- "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
- "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
- "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
- "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
- "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
- "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
- "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
- "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
- "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
- "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
- "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
- "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
- "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
- "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
- "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
- "cpu": [
- "ia32"
- ],
+ "node_modules/@emnapi/runtime": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz",
+ "integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==",
"dev": true,
"license": "MIT",
"optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "tslib": "^2.4.0"
}
},
- "node_modules/@esbuild/win32-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
- "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
- "cpu": [
- "x64"
- ],
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.3.tgz",
+ "integrity": "sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==",
"dev": true,
"license": "MIT",
"optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "tslib": "^2.4.0"
}
},
"node_modules/@img/sharp-darwin-arm64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz",
- "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz",
+ "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==",
"cpu": [
"arm64"
],
@@ -769,13 +372,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-arm64": "1.1.0"
+ "@img/sharp-libvips-darwin-arm64": "1.2.0"
}
},
"node_modules/@img/sharp-darwin-x64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz",
- "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz",
+ "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==",
"cpu": [
"x64"
],
@@ -792,13 +395,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-x64": "1.1.0"
+ "@img/sharp-libvips-darwin-x64": "1.2.0"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz",
- "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz",
+ "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==",
"cpu": [
"arm64"
],
@@ -813,9 +416,9 @@
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz",
- "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz",
+ "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==",
"cpu": [
"x64"
],
@@ -830,9 +433,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz",
- "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz",
+ "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==",
"cpu": [
"arm"
],
@@ -847,9 +450,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz",
- "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz",
+ "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==",
"cpu": [
"arm64"
],
@@ -864,9 +467,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz",
- "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz",
+ "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==",
"cpu": [
"ppc64"
],
@@ -881,9 +484,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz",
- "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz",
+ "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==",
"cpu": [
"s390x"
],
@@ -898,9 +501,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz",
- "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz",
+ "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==",
"cpu": [
"x64"
],
@@ -915,9 +518,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz",
- "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz",
+ "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==",
"cpu": [
"arm64"
],
@@ -932,9 +535,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz",
- "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz",
+ "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==",
"cpu": [
"x64"
],
@@ -949,9 +552,9 @@
}
},
"node_modules/@img/sharp-linux-arm": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz",
- "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz",
+ "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==",
"cpu": [
"arm"
],
@@ -968,13 +571,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm": "1.1.0"
+ "@img/sharp-libvips-linux-arm": "1.2.0"
}
},
"node_modules/@img/sharp-linux-arm64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz",
- "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz",
+ "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==",
"cpu": [
"arm64"
],
@@ -991,13 +594,36 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm64": "1.1.0"
+ "@img/sharp-libvips-linux-arm64": "1.2.0"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz",
+ "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.0"
}
},
"node_modules/@img/sharp-linux-s390x": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz",
- "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz",
+ "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==",
"cpu": [
"s390x"
],
@@ -1014,13 +640,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-s390x": "1.1.0"
+ "@img/sharp-libvips-linux-s390x": "1.2.0"
}
},
"node_modules/@img/sharp-linux-x64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz",
- "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz",
+ "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==",
"cpu": [
"x64"
],
@@ -1037,13 +663,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-x64": "1.1.0"
+ "@img/sharp-libvips-linux-x64": "1.2.0"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz",
- "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz",
+ "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==",
"cpu": [
"arm64"
],
@@ -1060,13 +686,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-arm64": "1.1.0"
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.0"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz",
- "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz",
+ "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==",
"cpu": [
"x64"
],
@@ -1083,13 +709,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-x64": "1.1.0"
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.0"
}
},
"node_modules/@img/sharp-wasm32": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz",
- "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz",
+ "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==",
"cpu": [
"wasm32"
],
@@ -1097,7 +723,7 @@
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
- "@emnapi/runtime": "^1.4.3"
+ "@emnapi/runtime": "^1.4.4"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -1107,9 +733,9 @@
}
},
"node_modules/@img/sharp-win32-arm64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz",
- "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz",
+ "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==",
"cpu": [
"arm64"
],
@@ -1127,9 +753,9 @@
}
},
"node_modules/@img/sharp-win32-ia32": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz",
- "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz",
+ "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==",
"cpu": [
"ia32"
],
@@ -1147,9 +773,9 @@
}
},
"node_modules/@img/sharp-win32-x64": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz",
- "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz",
+ "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==",
"cpu": [
"x64"
],
@@ -1186,6 +812,19 @@
"node": ">=8"
}
},
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+ "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.10.0"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1224,16 +863,40 @@
"node": ">= 8"
}
},
- "node_modules/@poppinss/exception": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.1.tgz",
- "integrity": "sha512-aQypoot0HPSJa6gDPEPTntc1GT6QINrSbgRlRhadGW2WaYqUK3tK4Bw9SBMZXhmxd3GeAlZjVcODHgiu+THY7A==",
+ "node_modules/@oxc-project/runtime": {
+ "version": "0.76.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.76.0.tgz",
+ "integrity": "sha512-17iezP/BukiovZZR7lp6fZZjNTOmodCWQKkI7sn2sOB1TiccRWzO2bpxnE94jhg8l+nBRMrwnM/cjFCr23winw==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@oxc-project/types": {
+ "version": "0.76.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.76.0.tgz",
+ "integrity": "sha512-CH3THIrSViKal8yV/Wh3FK0pFhp40nzW1MUDCik9fNuid2D/7JJXKJnfFOAvMxInGXDlvmgT6ACAzrl47TqzkQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@petamoriken/float16": {
+ "version": "3.9.2",
+ "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz",
+ "integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@poppinss/exception": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.2.tgz",
+ "integrity": "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@poppinss/inspect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@poppinss/inspect/-/inspect-1.0.1.tgz",
@@ -1245,14 +908,11 @@
}
},
"node_modules/@poppinss/macroable": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.0.4.tgz",
- "integrity": "sha512-ct43jurbe7lsUX5eIrj4ijO3j/6zIPp7CDnFWXDs7UPAbw1Pu1iH3oAmFdP4jcskKJBURH5M9oTtyeiUXyHX8Q==",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.0.5.tgz",
+ "integrity": "sha512-6u61y1HHd090MEk1Av0/1btDmm2Hh/+XoJj+HgFYRh9koUPI822ybJbwLHuqjLNCiY+o1gRykg2igEqOf/VBZw==",
"dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18.16.0"
- }
+ "license": "MIT"
},
"node_modules/@poppinss/object-builder": {
"version": "1.1.0",
@@ -1265,9 +925,9 @@
}
},
"node_modules/@poppinss/string": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@poppinss/string/-/string-1.6.0.tgz",
- "integrity": "sha512-HfAf9VqTvo31BsruwgwEauQ316RNODdryk6QgYZo4qTV50s0h1H9HmIr+QjwwI3u4Sz7r4Q1dd1EVaLB7pWlaw==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@poppinss/string/-/string-1.7.0.tgz",
+ "integrity": "sha512-IuCtWaUwmJeAdby0n1a5cTYsBLe7fPymdc4oNTTl1b6l+Ok+14XpSX0ILOEU6UtZ9D2XI3f4TVUh4Titkk1xgw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1299,66 +959,66 @@
"node": ">=18.16.0"
}
},
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz",
- "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==",
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.26.tgz",
+ "integrity": "sha512-I73Ej+PVoCJiYQHpy45CHKkLgFqrYv9O1CUJs6TIav6f8f9WAVeN/k0YXrs0tgMO20AfsyEN8zenz2wprVWOYQ==",
"cpu": [
- "arm"
+ "arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "android"
+ "darwin"
]
},
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz",
- "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==",
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.26.tgz",
+ "integrity": "sha512-IcXzfO2/9bnm6WfCNmGxBiD1kQQdA0pTjjGcjvglUub8H6RlEY0tz+IIQxUirsl/++84S0PkCuafAxZi8Am8fg==",
"cpu": [
- "arm64"
+ "x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "android"
+ "darwin"
]
},
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.34.9",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz",
- "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==",
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.26.tgz",
+ "integrity": "sha512-foLJNqEFdvwFm2MXDFxgywxJMic+wovbpEyszlz5K/sUbN7sP2+NJ7MZAUMHuggiswB4Rt1HqRLYKy26zJev8g==",
"cpu": [
- "arm64"
+ "x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "darwin"
+ "freebsd"
]
},
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.34.9",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz",
- "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==",
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.26.tgz",
+ "integrity": "sha512-1BWDpLtujfZCvWAcfIamqHGWo2+VnPWvpZQR0DL5qNit6cu3FC0sRZ+bZzTUK0QWDTA7nUy5RR9fUTL2PQxH2g==",
"cpu": [
- "x64"
+ "arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "darwin"
+ "linux"
]
},
- "node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz",
- "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==",
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.26.tgz",
+ "integrity": "sha512-lg6DVwciFb7sIw0ONDHeLhRuFQl/wz+J26bxfVOVzVoQ7Zgl07gDklv7q96W7SRDAjlG/20flBOexdiPim/I3g==",
"cpu": [
"arm64"
],
@@ -1366,29 +1026,29 @@
"license": "MIT",
"optional": true,
"os": [
- "freebsd"
+ "linux"
]
},
- "node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz",
- "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==",
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.26.tgz",
+ "integrity": "sha512-0X14trOBVtU13Y0XYeb8EvOvb3/TxJVOmalDakEID/UUX9qkvOmlU0fvoDVmsnhH6yx23bDlpmOj0f8V3BCgIw==",
"cpu": [
- "x64"
+ "arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "freebsd"
+ "linux"
]
},
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz",
- "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==",
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.26.tgz",
+ "integrity": "sha512-stb8XloM+N3hSKUs6kS5tNqrlTGsCoYuh9emFZtTovfFzzdFYevgXoOdeGoXv9KkPh5B7MOMl4/7c+WaX46Opg==",
"cpu": [
- "arm"
+ "x64"
],
"dev": true,
"license": "MIT",
@@ -1397,12 +1057,12 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz",
- "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==",
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.26.tgz",
+ "integrity": "sha512-5udEpAS5IUy2t74d/m40JUYyk3Ga8QXQDvK7eGqDDOwz8/7Piq0kCwmNuLnpSRiqbXNP8mnVlvtIcASJUEtRPA==",
"cpu": [
- "arm"
+ "x64"
],
"dev": true,
"license": "MIT",
@@ -1411,10 +1071,27 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.34.9",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz",
- "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==",
+ "node_modules/@rolldown/binding-wasm32-wasi": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.26.tgz",
+ "integrity": "sha512-Is5tTdScXXQzslj7+jCFncPoRNARJ/+fYt/C9+Yx0QQ67/m8pGPLFoCzIKmJQZ8QHzOfq5ML4CQlMgBbCFlZqQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^0.2.10"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.26.tgz",
+ "integrity": "sha512-bH+TB+/8Z/95cxGws0fH995HsbsopVYdGcuM1Z/Hnqe7KPLkhqkubsambHQYd1V/QNbLzAgJ0nMAFLyBrwFZZQ==",
"cpu": [
"arm64"
],
@@ -1422,71 +1099,78 @@
"license": "MIT",
"optional": true,
"os": [
- "linux"
+ "win32"
]
},
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.34.9",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz",
- "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==",
+ "node_modules/@rolldown/binding-win32-ia32-msvc": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.26.tgz",
+ "integrity": "sha512-Nsg7ZzfwLHwKGneuNHEpqdBekmZA5pzVOuFx5R8EVyva8dg+sgtDHQRmiVSVYe25YYISNFXDSuHKwNhrWI4HWA==",
"cpu": [
- "arm64"
+ "ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "linux"
+ "win32"
]
},
- "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz",
- "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==",
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.26.tgz",
+ "integrity": "sha512-NE5Btf10Fu3IbpHxrlRkgcO/d05iEpbIiP/XdMYW7Lc9BGSgE4f8njUHnM0V2XJKyXkC1fqv/uHSEw2dCNgzxQ==",
"cpu": [
- "loong64"
+ "x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "linux"
+ "win32"
]
},
- "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz",
- "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==",
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.26.tgz",
+ "integrity": "sha512-r/5po89voz/QRPDmoErL10+hVuTAuz1SHvokx+yWBlOIPB5C41jC7QhLqq9kaebx/+EHyoV3z22/qBfX81Ns8A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz",
+ "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==",
"cpu": [
- "ppc64"
+ "arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "linux"
+ "darwin"
]
},
- "node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz",
- "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==",
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz",
+ "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==",
"cpu": [
- "riscv64"
+ "x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
- "linux"
+ "darwin"
]
},
- "node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz",
- "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==",
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz",
+ "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==",
"cpu": [
- "riscv64"
+ "arm64"
],
"dev": true,
"license": "MIT",
@@ -1495,12 +1179,12 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz",
- "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==",
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.34.9",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz",
+ "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==",
"cpu": [
- "s390x"
+ "arm64"
],
"dev": true,
"license": "MIT",
@@ -1551,20 +1235,6 @@
"win32"
]
},
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz",
- "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz",
@@ -1580,9 +1250,9 @@
]
},
"node_modules/@stencil/core": {
- "version": "4.35.1",
- "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.35.1.tgz",
- "integrity": "sha512-u65m3TbzOtpn679gUV4Yvi8YpInhRJ62js30a7YtXief9Ej/vzrhwDE22U0w4DMWJOYwAsJl133BUaZkWwnmzg==",
+ "version": "4.35.3",
+ "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.35.3.tgz",
+ "integrity": "sha512-RH5/I+amV31QI8TMXhXkAkjzs2eod6Y07jkUYTl9kMB+X7c5wUpv95Y/2LtcAx0Rqdhh4SHbJiwpr0ApBZmv0g==",
"dev": true,
"license": "MIT",
"bin": {
@@ -1603,6 +1273,17 @@
"@rollup/rollup-win32-x64-msvc": "4.34.9"
}
},
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz",
+ "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@types/bytes": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz",
@@ -1610,12 +1291,15 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/estree": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
- "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "node_modules/@types/node": {
+ "version": "24.0.13",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz",
+ "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.8.0"
+ }
},
"node_modules/@types/pluralize": {
"version": "0.0.33",
@@ -1624,6 +1308,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/rbush": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-4.0.0.tgz",
+ "integrity": "sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -1680,6 +1371,16 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/ansis": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz",
+ "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -1792,6 +1493,58 @@
"node": ">=8"
}
},
+ "node_modules/browserslist": {
+ "version": "4.25.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
+ "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001726",
+ "electron-to-chromium": "^1.5.173",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/browserslist-to-esbuild": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/browserslist-to-esbuild/-/browserslist-to-esbuild-2.1.1.tgz",
+ "integrity": "sha512-KN+mty6C3e9AN8Z5dI1xeN15ExcRNeISoC3g7V0Kax/MMF9MSoYA2G7lkTTcVUFntiEjkpI0HNgqJC1NjdyNUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "meow": "^13.0.0"
+ },
+ "bin": {
+ "browserslist-to-esbuild": "cli/index.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "browserslist": "*"
+ }
+ },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -1828,14 +1581,14 @@
}
},
"node_modules/cacheable": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.0.tgz",
- "integrity": "sha512-SSgQTAnhd7WlJXnGlIi4jJJOiHzgnM5wRMEPaXAU4kECTAMpBoYKoZ9i5zHmclIEZbxcu3j7yY/CF8DTmwIsHg==",
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.1.tgz",
+ "integrity": "sha512-Fa2BZY0CS9F0PFc/6aVA6tgpOdw+hmv9dkZOlHXII5v5Hw+meJBIWDcPrG9q/dXxGcNbym5t77fzmawrBQfTmQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "hookified": "^1.8.2",
- "keyv": "^5.3.3"
+ "hookified": "^1.10.0",
+ "keyv": "^5.3.4"
}
},
"node_modules/callsites": {
@@ -1848,6 +1601,27 @@
"node": ">=6"
}
},
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001727",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
+ "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
"node_modules/case-anything": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/case-anything/-/case-anything-3.1.2.tgz",
@@ -2221,6 +1995,13 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
+ "node_modules/earcut": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz",
+ "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/edge-error": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/edge-error/-/edge-error-4.0.2.tgz",
@@ -2285,6 +2066,13 @@
"node": ">=18.16.0"
}
},
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.182",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz",
+ "integrity": "sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2346,45 +2134,14 @@
"dev": true,
"license": "MIT"
},
- "node_modules/esbuild": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
- "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
- "hasInstallScript": true,
"license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
"engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.5",
- "@esbuild/android-arm": "0.25.5",
- "@esbuild/android-arm64": "0.25.5",
- "@esbuild/android-x64": "0.25.5",
- "@esbuild/darwin-arm64": "0.25.5",
- "@esbuild/darwin-x64": "0.25.5",
- "@esbuild/freebsd-arm64": "0.25.5",
- "@esbuild/freebsd-x64": "0.25.5",
- "@esbuild/linux-arm": "0.25.5",
- "@esbuild/linux-arm64": "0.25.5",
- "@esbuild/linux-ia32": "0.25.5",
- "@esbuild/linux-loong64": "0.25.5",
- "@esbuild/linux-mips64el": "0.25.5",
- "@esbuild/linux-ppc64": "0.25.5",
- "@esbuild/linux-riscv64": "0.25.5",
- "@esbuild/linux-s390x": "0.25.5",
- "@esbuild/linux-x64": "0.25.5",
- "@esbuild/netbsd-arm64": "0.25.5",
- "@esbuild/netbsd-x64": "0.25.5",
- "@esbuild/openbsd-arm64": "0.25.5",
- "@esbuild/openbsd-x64": "0.25.5",
- "@esbuild/sunos-x64": "0.25.5",
- "@esbuild/win32-arm64": "0.25.5",
- "@esbuild/win32-ia32": "0.25.5",
- "@esbuild/win32-x64": "0.25.5"
+ "node": ">=6"
}
},
"node_modules/escape-goat": {
@@ -2492,15 +2249,15 @@
}
},
"node_modules/flat-cache": {
- "version": "6.1.10",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.10.tgz",
- "integrity": "sha512-B6/v1f0NwjxzmeOhzfXPGWpKBVA207LS7lehaVKQnFrVktcFRfkzjZZ2gwj2i1TkEUMQht7ZMJbABUT5N+V1Nw==",
+ "version": "6.1.11",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.11.tgz",
+ "integrity": "sha512-zfOAns94mp7bHG/vCn9Ru2eDCmIxVQ5dELUHKjHfDEOJmHNzE+uGa6208kfkgmtym4a0FFjEuFksCXFacbVhSg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cacheable": "^1.10.0",
+ "cacheable": "^1.10.1",
"flatted": "^3.3.3",
- "hookified": "^1.9.1"
+ "hookified": "^1.10.0"
}
},
"node_modules/flatted": {
@@ -2557,6 +2314,26 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/geotiff": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.1.3.tgz",
+ "integrity": "sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@petamoriken/float16": "^3.4.7",
+ "lerc": "^3.0.0",
+ "pako": "^2.0.4",
+ "parse-headers": "^2.0.2",
+ "quick-lru": "^6.1.1",
+ "web-worker": "^1.2.0",
+ "xml-utils": "^1.0.2",
+ "zstddec": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10.19"
+ }
+ },
"node_modules/git-hooks-list": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.1.1.tgz",
@@ -2674,9 +2451,9 @@
}
},
"node_modules/hookified": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.9.1.tgz",
- "integrity": "sha512-u3pxtGhKjcSXnGm1CX6aXS9xew535j3lkOCegbA6jdyh0BaAjTbXI4aslKstCr6zUNtoCxFGFKwjbSHdGrMB8g==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.10.0.tgz",
+ "integrity": "sha512-dJw0492Iddsj56U1JsSTm9E/0B/29a1AuoSLRAte8vQg/kaTGF3IgjEWT8c8yG4cC10+HisE1x5QAwR0Xwc+DA==",
"dev": true,
"license": "MIT"
},
@@ -2797,12 +2574,13 @@
"license": "ISC"
},
"node_modules/ionicons": {
- "version": "8.0.10",
- "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.10.tgz",
- "integrity": "sha512-w+6VmjcRwlAtryXzM+BOlIHKyJYlrfbIIYWW4cU0BM8OECoTn/KF8ecOE5j4401z5/FcmHf/yXol1xinKuPM8g==",
+ "version": "8.0.13",
+ "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.13.tgz",
+ "integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@stencil/core": "^4.30.0"
+ "@stencil/core": "^4.35.3"
}
},
"node_modules/is-arrayish": {
@@ -2986,12 +2764,12 @@
"dev": true,
"license": "MIT"
},
- "node_modules/leaflet": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
- "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
+ "node_modules/lerc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz",
+ "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==",
"dev": true,
- "license": "BSD-2-Clause"
+ "license": "Apache-2.0"
},
"node_modules/less": {
"version": "4.3.0",
@@ -3020,6 +2798,245 @@
"source-map": "~0.6.0"
}
},
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -3162,6 +3179,13 @@
"node": ">= 4.4.x"
}
},
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -3192,6 +3216,24 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
+ "node_modules/ol": {
+ "version": "10.6.1",
+ "resolved": "https://registry.npmjs.org/ol/-/ol-10.6.1.tgz",
+ "integrity": "sha512-xp174YOwPeLj7c7/8TCIEHQ4d41tgTDDhdv6SqNdySsql5/MaFJEJkjlsYcvOPt7xA6vrum/QG4UdJ0iCGT1cg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@types/rbush": "4.0.0",
+ "earcut": "^3.0.0",
+ "geotiff": "^2.1.3",
+ "pbf": "4.0.1",
+ "rbush": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/openlayers"
+ }
+ },
"node_modules/p-map": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz",
@@ -3205,6 +3247,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/pako": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+ "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
+ "dev": true,
+ "license": "(MIT AND Zlib)"
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -3218,6 +3267,13 @@
"node": ">=6"
}
},
+ "node_modules/parse-headers": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz",
+ "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -3257,6 +3313,19 @@
"node": ">=8"
}
},
+ "node_modules/pbf": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz",
+ "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "resolve-protobuf-schema": "^2.1.0"
+ },
+ "bin": {
+ "pbf": "bin/pbf"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -3436,6 +3505,13 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/protocol-buffers-schema": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
+ "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
@@ -3465,6 +3541,36 @@
],
"license": "MIT"
},
+ "node_modules/quick-lru": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz",
+ "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/quickselect": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/rbush": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz",
+ "integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "quickselect": "^3.0.0"
+ }
+ },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -3498,6 +3604,16 @@
"node": ">=8"
}
},
+ "node_modules/resolve-protobuf-schema": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
+ "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "protocol-buffers-schema": "^3.3.1"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -3509,158 +3625,36 @@
"node": ">=0.10.0"
}
},
- "node_modules/rollup": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz",
- "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==",
+ "node_modules/rolldown": {
+ "version": "1.0.0-beta.26",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.26.tgz",
+ "integrity": "sha512-2rad1JDFst/GD1J86RuqN1SIP8O8Xv4UbqNyKaVayXTjgF0D6HpvTnUZ1RQ6tANpZweGmq4v6Ay0uyRNEycFPw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "1.0.8"
+ "@oxc-project/runtime": "=0.76.0",
+ "@oxc-project/types": "=0.76.0",
+ "@rolldown/pluginutils": "1.0.0-beta.26",
+ "ansis": "^4.0.0"
},
"bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
+ "rolldown": "bin/cli.mjs"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.44.1",
- "@rollup/rollup-android-arm64": "4.44.1",
- "@rollup/rollup-darwin-arm64": "4.44.1",
- "@rollup/rollup-darwin-x64": "4.44.1",
- "@rollup/rollup-freebsd-arm64": "4.44.1",
- "@rollup/rollup-freebsd-x64": "4.44.1",
- "@rollup/rollup-linux-arm-gnueabihf": "4.44.1",
- "@rollup/rollup-linux-arm-musleabihf": "4.44.1",
- "@rollup/rollup-linux-arm64-gnu": "4.44.1",
- "@rollup/rollup-linux-arm64-musl": "4.44.1",
- "@rollup/rollup-linux-loongarch64-gnu": "4.44.1",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.44.1",
- "@rollup/rollup-linux-riscv64-gnu": "4.44.1",
- "@rollup/rollup-linux-riscv64-musl": "4.44.1",
- "@rollup/rollup-linux-s390x-gnu": "4.44.1",
- "@rollup/rollup-linux-x64-gnu": "4.44.1",
- "@rollup/rollup-linux-x64-musl": "4.44.1",
- "@rollup/rollup-win32-arm64-msvc": "4.44.1",
- "@rollup/rollup-win32-ia32-msvc": "4.44.1",
- "@rollup/rollup-win32-x64-msvc": "4.44.1",
- "fsevents": "~2.3.2"
+ "@rolldown/binding-darwin-arm64": "1.0.0-beta.26",
+ "@rolldown/binding-darwin-x64": "1.0.0-beta.26",
+ "@rolldown/binding-freebsd-x64": "1.0.0-beta.26",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.26",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.26",
+ "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.26",
+ "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.26",
+ "@rolldown/binding-linux-x64-musl": "1.0.0-beta.26",
+ "@rolldown/binding-wasm32-wasi": "1.0.0-beta.26",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.26",
+ "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.26",
+ "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.26"
}
},
- "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz",
- "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz",
- "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz",
- "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz",
- "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz",
- "integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz",
- "integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz",
- "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.44.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz",
- "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -3739,9 +3733,9 @@
}
},
"node_modules/sharp": {
- "version": "0.34.2",
- "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz",
- "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==",
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
+ "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
@@ -3757,27 +3751,28 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-darwin-arm64": "0.34.2",
- "@img/sharp-darwin-x64": "0.34.2",
- "@img/sharp-libvips-darwin-arm64": "1.1.0",
- "@img/sharp-libvips-darwin-x64": "1.1.0",
- "@img/sharp-libvips-linux-arm": "1.1.0",
- "@img/sharp-libvips-linux-arm64": "1.1.0",
- "@img/sharp-libvips-linux-ppc64": "1.1.0",
- "@img/sharp-libvips-linux-s390x": "1.1.0",
- "@img/sharp-libvips-linux-x64": "1.1.0",
- "@img/sharp-libvips-linuxmusl-arm64": "1.1.0",
- "@img/sharp-libvips-linuxmusl-x64": "1.1.0",
- "@img/sharp-linux-arm": "0.34.2",
- "@img/sharp-linux-arm64": "0.34.2",
- "@img/sharp-linux-s390x": "0.34.2",
- "@img/sharp-linux-x64": "0.34.2",
- "@img/sharp-linuxmusl-arm64": "0.34.2",
- "@img/sharp-linuxmusl-x64": "0.34.2",
- "@img/sharp-wasm32": "0.34.2",
- "@img/sharp-win32-arm64": "0.34.2",
- "@img/sharp-win32-ia32": "0.34.2",
- "@img/sharp-win32-x64": "0.34.2"
+ "@img/sharp-darwin-arm64": "0.34.3",
+ "@img/sharp-darwin-x64": "0.34.3",
+ "@img/sharp-libvips-darwin-arm64": "1.2.0",
+ "@img/sharp-libvips-darwin-x64": "1.2.0",
+ "@img/sharp-libvips-linux-arm": "1.2.0",
+ "@img/sharp-libvips-linux-arm64": "1.2.0",
+ "@img/sharp-libvips-linux-ppc64": "1.2.0",
+ "@img/sharp-libvips-linux-s390x": "1.2.0",
+ "@img/sharp-libvips-linux-x64": "1.2.0",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.0",
+ "@img/sharp-linux-arm": "0.34.3",
+ "@img/sharp-linux-arm64": "0.34.3",
+ "@img/sharp-linux-ppc64": "0.34.3",
+ "@img/sharp-linux-s390x": "0.34.3",
+ "@img/sharp-linux-x64": "0.34.3",
+ "@img/sharp-linuxmusl-arm64": "0.34.3",
+ "@img/sharp-linuxmusl-x64": "0.34.3",
+ "@img/sharp-wasm32": "0.34.3",
+ "@img/sharp-win32-arm64": "0.34.3",
+ "@img/sharp-win32-ia32": "0.34.3",
+ "@img/sharp-win32-x64": "0.34.3"
}
},
"node_modules/sharp/node_modules/semver": {
@@ -3866,6 +3861,7 @@
"resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.4.0.tgz",
"integrity": "sha512-97oFRRMM2/Js4oEA9LJhjyMlde+2ewpZQf53pgue27UkbEXfHJnDzHlUxQ/DWUkzqmp7DFwJp8D+wi/TYeQhpA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"detect-indent": "^7.0.1",
"detect-newline": "^4.0.1",
@@ -3975,6 +3971,7 @@
"url": "https://github.com/sponsors/stylelint"
}
],
+ "license": "MIT",
"dependencies": {
"@csstools/css-parser-algorithms": "^3.0.5",
"@csstools/css-tokenizer": "^3.0.4",
@@ -4292,6 +4289,27 @@
"dev": true,
"license": "0BSD"
},
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
+ "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -4302,6 +4320,37 @@
"node": ">= 10.0.0"
}
},
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -4310,16 +4359,18 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.2.tgz",
- "integrity": "sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==",
+ "name": "rolldown-vite",
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.0.8.tgz",
+ "integrity": "sha512-JvCftqO4+el0CujpfkakzI+yJDK03/6tUU/2THl7QfBvxItEC5zDJ7Y8cz0HB7vu6WM82G/emndyY+kUAYLPUg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "esbuild": "^0.25.0",
"fdir": "^6.4.6",
+ "lightningcss": "^1.30.1",
"picomatch": "^4.0.2",
"postcss": "^8.5.6",
- "rollup": "^4.40.0",
+ "rolldown": "1.0.0-beta.26",
"tinyglobby": "^0.2.14"
},
"bin": {
@@ -4336,9 +4387,9 @@
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
+ "esbuild": "^0.25.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
- "lightningcss": "^1.21.0",
"sass": "^1.70.0",
"sass-embedded": "^1.70.0",
"stylus": ">=0.54.8",
@@ -4351,13 +4402,13 @@
"@types/node": {
"optional": true
},
- "jiti": {
+ "esbuild": {
"optional": true
},
- "less": {
+ "jiti": {
"optional": true
},
- "lightningcss": {
+ "less": {
"optional": true
},
"sass": {
@@ -4431,6 +4482,13 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/web-worker": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
+ "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -4457,6 +4515,20 @@
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
+ },
+ "node_modules/xml-utils": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
+ "integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/zstddec": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz",
+ "integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==",
+ "dev": true,
+ "license": "MIT AND BSD-3-Clause"
}
}
}
diff --git a/client/simple/package.json b/client/simple/package.json
index 65d29b737..bdc19c8f8 100644
--- a/client/simple/package.json
+++ b/client/simple/package.json
@@ -6,31 +6,43 @@
"type": "module",
"scripts": {
"build": "npm run build:icons && npm run build:vite",
- "build:icons": "node theme_icons.js",
+ "build:icons": "node theme_icons.ts",
"build:vite": "vite build",
"clean": "rm -Rf node_modules",
"fix": "npm run fix:stylelint && npm run fix:biome && npm run fix:package",
"fix:biome": "biome check --write",
"fix:package": "sort-package-json --quiet",
"fix:stylelint": "stylelint --fix strict 'src/**/*.{scss,sass,less,styl}'",
- "lint": "npm run lint:biome",
- "lint:biome": "biome lint"
+ "lint": "npm run lint:biome && npm run lint:tsc",
+ "lint:biome": "biome lint",
+ "lint:tsc": "tsc --noEmit"
},
+ "browserslist": [
+ "Chrome >= 93",
+ "Firefox >= 92",
+ "Safari >= 15.4",
+ "not dead"
+ ],
"devDependencies": {
- "@biomejs/biome": "~2.0.6",
+ "@biomejs/biome": "~2.1.0",
+ "@types/node": "^24.0.0",
+ "browserslist": "^4.25.1",
+ "browserslist-to-esbuild": "^2.1.1",
"edge.js": "^6.2.1",
"ionicons": "^8.0.10",
- "leaflet": "^1.9.4",
"less": "^4.3.0",
+ "lightningcss": "^1.30.1",
"normalize.css": "^8.0.1",
- "sharp": "^0.34.2",
+ "ol": "^10.6.1",
+ "sharp": "^0.34.3",
"sort-package-json": "^3.4.0",
"stylelint": "^16.21.1",
"stylelint-config-standard-less": "^3.0.1",
"stylelint-prettier": "^5.0.3",
"svgo": "^4.0.0",
"swiped-events": "^1.2.0",
- "vite": "^7.0.2",
+ "typescript": "~5.8.3",
+ "vite": "npm:rolldown-vite@~7.0.8",
"vite-plugin-static-copy": "^3.1.0"
}
}
diff --git a/client/simple/src/js/head/00_init.js b/client/simple/src/js/head/00_init.js
deleted file mode 100644
index 7aec676a4..000000000
--- a/client/simple/src/js/head/00_init.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-((w, d) => {
- // add data- properties
- const getLastScriptElement = () => {
- const scripts = d.getElementsByTagName("script");
- return scripts[scripts.length - 1];
- };
-
- const script = d.currentScript || getLastScriptElement();
-
- w.searxng = {
- settings: JSON.parse(atob(script.getAttribute("client_settings")))
- };
-
- // update the css
- const htmlElement = d.getElementsByTagName("html")[0];
- htmlElement.classList.remove("no-js");
- htmlElement.classList.add("js");
-})(window, document);
diff --git a/client/simple/src/js/main/00_toolkit.js b/client/simple/src/js/main/00_toolkit.js
deleted file mode 100644
index 81e5071f9..000000000
--- a/client/simple/src/js/main/00_toolkit.js
+++ /dev/null
@@ -1,178 +0,0 @@
-/**
- * @license
- * (C) Copyright Contributors to the SearXNG project.
- * (C) Copyright Contributors to the searx project (2014 - 2021).
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-window.searxng = ((w, d) => {
- // not invented here toolkit with bugs fixed elsewhere
- // purposes : be just good enough and as small as possible
-
- // from https://plainjs.com/javascript/events/live-binding-event-handlers-14/
- if (w.Element) {
- ((ElementPrototype) => {
- ElementPrototype.matches =
- ElementPrototype.matches ||
- ElementPrototype.matchesSelector ||
- ElementPrototype.webkitMatchesSelector ||
- ElementPrototype.msMatchesSelector ||
- function (selector) {
- const nodes = (this.parentNode || this.document).querySelectorAll(selector);
- let i = -1;
- while (nodes[++i] && nodes[i] !== this);
- return !!nodes[i];
- };
- })(Element.prototype);
- }
-
- function callbackSafe(callback, el, e) {
- try {
- callback.call(el, e);
- } catch (exception) {
- console.log(exception);
- }
- }
-
- const searxng = window.searxng || {};
-
- searxng.on = (obj, eventType, callback, useCapture) => {
- useCapture = useCapture || false;
- if (typeof obj !== "string") {
- // obj HTMLElement, HTMLDocument
- obj.addEventListener(eventType, callback, useCapture);
- } else {
- // obj is a selector
- d.addEventListener(
- eventType,
- (e) => {
- let el = e.target || e.srcElement;
- let found = false;
-
- while (el?.matches && el !== d) {
- found = el.matches(obj);
-
- if (found) break;
-
- el = el.parentElement;
- }
-
- if (found) {
- callbackSafe(callback, el, e);
- }
- },
- useCapture
- );
- }
- };
-
- searxng.ready = (callback) => {
- if (document.readyState !== "loading") {
- callback.call(w);
- } else {
- w.addEventListener("DOMContentLoaded", callback.bind(w));
- }
- };
-
- searxng.http = (method, url, data = null) =>
- new Promise((resolve, reject) => {
- try {
- const req = new XMLHttpRequest();
- req.open(method, url, true);
- req.timeout = 20000;
-
- // On load
- req.onload = () => {
- if (req.status === 200) {
- resolve(req.response, req.responseType);
- } else {
- reject(Error(req.statusText));
- }
- };
-
- // Handle network errors
- req.onerror = () => {
- reject(Error("Network Error"));
- };
-
- req.onabort = () => {
- reject(Error("Transaction is aborted"));
- };
-
- req.ontimeout = () => {
- reject(Error("Timeout"));
- };
-
- // Make the request
- if (data) {
- req.send(data);
- } else {
- req.send();
- }
- } catch (ex) {
- reject(ex);
- }
- });
-
- searxng.loadStyle = (src) => {
- const path = `${searxng.settings.theme_static_path}/${src}`;
- const id = `style_${src.replace(".", "_")}`;
- let s = d.getElementById(id);
- if (s === null) {
- s = d.createElement("link");
- s.setAttribute("id", id);
- s.setAttribute("rel", "stylesheet");
- s.setAttribute("type", "text/css");
- s.setAttribute("href", path);
- d.body.appendChild(s);
- }
- };
-
- searxng.loadScript = (src, callback) => {
- const path = `${searxng.settings.theme_static_path}/${src}`;
- const id = `script_${src.replace(".", "_")}`;
- let s = d.getElementById(id);
- if (s === null) {
- s = d.createElement("script");
- s.setAttribute("id", id);
- s.setAttribute("src", path);
- s.onload = callback;
- s.onerror = () => {
- s.setAttribute("error", "1");
- };
- d.body.appendChild(s);
- } else if (!s.hasAttribute("error")) {
- try {
- callback.apply(s, []);
- } catch (exception) {
- console.log(exception);
- }
- } else {
- console.log(`callback not executed : script '${path}' not loaded.`);
- }
- };
-
- searxng.insertBefore = (newNode, referenceNode) => {
- referenceNode.parentNode.insertBefore(newNode, referenceNode);
- };
-
- searxng.insertAfter = (newNode, referenceNode) => {
- referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling);
- };
-
- searxng.on(".close", "click", function () {
- this.parentNode.classList.add("invisible");
- });
-
- function getEndpoint() {
- for (const className of d.getElementsByTagName("body")[0].classList.values()) {
- if (className.endsWith("_endpoint")) {
- return className.split("_")[0];
- }
- }
- return "";
- }
-
- searxng.endpoint = getEndpoint();
-
- return searxng;
-})(window, document);
diff --git a/client/simple/src/js/main/00_toolkit.ts b/client/simple/src/js/main/00_toolkit.ts
new file mode 100644
index 000000000..05cfc4b6b
--- /dev/null
+++ b/client/simple/src/js/main/00_toolkit.ts
@@ -0,0 +1,118 @@
+import type { KeyBindingLayout } from "./keyboard.ts";
+
+type Settings = {
+ theme_static_path?: string;
+ method?: string;
+ hotkeys?: KeyBindingLayout;
+ infinite_scroll?: boolean;
+ autocomplete?: boolean;
+ autocomplete_min?: number;
+ search_on_category_select?: boolean;
+ translations?: Record<string, string>;
+ [key: string]: unknown;
+};
+
+type ReadyOptions = {
+ // all values must be truthy for the callback to be executed
+ on?: (boolean | undefined)[];
+};
+
+const getEndpoint = (): string => {
+ const endpointClass = Array.from(document.body.classList).find((className) => className.endsWith("_endpoint"));
+ return endpointClass?.split("_")[0] ?? "";
+};
+
+const getSettings = (): Settings => {
+ const settings = document.querySelector("script[client_settings]")?.getAttribute("client_settings");
+ if (!settings) return {};
+
+ try {
+ return JSON.parse(atob(settings));
+ } catch (error) {
+ console.error("Failed to load client_settings:", error);
+ return {};
+ }
+};
+
+type AssertElement = (element?: Element | null) => asserts element is Element;
+export const assertElement: AssertElement = (element?: Element | null): asserts element is Element => {
+ if (!element) {
+ throw new Error("Bad assertion: DOM element not found");
+ }
+};
+
+export const searxng = {
+ // dynamic functions
+ closeDetail: undefined as (() => void) | undefined,
+ scrollPageToSelected: undefined as (() => void) | undefined,
+ selectImage: undefined as ((resultElement: Element) => void) | undefined,
+ selectNext: undefined as ((openDetailView?: boolean) => void) | undefined,
+ selectPrevious: undefined as ((openDetailView?: boolean) => void) | undefined,
+
+ endpoint: getEndpoint(),
+
+ http: async (method: string, url: string | URL, data?: BodyInit): Promise<Response> => {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
+
+ const res = await fetch(url, {
+ body: data,
+ method,
+ signal: controller.signal
+ }).finally(() => clearTimeout(timeoutId));
+ if (!res.ok) {
+ throw new Error(res.statusText);
+ }
+
+ return res;
+ },
+
+ listen: <K extends keyof DocumentEventMap, E extends Element>(
+ type: string | K,
+ target: string | Document | E,
+ listener: (this: E, event: DocumentEventMap[K]) => void,
+ options?: AddEventListenerOptions
+ ): void => {
+ if (typeof target !== "string") {
+ target.addEventListener(type, listener as EventListener, options);
+ return;
+ }
+
+ document.addEventListener(
+ type,
+ (event: Event) => {
+ for (const node of event.composedPath()) {
+ if (node instanceof Element && node.matches(target)) {
+ try {
+ listener.call(node as E, event as DocumentEventMap[K]);
+ } catch (error) {
+ console.error(error);
+ }
+ break;
+ }
+ }
+ },
+ options
+ );
+ },
+
+ ready: (callback: () => void, options?: ReadyOptions): void => {
+ for (const condition of options?.on ?? []) {
+ if (!condition) {
+ return;
+ }
+ }
+
+ if (document.readyState !== "loading") {
+ callback();
+ } else {
+ searxng.listen("DOMContentLoaded", document, callback, { once: true });
+ }
+ },
+
+ settings: getSettings()
+};
+
+searxng.listen("click", ".close", function (this: Element) {
+ (this.parentNode as Element)?.classList.add("invisible");
+});
diff --git a/client/simple/src/js/main/index.ts b/client/simple/src/js/main/index.ts
new file mode 100644
index 000000000..4dc86b63b
--- /dev/null
+++ b/client/simple/src/js/main/index.ts
@@ -0,0 +1,13 @@
+/**
+ * @preserve (C) Copyright Contributors to the SearXNG project.
+ * @preserve (C) Copyright Contributors to the searx project (2014 - 2021).
+ * @license AGPL-3.0-or-later
+ */
+
+import "./00_toolkit.ts";
+import "./infinite_scroll.ts";
+import "./keyboard.ts";
+import "./mapresult.ts";
+import "./preferences.ts";
+import "./results.ts";
+import "./search.ts";
diff --git a/client/simple/src/js/main/infinite_scroll.js b/client/simple/src/js/main/infinite_scroll.js
deleted file mode 100644
index 12ecd83be..000000000
--- a/client/simple/src/js/main/infinite_scroll.js
+++ /dev/null
@@ -1,84 +0,0 @@
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-/* global searxng */
-
-searxng.ready(() => {
- searxng.infinite_scroll_supported =
- "IntersectionObserver" in window &&
- "IntersectionObserverEntry" in window &&
- "intersectionRatio" in window.IntersectionObserverEntry.prototype;
-
- if (searxng.endpoint !== "results") {
- return;
- }
-
- if (!searxng.infinite_scroll_supported) {
- console.log("IntersectionObserver not supported");
- return;
- }
-
- const d = document;
- const onlyImages = d.getElementById("results").classList.contains("only_template_images");
-
- function newLoadSpinner() {
- const loader = d.createElement("div");
- loader.classList.add("loader");
- return loader;
- }
-
- function replaceChildrenWith(element, children) {
- element.textContent = "";
- children.forEach((child) => element.appendChild(child));
- }
-
- function loadNextPage(callback) {
- const form = d.querySelector("#pagination form.next_page");
- if (!form) {
- return;
- }
- replaceChildrenWith(d.querySelector("#pagination"), [newLoadSpinner()]);
- const formData = new FormData(form);
- searxng
- .http("POST", d.querySelector("#search").getAttribute("action"), formData)
- .then((response) => {
- const nextPageDoc = new DOMParser().parseFromString(response, "text/html");
- const articleList = nextPageDoc.querySelectorAll("#urls article");
- const paginationElement = nextPageDoc.querySelector("#pagination");
- d.querySelector("#pagination").remove();
- if (articleList.length > 0 && !onlyImages) {
- // do not add <hr> element when there are only images
- d.querySelector("#urls").appendChild(d.createElement("hr"));
- }
- articleList.forEach((articleElement) => {
- d.querySelector("#urls").appendChild(articleElement);
- });
- if (paginationElement) {
- d.querySelector("#results").appendChild(paginationElement);
- callback();
- }
- })
- .catch((err) => {
- console.log(err);
- const e = d.createElement("div");
- e.textContent = searxng.settings.translations.error_loading_next_page;
- e.classList.add("dialog-error");
- e.setAttribute("role", "alert");
- replaceChildrenWith(d.querySelector("#pagination"), [e]);
- });
- }
-
- if (searxng.settings.infinite_scroll && searxng.infinite_scroll_supported) {
- const intersectionObserveOptions = {
- rootMargin: "20rem"
- };
- const observedSelector = "article.result:last-child";
- const observer = new IntersectionObserver((entries) => {
- const paginationEntry = entries[0];
- if (paginationEntry.isIntersecting) {
- observer.unobserve(paginationEntry.target);
- loadNextPage(() => observer.observe(d.querySelector(observedSelector), intersectionObserveOptions));
- }
- });
- observer.observe(d.querySelector(observedSelector), intersectionObserveOptions);
- }
-});
diff --git a/client/simple/src/js/main/infinite_scroll.ts b/client/simple/src/js/main/infinite_scroll.ts
new file mode 100644
index 000000000..e9f931e51
--- /dev/null
+++ b/client/simple/src/js/main/infinite_scroll.ts
@@ -0,0 +1,108 @@
+import { assertElement, searxng } from "./00_toolkit";
+
+const newLoadSpinner = (): HTMLDivElement => {
+ return Object.assign(document.createElement("div"), {
+ className: "loader"
+ });
+};
+
+const loadNextPage = async (onlyImages: boolean, callback: () => void): Promise<void> => {
+ const searchForm = document.querySelector<HTMLFormElement>("#search");
+ assertElement(searchForm);
+
+ const form = document.querySelector<HTMLFormElement>("#pagination form.next_page");
+ assertElement(form);
+
+ const formData = new FormData(form);
+
+ const action = searchForm.getAttribute("action");
+ if (!action) {
+ console.error("Form action not found");
+ return;
+ }
+
+ const paginationElement = document.querySelector<HTMLElement>("#pagination");
+ assertElement(paginationElement);
+
+ paginationElement.replaceChildren(newLoadSpinner());
+
+ try {
+ const res = await searxng.http("POST", action, formData);
+ const nextPage = await res.text();
+ if (!nextPage) return;
+
+ const nextPageDoc = new DOMParser().parseFromString(nextPage, "text/html");
+ const articleList = nextPageDoc.querySelectorAll<HTMLElement>("#urls article");
+ const nextPaginationElement = nextPageDoc.querySelector<HTMLElement>("#pagination");
+
+ document.querySelector("#pagination")?.remove();
+
+ const urlsElement = document.querySelector<HTMLElement>("#urls");
+ if (!urlsElement) {
+ console.error("URLs element not found");
+ return;
+ }
+
+ if (articleList.length > 0 && !onlyImages) {
+ // do not add <hr> element when there are only images
+ urlsElement.appendChild(document.createElement("hr"));
+ }
+
+ urlsElement.append(...Array.from(articleList));
+
+ if (nextPaginationElement) {
+ const results = document.querySelector<HTMLElement>("#results");
+ results?.appendChild(nextPaginationElement);
+ callback();
+ }
+ } catch (error) {
+ console.error("Error loading next page:", error);
+
+ const errorElement = Object.assign(document.createElement("div"), {
+ textContent: searxng.settings.translations?.error_loading_next_page ?? "Error loading next page",
+ className: "dialog-error"
+ });
+ errorElement.setAttribute("role", "alert");
+ document.querySelector("#pagination")?.replaceChildren(errorElement);
+ }
+};
+
+searxng.ready(
+ () => {
+ const resultsElement = document.getElementById("results");
+ if (!resultsElement) {
+ console.error("Results element not found");
+ return;
+ }
+
+ const onlyImages = resultsElement.classList.contains("only_template_images");
+ const observedSelector = "article.result:last-child";
+
+ const intersectionObserveOptions: IntersectionObserverInit = {
+ rootMargin: "320px"
+ };
+
+ const observer = new IntersectionObserver(async (entries: IntersectionObserverEntry[]) => {
+ const [paginationEntry] = entries;
+
+ if (paginationEntry?.isIntersecting) {
+ observer.unobserve(paginationEntry.target);
+
+ await loadNextPage(onlyImages, () => {
+ const nextObservedElement = document.querySelector<HTMLElement>(observedSelector);
+ if (nextObservedElement) {
+ observer.observe(nextObservedElement);
+ }
+ });
+ }
+ }, intersectionObserveOptions);
+
+ const initialObservedElement = document.querySelector<HTMLElement>(observedSelector);
+ if (initialObservedElement) {
+ observer.observe(initialObservedElement);
+ }
+ },
+ {
+ on: [searxng.endpoint === "results", searxng.settings.infinite_scroll]
+ }
+);
diff --git a/client/simple/src/js/main/keyboard.js b/client/simple/src/js/main/keyboard.js
deleted file mode 100644
index e707c397f..000000000
--- a/client/simple/src/js/main/keyboard.js
+++ /dev/null
@@ -1,473 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-/* global searxng */
-
-searxng.ready(() => {
- function isElementInDetail(el) {
- while (el !== undefined) {
- if (el.classList.contains("detail")) {
- return true;
- }
- if (el.classList.contains("result")) {
- // we found a result, no need to go to the root of the document:
- // el is not inside a <div class="detail"> element
- return false;
- }
- el = el.parentNode;
- }
- return false;
- }
-
- function getResultElement(el) {
- while (el !== undefined) {
- if (el.classList.contains("result")) {
- return el;
- }
- el = el.parentNode;
- }
- return undefined;
- }
-
- function isImageResult(resultElement) {
- return resultElement?.classList.contains("result-images");
- }
-
- searxng.on(".result", "click", function (e) {
- if (!isElementInDetail(e.target)) {
- highlightResult(this)(true, true);
- const resultElement = getResultElement(e.target);
- if (isImageResult(resultElement)) {
- e.preventDefault();
- searxng.selectImage(resultElement);
- }
- }
- });
-
- searxng.on(
- ".result a",
- "focus",
- (e) => {
- if (!isElementInDetail(e.target)) {
- const resultElement = getResultElement(e.target);
- if (resultElement && resultElement.getAttribute("data-vim-selected") === null) {
- highlightResult(resultElement)(true);
- }
- if (isImageResult(resultElement)) {
- searxng.selectImage(resultElement);
- }
- }
- },
- true
- );
-
- /* common base for layouts */
- const baseKeyBinding = {
- Escape: {
- key: "ESC",
- fun: removeFocus,
- des: "remove focus from the focused input",
- cat: "Control"
- },
- c: {
- key: "c",
- fun: copyURLToClipboard,
- des: "copy url of the selected result to the clipboard",
- cat: "Results"
- },
- h: {
- key: "h",
- fun: toggleHelp,
- des: "toggle help window",
- cat: "Other"
- },
- i: {
- key: "i",
- fun: searchInputFocus,
- des: "focus on the search input",
- cat: "Control"
- },
- n: {
- key: "n",
- fun: GoToNextPage(),
- des: "go to next page",
- cat: "Results"
- },
- o: {
- key: "o",
- fun: openResult(false),
- des: "open search result",
- cat: "Results"
- },
- p: {
- key: "p",
- fun: GoToPreviousPage(),
- des: "go to previous page",
- cat: "Results"
- },
- r: {
- key: "r",
- fun: reloadPage,
- des: "reload page from the server",
- cat: "Control"
- },
- t: {
- key: "t",
- fun: openResult(true),
- des: "open the result in a new tab",
- cat: "Results"
- }
- };
- const keyBindingLayouts = {
- default: Object.assign(
- {
- /* SearXNG layout */
- ArrowLeft: {
- key: "←",
- fun: highlightResult("up"),
- des: "select previous search result",
- cat: "Results"
- },
- ArrowRight: {
- key: "→",
- fun: highlightResult("down"),
- des: "select next search result",
- cat: "Results"
- }
- },
- baseKeyBinding
- ),
-
- vim: Object.assign(
- {
- /* Vim-like Key Layout. */
- b: {
- key: "b",
- fun: scrollPage(-window.innerHeight),
- des: "scroll one page up",
- cat: "Navigation"
- },
- f: {
- key: "f",
- fun: scrollPage(window.innerHeight),
- des: "scroll one page down",
- cat: "Navigation"
- },
- u: {
- key: "u",
- fun: scrollPage(-window.innerHeight / 2),
- des: "scroll half a page up",
- cat: "Navigation"
- },
- d: {
- key: "d",
- fun: scrollPage(window.innerHeight / 2),
- des: "scroll half a page down",
- cat: "Navigation"
- },
- g: {
- key: "g",
- fun: scrollPageTo(-document.body.scrollHeight, "top"),
- des: "scroll to the top of the page",
- cat: "Navigation"
- },
- v: {
- key: "v",
- fun: scrollPageTo(document.body.scrollHeight, "bottom"),
- des: "scroll to the bottom of the page",
- cat: "Navigation"
- },
- k: {
- key: "k",
- fun: highlightResult("up"),
- des: "select previous search result",
- cat: "Results"
- },
- j: {
- key: "j",
- fun: highlightResult("down"),
- des: "select next search result",
- cat: "Results"
- },
- y: {
- key: "y",
- fun: copyURLToClipboard,
- des: "copy url of the selected result to the clipboard",
- cat: "Results"
- }
- },
- baseKeyBinding
- )
- };
-
- const keyBindings = keyBindingLayouts[searxng.settings.hotkeys] || keyBindingLayouts.default;
-
- searxng.on(document, "keydown", (e) => {
- // check for modifiers so we don't break browser's hotkeys
- if (
- // biome-ignore lint/suspicious/noPrototypeBuiltins: FIXME: support for Chromium 93-87, Firefox 92-78, Safari 15.4-14
- Object.prototype.hasOwnProperty.call(keyBindings, e.key) &&
- !e.ctrlKey &&
- !e.altKey &&
- !e.shiftKey &&
- !e.metaKey
- ) {
- const tagName = e.target.tagName.toLowerCase();
- if (e.key === "Escape") {
- keyBindings[e.key].fun(e);
- } else {
- if (e.target === document.body || tagName === "a" || tagName === "button") {
- e.preventDefault();
- keyBindings[e.key].fun();
- }
- }
- }
- });
-
- function highlightResult(which) {
- return (noScroll, keepFocus) => {
- let current = document.querySelector(".result[data-vim-selected]"),
- effectiveWhich = which;
- if (current === null) {
- // no selection : choose the first one
- current = document.querySelector(".result");
- if (current === null) {
- // no first one : there are no results
- return;
- }
- // replace up/down actions by selecting first one
- if (which === "down" || which === "up") {
- effectiveWhich = current;
- }
- }
-
- let next,
- results = document.querySelectorAll(".result");
- results = Array.from(results); // convert NodeList to Array for further use
-
- if (typeof effectiveWhich !== "string") {
- next = effectiveWhich;
- } else {
- switch (effectiveWhich) {
- case "visible": {
- const top = document.documentElement.scrollTop || document.body.scrollTop;
- const bot = top + document.documentElement.clientHeight;
-
- for (let i = 0; i < results.length; i++) {
- next = results[i];
- const etop = next.offsetTop;
- const ebot = etop + next.clientHeight;
-
- if (ebot <= bot && etop > top) {
- break;
- }
- }
- break;
- }
- case "down":
- next = results[results.indexOf(current) + 1] || current;
- break;
- case "up":
- next = results[results.indexOf(current) - 1] || current;
- break;
- case "bottom":
- next = results[results.length - 1];
- break;
- // biome-ignore lint/complexity/noUselessSwitchCase: fallthrough is intended
- case "top":
- /* falls through */
- default:
- next = results[0];
- }
- }
-
- if (next) {
- current.removeAttribute("data-vim-selected");
- next.setAttribute("data-vim-selected", "true");
- if (!keepFocus) {
- const link = next.querySelector("h3 a") || next.querySelector("a");
- if (link !== null) {
- link.focus();
- }
- }
- if (!noScroll) {
- scrollPageToSelected();
- }
- }
- };
- }
-
- function reloadPage() {
- document.location.reload(true);
- }
-
- function removeFocus(e) {
- const tagName = e.target.tagName.toLowerCase();
- if (document.activeElement && (tagName === "input" || tagName === "select" || tagName === "textarea")) {
- document.activeElement.blur();
- } else {
- searxng.closeDetail();
- }
- }
-
- function pageButtonClick(css_selector) {
- return () => {
- const button = document.querySelector(css_selector);
- if (button) {
- button.click();
- }
- };
- }
-
- function GoToNextPage() {
- return pageButtonClick('nav#pagination .next_page button[type="submit"]');
- }
-
- function GoToPreviousPage() {
- return pageButtonClick('nav#pagination .previous_page button[type="submit"]');
- }
-
- function scrollPageToSelected() {
- const sel = document.querySelector(".result[data-vim-selected]");
- if (sel === null) {
- return;
- }
- const wtop = document.documentElement.scrollTop || document.body.scrollTop,
- wheight = document.documentElement.clientHeight,
- etop = sel.offsetTop,
- ebot = etop + sel.clientHeight,
- offset = 120;
- // first element ?
- if (sel.previousElementSibling === null && ebot < wheight) {
- // set to the top of page if the first element
- // is fully included in the viewport
- window.scroll(window.scrollX, 0);
- return;
- }
- if (wtop > etop - offset) {
- window.scroll(window.scrollX, etop - offset);
- } else {
- const wbot = wtop + wheight;
- if (wbot < ebot + offset) {
- window.scroll(window.scrollX, ebot - wheight + offset);
- }
- }
- }
-
- function scrollPage(amount) {
- return () => {
- window.scrollBy(0, amount);
- highlightResult("visible")();
- };
- }
-
- function scrollPageTo(position, nav) {
- return () => {
- window.scrollTo(0, position);
- highlightResult(nav)();
- };
- }
-
- function searchInputFocus() {
- window.scrollTo(0, 0);
- const q = document.querySelector("#q");
- q.focus();
- if (q.setSelectionRange) {
- const len = q.value.length;
- q.setSelectionRange(len, len);
- }
- }
-
- function openResult(newTab) {
- return () => {
- let link = document.querySelector(".result[data-vim-selected] h3 a");
- if (link === null) {
- link = document.querySelector(".result[data-vim-selected] > a");
- }
- if (link !== null) {
- const url = link.getAttribute("href");
- if (newTab) {
- window.open(url);
- } else {
- window.location.href = url;
- }
- }
- };
- }
-
- function initHelpContent(divElement) {
- const categories = {};
-
- for (const k in keyBindings) {
- const key = keyBindings[k];
- categories[key.cat] = categories[key.cat] || [];
- categories[key.cat].push(key);
- }
-
- const sorted = Object.keys(categories).sort((a, b) => categories[b].length - categories[a].length);
-
- if (sorted.length === 0) {
- return;
- }
-
- let html = '<a href="#" class="close" aria-label="close" title="close">×</a>';
- html += "<h3>How to navigate SearXNG with hotkeys</h3>";
- html += "<table>";
-
- for (let i = 0; i < sorted.length; i++) {
- const cat = categories[sorted[i]];
-
- const lastCategory = i === sorted.length - 1;
- const first = i % 2 === 0;
-
- if (first) {
- html += "<tr>";
- }
- html += "<td>";
-
- html += `<h4>${cat[0].cat}</h4>`;
- html += '<ul class="list-unstyled">';
-
- for (const cj in cat) {
- html += `<li><kbd>${cat[cj].key}</kbd> ${cat[cj].des}</li>`;
- }
-
- html += "</ul>";
- html += "</td>"; // col-sm-*
-
- if (!first || lastCategory) {
- html += "</tr>"; // row
- }
- }
-
- html += "</table>";
-
- divElement.innerHTML = html;
- }
-
- function toggleHelp() {
- let helpPanel = document.querySelector("#vim-hotkeys-help");
- if (helpPanel === undefined || helpPanel === null) {
- // first call
- helpPanel = document.createElement("div");
- helpPanel.id = "vim-hotkeys-help";
- helpPanel.className = "dialog-modal";
- initHelpContent(helpPanel);
- const body = document.getElementsByTagName("body")[0];
- body.appendChild(helpPanel);
- } else {
- // toggle hidden
- helpPanel.classList.toggle("invisible");
- }
- }
-
- function copyURLToClipboard() {
- const currentUrlElement = document.querySelector(".result[data-vim-selected] h3 a");
- if (currentUrlElement === null) return;
-
- const url = currentUrlElement.getAttribute("href");
- navigator.clipboard.writeText(url);
- }
-
- searxng.scrollPageToSelected = scrollPageToSelected;
- searxng.selectNext = highlightResult("down");
- searxng.selectPrevious = highlightResult("up");
-});
diff --git a/client/simple/src/js/main/keyboard.ts b/client/simple/src/js/main/keyboard.ts
new file mode 100644
index 000000000..67dd1b3a0
--- /dev/null
+++ b/client/simple/src/js/main/keyboard.ts
@@ -0,0 +1,469 @@
+import { assertElement, searxng } from "./00_toolkit.ts";
+
+export type KeyBindingLayout = "default" | "vim";
+
+type KeyBinding = {
+ key: string;
+ fun: (event: KeyboardEvent) => void;
+ des: string;
+ cat: string;
+};
+
+/* common base for layouts */
+const baseKeyBinding: Record<string, KeyBinding> = {
+ Escape: {
+ key: "ESC",
+ fun: (event) => removeFocus(event),
+ des: "remove focus from the focused input",
+ cat: "Control"
+ },
+ c: {
+ key: "c",
+ fun: () => copyURLToClipboard(),
+ des: "copy url of the selected result to the clipboard",
+ cat: "Results"
+ },
+ h: {
+ key: "h",
+ fun: () => toggleHelp(keyBindings),
+ des: "toggle help window",
+ cat: "Other"
+ },
+ i: {
+ key: "i",
+ fun: () => searchInputFocus(),
+ des: "focus on the search input",
+ cat: "Control"
+ },
+ n: {
+ key: "n",
+ fun: () => GoToNextPage(),
+ des: "go to next page",
+ cat: "Results"
+ },
+ o: {
+ key: "o",
+ fun: () => openResult(false),
+ des: "open search result",
+ cat: "Results"
+ },
+ p: {
+ key: "p",
+ fun: () => GoToPreviousPage(),
+ des: "go to previous page",
+ cat: "Results"
+ },
+ r: {
+ key: "r",
+ fun: () => reloadPage(),
+ des: "reload page from the server",
+ cat: "Control"
+ },
+ t: {
+ key: "t",
+ fun: () => openResult(true),
+ des: "open the result in a new tab",
+ cat: "Results"
+ }
+};
+
+const keyBindingLayouts: Record<KeyBindingLayout, Record<string, KeyBinding>> = {
+ // SearXNG layout
+ default: {
+ ArrowLeft: {
+ key: "←",
+ fun: () => highlightResult("up"),
+ des: "select previous search result",
+ cat: "Results"
+ },
+ ArrowRight: {
+ key: "→",
+ fun: () => highlightResult("down"),
+ des: "select next search result",
+ cat: "Results"
+ },
+ ...baseKeyBinding
+ },
+
+ // Vim-like keyboard layout
+ vim: {
+ b: {
+ key: "b",
+ fun: () => scrollPage(-window.innerHeight),
+ des: "scroll one page up",
+ cat: "Navigation"
+ },
+ d: {
+ key: "d",
+ fun: () => scrollPage(window.innerHeight / 2),
+ des: "scroll half a page down",
+ cat: "Navigation"
+ },
+ f: {
+ key: "f",
+ fun: () => scrollPage(window.innerHeight),
+ des: "scroll one page down",
+ cat: "Navigation"
+ },
+ g: {
+ key: "g",
+ fun: () => scrollPageTo(-document.body.scrollHeight, "top"),
+ des: "scroll to the top of the page",
+ cat: "Navigation"
+ },
+ j: {
+ key: "j",
+ fun: () => highlightResult("down"),
+ des: "select next search result",
+ cat: "Results"
+ },
+ k: {
+ key: "k",
+ fun: () => highlightResult("up"),
+ des: "select previous search result",
+ cat: "Results"
+ },
+ u: {
+ key: "u",
+ fun: () => scrollPage(-window.innerHeight / 2),
+ des: "scroll half a page up",
+ cat: "Navigation"
+ },
+ v: {
+ key: "v",
+ fun: () => scrollPageTo(document.body.scrollHeight, "bottom"),
+ des: "scroll to the bottom of the page",
+ cat: "Navigation"
+ },
+ y: {
+ key: "y",
+ fun: () => copyURLToClipboard(),
+ des: "copy url of the selected result to the clipboard",
+ cat: "Results"
+ },
+ ...baseKeyBinding
+ }
+};
+
+const keyBindings =
+ searxng.settings.hotkeys && searxng.settings.hotkeys in keyBindingLayouts
+ ? keyBindingLayouts[searxng.settings.hotkeys]
+ : keyBindingLayouts.default;
+
+const isElementInDetail = (element?: Element): boolean => {
+ const ancestor = element?.closest(".detail, .result");
+ return ancestor?.classList.contains("detail") ?? false;
+};
+
+const getResultElement = (element?: Element): Element | undefined => {
+ return element?.closest(".result") ?? undefined;
+};
+
+const isImageResult = (resultElement?: Element): boolean => {
+ return resultElement?.classList.contains("result-images") ?? false;
+};
+
+const highlightResult =
+ (which: string | Element) =>
+ (noScroll?: boolean, keepFocus?: boolean): void => {
+ let current = document.querySelector<HTMLElement>(".result[data-vim-selected]");
+ let effectiveWhich = which;
+ if (!current) {
+ // no selection : choose the first one
+ current = document.querySelector<HTMLElement>(".result");
+ if (!current) {
+ // no first one : there are no results
+ return;
+ }
+ // replace up/down actions by selecting first one
+ if (which === "down" || which === "up") {
+ effectiveWhich = current;
+ }
+ }
+
+ let next: Element | null | undefined = null;
+ const results = Array.from(document.querySelectorAll<HTMLElement>(".result"));
+
+ if (typeof effectiveWhich !== "string") {
+ next = effectiveWhich;
+ } else {
+ switch (effectiveWhich) {
+ case "visible": {
+ const top = document.documentElement.scrollTop || document.body.scrollTop;
+ const bot = top + document.documentElement.clientHeight;
+
+ for (let i = 0; i < results.length; i++) {
+ const element = results[i] as HTMLElement;
+ next = element;
+
+ const etop = element.offsetTop;
+ const ebot = etop + element.clientHeight;
+
+ if (ebot <= bot && etop > top) {
+ break;
+ }
+ }
+ break;
+ }
+ case "down":
+ next = results[results.indexOf(current) + 1] || current;
+ break;
+ case "up":
+ next = results[results.indexOf(current) - 1] || current;
+ break;
+ case "bottom":
+ next = results[results.length - 1];
+ break;
+ // biome-ignore lint/complexity/noUselessSwitchCase: fallthrough is intended
+ case "top":
+ default:
+ next = results[0];
+ }
+ }
+
+ if (next && current) {
+ current.removeAttribute("data-vim-selected");
+ next.setAttribute("data-vim-selected", "true");
+ if (!keepFocus) {
+ const link = next.querySelector<HTMLElement>("h3 a") || next.querySelector<HTMLElement>("a");
+ if (link) {
+ link.focus();
+ }
+ }
+ if (!noScroll) {
+ scrollPageToSelected();
+ }
+ }
+ };
+
+const reloadPage = (): void => {
+ document.location.reload();
+};
+
+const removeFocus = (event: KeyboardEvent): void => {
+ const target = event.target as HTMLElement;
+ const tagName = target?.tagName?.toLowerCase();
+
+ if (document.activeElement && (tagName === "input" || tagName === "select" || tagName === "textarea")) {
+ (document.activeElement as HTMLElement).blur();
+ } else {
+ searxng.closeDetail?.();
+ }
+};
+
+const pageButtonClick = (css_selector: string): void => {
+ const button = document.querySelector<HTMLButtonElement>(css_selector);
+ if (button) {
+ button.click();
+ }
+};
+
+const GoToNextPage = () => {
+ pageButtonClick('nav#pagination .next_page button[type="submit"]');
+};
+
+const GoToPreviousPage = () => {
+ pageButtonClick('nav#pagination .previous_page button[type="submit"]');
+};
+
+const scrollPageToSelected = (): void => {
+ const sel = document.querySelector<HTMLElement>(".result[data-vim-selected]");
+ if (!sel) return;
+
+ const wtop = document.documentElement.scrollTop || document.body.scrollTop,
+ height = document.documentElement.clientHeight,
+ etop = sel.offsetTop,
+ ebot = etop + sel.clientHeight,
+ offset = 120;
+
+ // first element ?
+ if (!sel.previousElementSibling && ebot < height) {
+ // set to the top of page if the first element
+ // is fully included in the viewport
+ window.scroll(window.scrollX, 0);
+ return;
+ }
+
+ if (wtop > etop - offset) {
+ window.scroll(window.scrollX, etop - offset);
+ } else {
+ const wbot = wtop + height;
+ if (wbot < ebot + offset) {
+ window.scroll(window.scrollX, ebot - height + offset);
+ }
+ }
+};
+
+const scrollPage = (amount: number): void => {
+ window.scrollBy(0, amount);
+ highlightResult("visible")();
+};
+
+const scrollPageTo = (position: number, nav: string): void => {
+ window.scrollTo(0, position);
+ highlightResult(nav)();
+};
+
+const searchInputFocus = (): void => {
+ window.scrollTo(0, 0);
+
+ const q = document.querySelector<HTMLInputElement>("#q");
+ if (q) {
+ q.focus();
+
+ if (q.setSelectionRange) {
+ const len = q.value.length;
+
+ q.setSelectionRange(len, len);
+ }
+ }
+};
+
+const openResult = (newTab: boolean): void => {
+ let link = document.querySelector<HTMLAnchorElement>(".result[data-vim-selected] h3 a");
+ if (!link) {
+ link = document.querySelector<HTMLAnchorElement>(".result[data-vim-selected] > a");
+ }
+ if (!link) return;
+
+ const url = link.getAttribute("href");
+ if (url) {
+ if (newTab) {
+ window.open(url);
+ } else {
+ window.location.href = url;
+ }
+ }
+};
+
+const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBinding): void => {
+ const categories: Record<string, KeyBinding[]> = {};
+
+ for (const binding of Object.values(keyBindings)) {
+ const cat = binding.cat;
+ categories[cat] ??= [];
+ categories[cat].push(binding);
+ }
+
+ const sortedCategoryKeys = Object.keys(categories).sort(
+ (a, b) => (categories[b]?.length ?? 0) - (categories[a]?.length ?? 0)
+ );
+
+ let html = '<a href="#" class="close" aria-label="close" title="close">×</a>';
+ html += "<h3>How to navigate SearXNG with hotkeys</h3>";
+ html += "<table>";
+
+ for (const [i, categoryKey] of sortedCategoryKeys.entries()) {
+ const bindings = categories[categoryKey];
+ if (!bindings || bindings.length === 0) continue;
+
+ const isFirst = i % 2 === 0;
+ const isLast = i === sortedCategoryKeys.length - 1;
+
+ if (isFirst) {
+ html += "<tr>";
+ }
+
+ html += "<td>";
+ html += `<h4>${categoryKey}</h4>`;
+ html += '<ul class="list-unstyled">';
+
+ for (const binding of bindings) {
+ html += `<li><kbd>${binding.key}</kbd> ${binding.des}</li>`;
+ }
+
+ html += "</ul>";
+ html += "</td>";
+
+ if (!isFirst || isLast) {
+ html += "</tr>";
+ }
+ }
+
+ html += "</table>";
+
+ divElement.innerHTML = html;
+};
+
+const toggleHelp = (keyBindings: typeof baseKeyBinding): void => {
+ let helpPanel = document.querySelector<HTMLElement>("#vim-hotkeys-help");
+ if (!helpPanel) {
+ // first call
+ helpPanel = Object.assign(document.createElement("div"), {
+ id: "vim-hotkeys-help",
+ className: "dialog-modal"
+ });
+ initHelpContent(helpPanel, keyBindings);
+ const body = document.getElementsByTagName("body")[0];
+ if (body) {
+ body.appendChild(helpPanel);
+ }
+ } else {
+ // toggle hidden
+ helpPanel.classList.toggle("invisible");
+ }
+};
+
+const copyURLToClipboard = async (): Promise<void> => {
+ const currentUrlElement = document.querySelector<HTMLAnchorElement>(".result[data-vim-selected] h3 a");
+ assertElement(currentUrlElement);
+
+ const url = currentUrlElement.getAttribute("href");
+ if (url) {
+ await navigator.clipboard.writeText(url);
+ }
+};
+
+searxng.ready(() => {
+ searxng.listen("click", ".result", function (this: Element, event: Event) {
+ if (!isElementInDetail(event.target as Element)) {
+ highlightResult(this)(true, true);
+
+ const resultElement = getResultElement(event.target as Element);
+
+ if (resultElement && isImageResult(resultElement)) {
+ event.preventDefault();
+ searxng.selectImage?.(resultElement);
+ }
+ }
+ });
+
+ searxng.listen(
+ "focus",
+ ".result a",
+ (event: Event) => {
+ if (!isElementInDetail(event.target as Element)) {
+ const resultElement = getResultElement(event.target as Element);
+
+ if (resultElement && !resultElement.getAttribute("data-vim-selected")) {
+ highlightResult(resultElement)(true);
+ }
+
+ if (resultElement && isImageResult(resultElement)) {
+ searxng.selectImage?.(resultElement);
+ }
+ }
+ },
+ { capture: true }
+ );
+
+ searxng.listen("keydown", document, (event: KeyboardEvent) => {
+ // check for modifiers so we don't break browser's hotkeys
+ if (Object.hasOwn(keyBindings, event.key) && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
+ const tagName = (event.target as Element)?.tagName?.toLowerCase();
+
+ if (event.key === "Escape") {
+ keyBindings[event.key]?.fun(event);
+ } else {
+ if (event.target === document.body || tagName === "a" || tagName === "button") {
+ event.preventDefault();
+ keyBindings[event.key]?.fun(event);
+ }
+ }
+ }
+ });
+
+ searxng.scrollPageToSelected = scrollPageToSelected;
+ searxng.selectNext = highlightResult("down");
+ searxng.selectPrevious = highlightResult("up");
+});
diff --git a/client/simple/src/js/main/mapresult.js b/client/simple/src/js/main/mapresult.js
deleted file mode 100644
index 3f2d06548..000000000
--- a/client/simple/src/js/main/mapresult.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-/* global L */
-((_w, _d, searxng) => {
- searxng.ready(() => {
- searxng.on(".searxng_init_map", "click", function (event) {
- // no more request
- this.classList.remove("searxng_init_map");
-
- //
- const leaflet_target = this.dataset.leafletTarget;
- const map_lon = parseFloat(this.dataset.mapLon);
- const map_lat = parseFloat(this.dataset.mapLat);
- const map_zoom = parseFloat(this.dataset.mapZoom);
- const map_boundingbox = JSON.parse(this.dataset.mapBoundingbox);
- const map_geojson = JSON.parse(this.dataset.mapGeojson);
-
- searxng.loadStyle("css/leaflet.css");
- searxng.loadScript("js/leaflet.js", () => {
- let map_bounds = null;
- if (map_boundingbox) {
- const southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]);
- const northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]);
- map_bounds = L.latLngBounds(southWest, northEast);
- }
-
- // init map
- const map = L.map(leaflet_target);
- // create the tile layer with correct attribution
- const osmMapnikUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
- const osmMapnikAttrib = 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
- const osmMapnik = new L.TileLayer(osmMapnikUrl, { minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib });
- const osmWikimediaUrl = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png";
- const osmWikimediaAttrib =
- 'Wikimedia maps | Maps data © <a href="https://openstreetmap.org">OpenStreetMap contributors</a>';
- const osmWikimedia = new L.TileLayer(osmWikimediaUrl, {
- minZoom: 1,
- maxZoom: 19,
- attribution: osmWikimediaAttrib
- });
- // init map view
- if (map_bounds) {
- // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021
- // Still useful ?
- setTimeout(() => {
- map.fitBounds(map_bounds, {
- maxZoom: 17
- });
- }, 0);
- } else if (map_lon && map_lat) {
- if (map_zoom) {
- map.setView(new L.LatLng(map_lat, map_lon), map_zoom);
- } else {
- map.setView(new L.LatLng(map_lat, map_lon), 8);
- }
- }
-
- map.addLayer(osmMapnik);
-
- const baseLayers = {
- "OSM Mapnik": osmMapnik,
- "OSM Wikimedia": osmWikimedia
- };
-
- L.control.layers(baseLayers).addTo(map);
-
- if (map_geojson) {
- L.geoJson(map_geojson).addTo(map);
- } /* else if(map_bounds) {
- L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map);
- } */
- });
-
- // this event occur only once per element
- event.preventDefault();
- });
- });
-})(window, document, window.searxng);
diff --git a/client/simple/src/js/main/mapresult.ts b/client/simple/src/js/main/mapresult.ts
new file mode 100644
index 000000000..421b41f77
--- /dev/null
+++ b/client/simple/src/js/main/mapresult.ts
@@ -0,0 +1,89 @@
+import { searxng } from "./00_toolkit.ts";
+
+searxng.ready(
+ () => {
+ searxng.listen("click", ".searxng_init_map", async function (this: HTMLElement, event: Event) {
+ event.preventDefault();
+ this.classList.remove("searxng_init_map");
+
+ const {
+ View,
+ OlMap,
+ TileLayer,
+ VectorLayer,
+ OSM,
+ VectorSource,
+ Style,
+ Stroke,
+ Fill,
+ Circle,
+ fromLonLat,
+ GeoJSON,
+ Feature,
+ Point
+ } = await import("../pkg/ol.ts");
+ import("ol/ol.css");
+
+ const { leafletTarget: target, mapLon, mapLat, mapGeojson } = this.dataset;
+
+ const lon = parseFloat(mapLon || "0");
+ const lat = parseFloat(mapLat || "0");
+ const view = new View({ maxZoom: 16, enableRotation: false });
+ const map = new OlMap({
+ target,
+ layers: [new TileLayer({ source: new OSM({ maxZoom: 16 }) })],
+ view
+ });
+
+ try {
+ const markerSource = new VectorSource({
+ features: [
+ new Feature({
+ geometry: new Point(fromLonLat([lon, lat]))
+ })
+ ]
+ });
+
+ const markerLayer = new VectorLayer({
+ source: markerSource,
+ style: new Style({
+ image: new Circle({
+ radius: 6,
+ fill: new Fill({ color: "#3050ff" })
+ })
+ })
+ });
+
+ map.addLayer(markerLayer);
+ } catch (error) {
+ console.error("Failed to create marker layer:", error);
+ }
+
+ if (mapGeojson) {
+ try {
+ const geoSource = new VectorSource({
+ features: new GeoJSON().readFeatures(JSON.parse(mapGeojson), {
+ dataProjection: "EPSG:4326",
+ featureProjection: "EPSG:3857"
+ })
+ });
+
+ const geoLayer = new VectorLayer({
+ source: geoSource,
+ style: new Style({
+ stroke: new Stroke({ color: "#3050ff", width: 2 }),
+ fill: new Fill({ color: "#3050ff33" })
+ })
+ });
+
+ map.addLayer(geoLayer);
+
+ view.fit(geoSource.getExtent(), { padding: [20, 20, 20, 20] });
+ } catch (error) {
+ console.error("Failed to create GeoJSON layer:", error);
+ }
+ }
+ });
+ },
+ { on: [searxng.endpoint === "results"] }
+);
diff --git a/client/simple/src/js/main/preferences.js b/client/simple/src/js/main/preferences.js
deleted file mode 100644
index ac080e290..000000000
--- a/client/simple/src/js/main/preferences.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-((_w, d, searxng) => {
- if (searxng.endpoint !== "preferences") {
- return;
- }
-
- searxng.ready(() => {
- let engine_descriptions = null;
-
- function load_engine_descriptions() {
- if (engine_descriptions == null) {
- searxng.http("GET", "engine_descriptions.json").then((content) => {
- engine_descriptions = JSON.parse(content);
- for (const [engine_name, description] of Object.entries(engine_descriptions)) {
- const elements = d.querySelectorAll(`[data-engine-name="${engine_name}"] .engine-description`);
- for (const element of elements) {
- const source = ` (<i>${searxng.settings.translations.Source}:&nbsp;${description[1]}</i>)`;
- element.innerHTML = description[0] + source;
- }
- }
- });
- }
- }
-
- for (const el of d.querySelectorAll("[data-engine-name]")) {
- searxng.on(el, "mouseenter", load_engine_descriptions);
- }
-
- const enableAllEngines = d.querySelectorAll(".enable-all-engines");
- const disableAllEngines = d.querySelectorAll(".disable-all-engines");
- const engineToggles = d.querySelectorAll("tbody input[type=checkbox][class~=checkbox-onoff]");
- const toggleEngines = (enable) => {
- for (const el of engineToggles) {
- // check if element visible, so that only engines of the current category are modified
- if (el.offsetParent !== null) el.checked = !enable;
- }
- };
- for (const el of enableAllEngines) {
- searxng.on(el, "click", () => toggleEngines(true));
- }
- for (const el of disableAllEngines) {
- searxng.on(el, "click", () => toggleEngines(false));
- }
-
- const copyHashButton = d.querySelector("#copy-hash");
- searxng.on(copyHashButton, "click", (e) => {
- e.preventDefault();
- navigator.clipboard.writeText(copyHashButton.dataset.hash);
- copyHashButton.innerText = copyHashButton.dataset.copiedText;
- });
- });
-})(window, document, window.searxng);
diff --git a/client/simple/src/js/main/preferences.ts b/client/simple/src/js/main/preferences.ts
new file mode 100644
index 000000000..6c66018a6
--- /dev/null
+++ b/client/simple/src/js/main/preferences.ts
@@ -0,0 +1,71 @@
+import { searxng } from "./00_toolkit.ts";
+
+const loadEngineDescriptions = async (): Promise<void> => {
+ let engineDescriptions: Record<string, [string, string]> | null = null;
+ try {
+ const res = await searxng.http("GET", "engine_descriptions.json");
+ engineDescriptions = await res.json();
+ } catch (error) {
+ console.error("Error fetching engineDescriptions:", error);
+ }
+ if (!engineDescriptions) return;
+
+ for (const [engine_name, [description, source]] of Object.entries(engineDescriptions)) {
+ const elements = document.querySelectorAll<HTMLElement>(`[data-engine-name="${engine_name}"] .engine-description`);
+ const sourceText = ` (<i>${searxng.settings.translations?.Source}:&nbsp;${source}</i>)`;
+
+ for (const element of elements) {
+ element.innerHTML = description + sourceText;
+ }
+ }
+};
+
+const toggleEngines = (enable: boolean, engineToggles: NodeListOf<HTMLInputElement>): void => {
+ for (const engineToggle of engineToggles) {
+ // check if element visible, so that only engines of the current category are modified
+ if (engineToggle.offsetParent) {
+ engineToggle.checked = !enable;
+ }
+ }
+};
+
+searxng.ready(
+ () => {
+ const engineElements = document.querySelectorAll<HTMLElement>("[data-engine-name]");
+ for (const engineElement of engineElements) {
+ searxng.listen("mouseenter", engineElement, loadEngineDescriptions);
+ }
+
+ const engineToggles = document.querySelectorAll<HTMLInputElement>(
+ "tbody input[type=checkbox][class~=checkbox-onoff]"
+ );
+
+ const enableAllEngines = document.querySelectorAll<HTMLElement>(".enable-all-engines");
+ for (const engine of enableAllEngines) {
+ searxng.listen("click", engine, () => toggleEngines(true, engineToggles));
+ }
+
+ const disableAllEngines = document.querySelectorAll<HTMLElement>(".disable-all-engines");
+ for (const engine of disableAllEngines) {
+ searxng.listen("click", engine, () => toggleEngines(false, engineToggles));
+ }
+
+ const copyHashButton = document.querySelector<HTMLElement>("#copy-hash");
+ if (copyHashButton) {
+ searxng.listen("click", copyHashButton, async (event: Event) => {
+ event.preventDefault();
+
+ const { copiedText, hash } = copyHashButton.dataset;
+ if (!copiedText || !hash) return;
+
+ try {
+ await navigator.clipboard.writeText(hash);
+ copyHashButton.innerText = copiedText;
+ } catch (error) {
+ console.error("Failed to copy hash:", error);
+ }
+ });
+ }
+ },
+ { on: [searxng.endpoint === "preferences"] }
+);
diff --git a/client/simple/src/js/main/results.js b/client/simple/src/js/main/results.js
deleted file mode 100644
index cf7829912..000000000
--- a/client/simple/src/js/main/results.js
+++ /dev/null
@@ -1,182 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-
-import "../../../node_modules/swiped-events/src/swiped-events.js";
-
-((w, d, searxng) => {
- if (searxng.endpoint !== "results") {
- return;
- }
-
- searxng.ready(() => {
- d.querySelectorAll("#urls img").forEach((img) =>
- img.addEventListener(
- "error",
- () => {
- // console.log("ERROR can't load: " + img.src);
- img.src = `${window.searxng.settings.theme_static_path}/img/img_load_error.svg`;
- },
- { once: true }
- )
- );
-
- if (d.querySelector("#search_url button#copy_url")) {
- d.querySelector("#search_url button#copy_url").style.display = "block";
- }
-
- searxng.on(".btn-collapse", "click", function () {
- const btnLabelCollapsed = this.getAttribute("data-btn-text-collapsed");
- const btnLabelNotCollapsed = this.getAttribute("data-btn-text-not-collapsed");
- const target = this.getAttribute("data-target");
- const targetElement = d.querySelector(target);
- let html = this.innerHTML;
- if (this.classList.contains("collapsed")) {
- html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed);
- } else {
- html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed);
- }
- this.innerHTML = html;
- this.classList.toggle("collapsed");
- targetElement.classList.toggle("invisible");
- });
-
- searxng.on(".media-loader", "click", function () {
- const target = this.getAttribute("data-target");
- const iframe_load = d.querySelector(`${target} > iframe`);
- const srctest = iframe_load.getAttribute("src");
- if (srctest === null || srctest === undefined || srctest === false) {
- iframe_load.setAttribute("src", iframe_load.getAttribute("data-src"));
- }
- });
-
- searxng.on("#copy_url", "click", function () {
- const target = this.parentElement.querySelector("pre");
- navigator.clipboard.writeText(target.innerText);
- this.innerText = this.dataset.copiedText;
- });
-
- // searxng.selectImage (gallery)
- // -----------------------------
-
- // setTimeout() ID, needed to cancel *last* loadImage
- let imgTimeoutID;
-
- // progress spinner, while an image is loading
- const imgLoaderSpinner = d.createElement("div");
- imgLoaderSpinner.classList.add("loader");
-
- // singleton image object, which is used for all loading processes of a
- // detailed image
- const imgLoader = new Image();
-
- const loadImage = (imgSrc, onSuccess) => {
- // if defered image load exists, stop defered task.
- if (imgTimeoutID) clearTimeout(imgTimeoutID);
-
- // defer load of the detail image for 1 sec
- imgTimeoutID = setTimeout(() => {
- imgLoader.src = imgSrc;
- }, 1000);
-
- // set handlers in the on-properties
- imgLoader.onload = () => {
- onSuccess();
- imgLoaderSpinner.remove();
- };
- imgLoader.onerror = () => {
- imgLoaderSpinner.remove();
- };
- };
-
- searxng.selectImage = (resultElement) => {
- // add a class that can be evaluated in the CSS and indicates that the
- // detail view is open
- d.getElementById("results").classList.add("image-detail-open");
-
- // add a hash to the browser history so that pressing back doesn't return
- // to the previous page this allows us to dismiss the image details on
- // pressing the back button on mobile devices
- window.location.hash = "#image-viewer";
-
- searxng.scrollPageToSelected();
-
- // if there is none element given by the caller, stop here
- if (!resultElement) return;
-
- // find <img> object in the element, if there is none, stop here.
- const img = resultElement.querySelector(".result-images-source img");
- if (!img) return;
-
- // <img src="" data-src="http://example.org/image.jpg">
- const src = img.getAttribute("data-src");
-
- // already loaded high-res image or no high-res image available
- if (!src) return;
-
- // use the image thumbnail until the image is fully loaded
- const thumbnail = resultElement.querySelector(".image_thumbnail");
- img.src = thumbnail.src;
-
- // show a progress spinner
- const detailElement = resultElement.querySelector(".detail");
- detailElement.appendChild(imgLoaderSpinner);
-
- // load full size image in background
- loadImage(src, () => {
- // after the singelton loadImage has loaded the detail image into the
- // cache, it can be used in the origin <img> as src property.
- img.src = src;
- img.removeAttribute("data-src");
- });
- };
-
- searxng.closeDetail = () => {
- d.getElementById("results").classList.remove("image-detail-open");
- // remove #image-viewer hash from url by navigating back
- if (window.location.hash === "#image-viewer") window.history.back();
- searxng.scrollPageToSelected();
- };
- searxng.on(".result-detail-close", "click", (e) => {
- e.preventDefault();
- searxng.closeDetail();
- });
- searxng.on(".result-detail-previous", "click", (e) => {
- e.preventDefault();
- searxng.selectPrevious(false);
- });
- searxng.on(".result-detail-next", "click", (e) => {
- e.preventDefault();
- searxng.selectNext(false);
- });
-
- // listen for the back button to be pressed and dismiss the image details when called
- window.addEventListener("hashchange", () => {
- if (window.location.hash !== "#image-viewer") searxng.closeDetail();
- });
-
- d.querySelectorAll(".swipe-horizontal").forEach((obj) => {
- obj.addEventListener("swiped-left", () => {
- searxng.selectNext(false);
- });
- obj.addEventListener("swiped-right", () => {
- searxng.selectPrevious(false);
- });
- });
-
- w.addEventListener(
- "scroll",
- () => {
- const e = d.getElementById("backToTop"),
- scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
- results = d.getElementById("results");
- if (e !== null) {
- if (scrollTop >= 100) {
- results.classList.add("scrolling");
- } else {
- results.classList.remove("scrolling");
- }
- }
- },
- true
- );
- });
-})(window, document, window.searxng);
diff --git a/client/simple/src/js/main/results.ts b/client/simple/src/js/main/results.ts
new file mode 100644
index 000000000..e278c894a
--- /dev/null
+++ b/client/simple/src/js/main/results.ts
@@ -0,0 +1,181 @@
+import "../../../node_modules/swiped-events/src/swiped-events.js";
+import { assertElement, searxng } from "./00_toolkit.ts";
+
+const loadImage = (imgSrc: string, onSuccess: () => void): void => {
+ // singleton image object, which is used for all loading processes of a detailed image
+ const imgLoader = new Image();
+
+ // set handlers in the on-properties
+ imgLoader.onload = () => {
+ onSuccess();
+ };
+
+ imgLoader.src = imgSrc;
+};
+
+searxng.ready(
+ () => {
+ const imageThumbnails = document.querySelectorAll<HTMLImageElement>("#urls img.image_thumbnail");
+ for (const thumbnail of imageThumbnails) {
+ if (thumbnail.complete && thumbnail.naturalWidth === 0) {
+ thumbnail.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ }
+
+ thumbnail.onerror = () => {
+ thumbnail.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ };
+ }
+
+ const copyUrlButton = document.querySelector<HTMLButtonElement>("#search_url button#copy_url");
+ copyUrlButton?.style.setProperty("display", "block");
+
+ searxng.listen("click", ".btn-collapse", function (this: HTMLElement) {
+ const btnLabelCollapsed = this.getAttribute("data-btn-text-collapsed");
+ const btnLabelNotCollapsed = this.getAttribute("data-btn-text-not-collapsed");
+ const target = this.getAttribute("data-target");
+
+ if (!target || !btnLabelCollapsed || !btnLabelNotCollapsed) return;
+
+ const targetElement = document.querySelector<HTMLElement>(target);
+ assertElement(targetElement);
+
+ const isCollapsed = this.classList.contains("collapsed");
+ const newLabel = isCollapsed ? btnLabelNotCollapsed : btnLabelCollapsed;
+ const oldLabel = isCollapsed ? btnLabelCollapsed : btnLabelNotCollapsed;
+
+ this.innerHTML = this.innerHTML.replace(oldLabel, newLabel);
+ this.classList.toggle("collapsed");
+
+ targetElement.classList.toggle("invisible");
+ });
+
+ searxng.listen("click", ".media-loader", function (this: HTMLElement) {
+ const target = this.getAttribute("data-target");
+ if (!target) return;
+
+ const iframeLoad = document.querySelector<HTMLIFrameElement>(`${target} > iframe`);
+ assertElement(iframeLoad);
+
+ const srctest = iframeLoad.getAttribute("src");
+ if (!srctest) {
+ const dataSrc = iframeLoad.getAttribute("data-src");
+ if (dataSrc) {
+ iframeLoad.setAttribute("src", dataSrc);
+ }
+ }
+ });
+
+ searxng.listen("click", "#copy_url", async function (this: HTMLElement) {
+ const target = this.parentElement?.querySelector<HTMLPreElement>("pre");
+ assertElement(target);
+
+ await navigator.clipboard.writeText(target.innerText);
+ const copiedText = this.dataset.copiedText;
+ if (copiedText) {
+ this.innerText = copiedText;
+ }
+ });
+
+ searxng.selectImage = (resultElement: Element): void => {
+ // add a class that can be evaluated in the CSS and indicates that the
+ // detail view is open
+ const resultsElement = document.getElementById("results");
+ resultsElement?.classList.add("image-detail-open");
+
+ // add a hash to the browser history so that pressing back doesn't return
+ // to the previous page this allows us to dismiss the image details on
+ // pressing the back button on mobile devices
+ window.location.hash = "#image-viewer";
+
+ searxng.scrollPageToSelected?.();
+
+ // if there is no element given by the caller, stop here
+ if (!resultElement) return;
+
+ // find image element, if there is none, stop here
+ const img = resultElement.querySelector<HTMLImageElement>(".result-images-source img");
+ if (!img) return;
+
+ // <img src="" data-src="http://example.org/image.jpg">
+ const src = img.getAttribute("data-src");
+ if (!src) return;
+
+ // use thumbnail until full image loads
+ const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
+ if (thumbnail) {
+ img.src = thumbnail.src;
+ }
+
+ // load full size image
+ loadImage(src, () => {
+ img.src = src;
+ img.onerror = () => {
+ img.src = `${searxng.settings.theme_static_path}/img/img_load_error.svg`;
+ };
+
+ img.removeAttribute("data-src");
+ });
+ };
+
+ searxng.closeDetail = (): void => {
+ const resultsElement = document.getElementById("results");
+ resultsElement?.classList.remove("image-detail-open");
+
+ // remove #image-viewer hash from url by navigating back
+ if (window.location.hash === "#image-viewer") {
+ window.history.back();
+ }
+
+ searxng.scrollPageToSelected?.();
+ };
+
+ searxng.listen("click", ".result-detail-close", (event: Event) => {
+ event.preventDefault();
+ searxng.closeDetail?.();
+ });
+
+ searxng.listen("click", ".result-detail-previous", (event: Event) => {
+ event.preventDefault();
+ searxng.selectPrevious?.(false);
+ });
+
+ searxng.listen("click", ".result-detail-next", (event: Event) => {
+ event.preventDefault();
+ searxng.selectNext?.(false);
+ });
+
+ // listen for the back button to be pressed and dismiss the image details when called
+ window.addEventListener("hashchange", () => {
+ if (window.location.hash !== "#image-viewer") {
+ searxng.closeDetail?.();
+ }
+ });
+
+ const swipeHorizontal = document.querySelectorAll<HTMLElement>(".swipe-horizontal");
+ for (const element of swipeHorizontal) {
+ searxng.listen("swiped-left", element, () => {
+ searxng.selectNext?.(false);
+ });
+
+ searxng.listen("swiped-right", element, () => {
+ searxng.selectPrevious?.(false);
+ });
+ }
+
+ window.addEventListener(
+ "scroll",
+ () => {
+ const backToTopElement = document.getElementById("backToTop");
+ const resultsElement = document.getElementById("results");
+
+ if (backToTopElement && resultsElement) {
+ const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+ const isScrolling = scrollTop >= 100;
+ resultsElement.classList.toggle("scrolling", isScrolling);
+ }
+ },
+ true
+ );
+ },
+ { on: [searxng.endpoint === "results"] }
+);
diff --git a/client/simple/src/js/main/search.js b/client/simple/src/js/main/search.js
deleted file mode 100644
index 5d1e18bde..000000000
--- a/client/simple/src/js/main/search.js
+++ /dev/null
@@ -1,197 +0,0 @@
-/* SPDX-License-Identifier: AGPL-3.0-or-later */
-/* exported AutoComplete */
-
-((_w, d, searxng) => {
- const qinput_id = "q";
- let qinput;
-
- const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches;
- const isResultsPage = document.querySelector("main").id === "main_results";
-
- function submitIfQuery() {
- if (qinput.value.length > 0) {
- const search = document.getElementById("search");
- setTimeout(search.submit.bind(search), 0);
- }
- }
-
- function createClearButton(qinput) {
- const cs = document.getElementById("clear_search");
- const updateClearButton = () => {
- if (qinput.value.length === 0) {
- cs.classList.add("empty");
- } else {
- cs.classList.remove("empty");
- }
- };
-
- // update status, event listener
- updateClearButton();
- cs.addEventListener("click", (ev) => {
- qinput.value = "";
- qinput.focus();
- updateClearButton();
- ev.preventDefault();
- });
- qinput.addEventListener("input", updateClearButton, false);
- }
-
- const fetchResults = async (query) => {
- let request;
- if (searxng.settings.method === "GET") {
- const reqParams = new URLSearchParams();
- reqParams.append("q", query);
- request = fetch(`./autocompleter?${reqParams.toString()}`);
- } else {
- const formData = new FormData();
- formData.append("q", query);
- request = fetch("./autocompleter", {
- method: "POST",
- body: formData
- });
- }
-
- request.then(async (response) => {
- const results = await response.json();
-
- if (!results) return;
-
- const autocomplete = d.querySelector(".autocomplete");
- const autocompleteList = d.querySelector(".autocomplete ul");
- autocomplete.classList.add("open");
- autocompleteList.innerHTML = "";
-
- // show an error message that no result was found
- if (!results[1] || results[1].length === 0) {
- const noItemFoundMessage = document.createElement("li");
- noItemFoundMessage.classList.add("no-item-found");
- noItemFoundMessage.innerHTML = searxng.settings.translations.no_item_found;
- autocompleteList.appendChild(noItemFoundMessage);
- return;
- }
-
- for (const result of results[1]) {
- const li = document.createElement("li");
- li.innerText = result;
-
- searxng.on(li, "mousedown", () => {
- qinput.value = result;
- const form = d.querySelector("#search");
- form.submit();
- autocomplete.classList.remove("open");
- });
- autocompleteList.appendChild(li);
- }
- });
- };
-
- searxng.ready(() => {
- // focus search input on large screens
- if (!isMobile && !isResultsPage) document.getElementById("q").focus();
-
- qinput = d.getElementById(qinput_id);
- const autocomplete = d.querySelector(".autocomplete");
- const autocompleteList = d.querySelector(".autocomplete ul");
-
- if (qinput !== null) {
- // clear button
- createClearButton(qinput);
-
- // autocompleter
- if (searxng.settings.autocomplete) {
- searxng.on(qinput, "input", () => {
- const query = qinput.value;
- if (query.length < searxng.settings.autocomplete_min) return;
-
- setTimeout(() => {
- if (query === qinput.value) fetchResults(query);
- }, 300);
- });
-
- searxng.on(qinput, "keyup", (e) => {
- let currentIndex = -1;
- const listItems = autocompleteList.children;
- for (let i = 0; i < listItems.length; i++) {
- if (listItems[i].classList.contains("active")) {
- currentIndex = i;
- break;
- }
- }
-
- let newCurrentIndex = -1;
- if (e.key === "ArrowUp") {
- if (currentIndex >= 0) listItems[currentIndex].classList.remove("active");
- // we need to add listItems.length to the index calculation here because the JavaScript modulos
- // operator doesn't work with negative numbers
- newCurrentIndex = (currentIndex - 1 + listItems.length) % listItems.length;
- } else if (e.key === "ArrowDown") {
- if (currentIndex >= 0) listItems[currentIndex].classList.remove("active");
- newCurrentIndex = (currentIndex + 1) % listItems.length;
- } else if (e.key === "Tab" || e.key === "Enter") {
- autocomplete.classList.remove("open");
- }
-
- if (newCurrentIndex !== -1) {
- const selectedItem = listItems[newCurrentIndex];
- selectedItem.classList.add("active");
-
- if (!selectedItem.classList.contains("no-item-found")) qinput.value = selectedItem.innerText;
- }
- });
- }
- }
-
- // Additionally to searching when selecting a new category, we also
- // automatically start a new search request when the user changes a search
- // filter (safesearch, time range or language) (this requires JavaScript
- // though)
- if (
- qinput !== null &&
- searxng.settings.search_on_category_select &&
- // If .search_filters is undefined (invisible) we are on the homepage and
- // hence don't have to set any listeners
- d.querySelector(".search_filters") != null
- ) {
- searxng.on(d.getElementById("safesearch"), "change", submitIfQuery);
- searxng.on(d.getElementById("time_range"), "change", submitIfQuery);
- searxng.on(d.getElementById("language"), "change", submitIfQuery);
- }
-
- const categoryButtons = d.querySelectorAll("button.category_button");
- for (const button of categoryButtons) {
- searxng.on(button, "click", (event) => {
- if (event.shiftKey) {
- event.preventDefault();
- button.classList.toggle("selected");
- return;
- }
-
- // manually deselect the old selection when a new category is selected
- const selectedCategories = d.querySelectorAll("button.category_button.selected");
- for (const categoryButton of selectedCategories) {
- categoryButton.classList.remove("selected");
- }
- button.classList.add("selected");
- });
- }
-
- // override form submit action to update the actually selected categories
- const form = d.querySelector("#search");
- if (form != null) {
- searxng.on(form, "submit", (event) => {
- event.preventDefault();
- const categoryValuesInput = d.querySelector("#selected-categories");
- if (categoryValuesInput) {
- const categoryValues = [];
- for (const categoryButton of categoryButtons) {
- if (categoryButton.classList.contains("selected")) {
- categoryValues.push(categoryButton.name.replace("category_", ""));
- }
- }
- categoryValuesInput.value = categoryValues.join(",");
- }
- form.submit();
- });
- }
- });
-})(window, document, window.searxng);
diff --git a/client/simple/src/js/main/search.ts b/client/simple/src/js/main/search.ts
new file mode 100644
index 000000000..5e68965b1
--- /dev/null
+++ b/client/simple/src/js/main/search.ts
@@ -0,0 +1,233 @@
+import { assertElement, searxng } from "./00_toolkit.ts";
+
+const submitIfQuery = (qInput: HTMLInputElement): void => {
+ if (qInput.value.length > 0) {
+ const search = document.getElementById("search") as HTMLFormElement | null;
+ search?.submit();
+ }
+};
+
+const updateClearButton = (qInput: HTMLInputElement, cs: HTMLElement): void => {
+ cs.classList.toggle("empty", qInput.value.length === 0);
+};
+
+const createClearButton = (qInput: HTMLInputElement): void => {
+ const cs = document.getElementById("clear_search");
+ assertElement(cs);
+
+ updateClearButton(qInput, cs);
+
+ searxng.listen("click", cs, (event: MouseEvent) => {
+ event.preventDefault();
+ qInput.value = "";
+ qInput.focus();
+ updateClearButton(qInput, cs);
+ });
+
+ searxng.listen("input", qInput, () => updateClearButton(qInput, cs), { passive: true });
+};
+
+const fetchResults = async (qInput: HTMLInputElement, query: string): Promise<void> => {
+ try {
+ let res: Response;
+
+ if (searxng.settings.method === "GET") {
+ res = await searxng.http("GET", `./autocompleter?q=${query}`);
+ } else {
+ res = await searxng.http("POST", "./autocompleter", new URLSearchParams({ q: query }));
+ }
+
+ const results = await res.json();
+
+ const autocomplete = document.querySelector<HTMLElement>(".autocomplete");
+ assertElement(autocomplete);
+
+ const autocompleteList = document.querySelector<HTMLUListElement>(".autocomplete ul");
+ assertElement(autocompleteList);
+
+ autocomplete.classList.add("open");
+ autocompleteList.replaceChildren();
+
+ // show an error message that no result was found
+ if (!results?.[1]?.length) {
+ const noItemFoundMessage = Object.assign(document.createElement("li"), {
+ className: "no-item-found",
+ textContent: searxng.settings.translations?.no_item_found ?? "No results found"
+ });
+ autocompleteList.append(noItemFoundMessage);
+ return;
+ }
+
+ const fragment = new DocumentFragment();
+
+ for (const result of results[1]) {
+ const li = Object.assign(document.createElement("li"), { textContent: result });
+
+ searxng.listen("mousedown", li, () => {
+ qInput.value = result;
+
+ const form = document.querySelector<HTMLFormElement>("#search");
+ form?.submit();
+
+ autocomplete.classList.remove("open");
+ });
+
+ fragment.append(li);
+ }
+
+ autocompleteList.append(fragment);
+ } catch (error) {
+ console.error("Error fetching autocomplete results:", error);
+ }
+};
+
+searxng.ready(
+ () => {
+ const qInput = document.getElementById("q") as HTMLInputElement | null;
+ assertElement(qInput);
+
+ const isMobile = window.matchMedia("(max-width: 50em)").matches;
+ const isResultsPage = document.querySelector("main")?.id === "main_results";
+
+ // focus search input on large screens
+ if (!isMobile && !isResultsPage) {
+ qInput.focus();
+ }
+
+ createClearButton(qInput);
+
+ // autocompleter
+ if (searxng.settings.autocomplete) {
+ let timeoutId: number;
+
+ searxng.listen("input", qInput, () => {
+ clearTimeout(timeoutId);
+
+ const query = qInput.value;
+ const minLength = searxng.settings.autocomplete_min ?? 2;
+
+ if (query.length < minLength) return;
+
+ timeoutId = window.setTimeout(async () => {
+ if (query === qInput.value) {
+ await fetchResults(qInput, query);
+ }
+ }, 300);
+ });
+
+ const autocomplete = document.querySelector<HTMLElement>(".autocomplete");
+ const autocompleteList = document.querySelector<HTMLUListElement>(".autocomplete ul");
+ if (autocompleteList) {
+ searxng.listen("keyup", qInput, (event: KeyboardEvent) => {
+ const listItems = [...autocompleteList.children] as HTMLElement[];
+
+ const currentIndex = listItems.findIndex((item) => item.classList.contains("active"));
+ let newCurrentIndex = -1;
+
+ switch (event.key) {
+ case "ArrowUp": {
+ const currentItem = listItems[currentIndex];
+ if (currentItem && currentIndex >= 0) {
+ currentItem.classList.remove("active");
+ }
+ // we need to add listItems.length to the index calculation here because the JavaScript modulos
+ // operator doesn't work with negative numbers
+ newCurrentIndex = (currentIndex - 1 + listItems.length) % listItems.length;
+ break;
+ }
+ case "ArrowDown": {
+ const currentItem = listItems[currentIndex];
+ if (currentItem && currentIndex >= 0) {
+ currentItem.classList.remove("active");
+ }
+ newCurrentIndex = (currentIndex + 1) % listItems.length;
+ break;
+ }
+ case "Tab":
+ case "Enter":
+ if (autocomplete) {
+ autocomplete.classList.remove("open");
+ }
+ break;
+ }
+
+ if (newCurrentIndex !== -1) {
+ const selectedItem = listItems[newCurrentIndex];
+ if (selectedItem) {
+ selectedItem.classList.add("active");
+
+ if (!selectedItem.classList.contains("no-item-found")) {
+ const qInput = document.getElementById("q") as HTMLInputElement | null;
+ if (qInput) {
+ qInput.value = selectedItem.textContent ?? "";
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ // Additionally to searching when selecting a new category, we also
+ // automatically start a new search request when the user changes a search
+ // filter (safesearch, time range or language) (this requires JavaScript
+ // though)
+ if (
+ searxng.settings.search_on_category_select &&
+ // If .search_filters is undefined (invisible) we are on the homepage and
+ // hence don't have to set any listeners
+ document.querySelector(".search_filters")
+ ) {
+ const safesearchElement = document.getElementById("safesearch");
+ if (safesearchElement) {
+ searxng.listen("change", safesearchElement, () => submitIfQuery(qInput));
+ }
+
+ const timeRangeElement = document.getElementById("time_range");
+ if (timeRangeElement) {
+ searxng.listen("change", timeRangeElement, () => submitIfQuery(qInput));
+ }
+
+ const languageElement = document.getElementById("language");
+ if (languageElement) {
+ searxng.listen("change", languageElement, () => submitIfQuery(qInput));
+ }
+ }
+
+ const categoryButtons = [...document.querySelectorAll<HTMLButtonElement>("button.category_button")];
+ for (const button of categoryButtons) {
+ searxng.listen("click", button, (event: MouseEvent) => {
+ if (event.shiftKey) {
+ event.preventDefault();
+ button.classList.toggle("selected");
+ return;
+ }
+
+ // deselect all other categories
+ for (const categoryButton of categoryButtons) {
+ categoryButton.classList.toggle("selected", categoryButton === button);
+ }
+ });
+ }
+
+ const form = document.querySelector<HTMLFormElement>("#search");
+ assertElement(form);
+
+ // override form submit action to update the actually selected categories
+ searxng.listen("submit", form, (event: Event) => {
+ event.preventDefault();
+
+ const categoryValuesInput = document.querySelector<HTMLInputElement>("#selected-categories");
+ if (categoryValuesInput) {
+ const categoryValues = categoryButtons
+ .filter((button) => button.classList.contains("selected"))
+ .map((button) => button.name.replace("category_", ""));
+
+ categoryValuesInput.value = categoryValues.join(",");
+ }
+
+ form.submit();
+ });
+ },
+ { on: [searxng.endpoint === "index" || searxng.endpoint === "results"] }
+);
diff --git a/client/simple/src/js/pkg/ol.ts b/client/simple/src/js/pkg/ol.ts
new file mode 100644
index 000000000..f0f932182
--- /dev/null
+++ b/client/simple/src/js/pkg/ol.ts
@@ -0,0 +1,26 @@
+import { Feature, Map as OlMap, View } from "ol";
+import { createEmpty } from "ol/extent";
+import { GeoJSON } from "ol/format";
+import { Point } from "ol/geom";
+import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
+import { fromLonLat } from "ol/proj";
+import { OSM, Vector as VectorSource } from "ol/source";
+import { Circle, Fill, Stroke, Style } from "ol/style";
+
+export {
+ View,
+ OlMap,
+ TileLayer,
+ VectorLayer,
+ OSM,
+ createEmpty,
+ VectorSource,
+ Style,
+ Stroke,
+ Fill,
+ Circle,
+ fromLonLat,
+ GeoJSON,
+ Feature,
+ Point
+};
diff --git a/client/simple/src/js/searxng.head.js b/client/simple/src/js/searxng.head.js
deleted file mode 100644
index 895c95f94..000000000
--- a/client/simple/src/js/searxng.head.js
+++ /dev/null
@@ -1 +0,0 @@
-import "./head/00_init.js";
diff --git a/client/simple/src/js/searxng.js b/client/simple/src/js/searxng.js
deleted file mode 100644
index c9a6eea43..000000000
--- a/client/simple/src/js/searxng.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import "./main/00_toolkit.js";
-import "./main/infinite_scroll.js";
-import "./main/keyboard.js";
-import "./main/mapresult.js";
-import "./main/preferences.js";
-import "./main/results.js";
-import "./main/search.js";
diff --git a/client/simple/src/less/code.less b/client/simple/src/less/code.less
index dd0998b23..d83bb1f6f 100644
--- a/client/simple/src/less/code.less
+++ b/client/simple/src/less/code.less
@@ -24,6 +24,7 @@
&::-moz-selection {
background: transparent; /* Gecko Browsers */
}
+
margin-right: 8px;
text-align: right;
}
diff --git a/client/simple/theme_icons.js b/client/simple/theme_icons.ts
index a70867aba..5bb06a020 100644
--- a/client/simple/theme_icons.js
+++ b/client/simple/theme_icons.ts
@@ -4,40 +4,33 @@
import { dirname, resolve } from "node:path";
import { argv } from "node:process";
-import { jinja_svg_sets } from "./tools/jinja_svg_catalog.js";
+import type { Config as SvgoConfig } from "svgo";
+import { type IconSet, type JinjaMacro, jinja_svg_sets } from "./tools/jinja_svg_catalog.ts";
-const HERE = `${dirname(argv[1])}/`;
+const HERE = `${dirname(argv[1] || "")}/`;
const dest = resolve(HERE, "../../searx/templates/simple/icons.html");
-/** @type import("./tools/jinja_svg_catalog.js").JinjaMacro[] */
-const searxng_jinja_macros = [
+const searxng_jinja_macros: JinjaMacro[] = [
{ name: "icon", class: "sxng-icon-set" },
{ name: "icon_small", class: "sxng-icon-set-small" },
{ name: "icon_big", class: "sxng-icon-set-big" }
];
-const sxng_icon_opts = {
+const sxng_icon_opts: SvgoConfig = {
multipass: true,
plugins: [
- { name: "removeTitle" },
- { name: "removeXMLNS" },
+ "removeTitle",
+ "removeXMLNS",
{
name: "addAttributesToSVGElement",
params: {
- attributes: [
- {
- "aria-hidden": "true"
- }
- ]
+ attributes: [{ "aria-hidden": "true" }]
}
}
]
};
-/**
- * @type import("./tools/jinja_svg_catalog.js").IconSet[]
- */
-const simple_icons = [
+const simple_icons: IconSet[] = [
{
base: resolve(HERE, "node_modules/ionicons/dist/svg"),
set: {
diff --git a/client/simple/tools/img.js b/client/simple/tools/img.ts
index 0b1b96ed8..db4e08645 100644
--- a/client/simple/tools/img.js
+++ b/client/simple/tools/img.ts
@@ -1,25 +1,26 @@
import fs from "node:fs";
import path from "node:path";
import sharp from "sharp";
+import type { Config } from "svgo";
import { optimize as svgo } from "svgo";
-/**
- * @typedef {object} Src2Dest - Mapping of src to dest
- * @property {string} src - Name of the source file.
- * @property {string} dest - Name of the destination file.
- */
+// Mapping of src to dest
+export type Src2Dest = {
+ // Name of the source file.
+ src: string;
+ // Name of the destination file.
+ dest: string;
+};
/**
* Convert a list of SVG files to PNG.
*
- * @param {Src2Dest[]} items - Array of SVG files (src: SVG, dest:PNG) to convert.
+ * @param items - Array of SVG files (src: SVG, dest:PNG) to convert.
*/
-async function svg2png(items) {
+export const svg2png = async (items: Src2Dest[]) => {
for (const item of items) {
try {
- fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => {
- if (err) throw err;
- });
+ fs.mkdirSync(path.dirname(item.dest), { recursive: true });
const info = await sharp(item.src)
.png({
@@ -35,23 +36,22 @@ async function svg2png(items) {
throw err;
}
}
-}
+};
/**
* Optimize SVG images for WEB.
*
- * @param {Src2Dest[]} items - Array of SVG files (src:SVG, dest:SVG) to optimize.
- * @param {import('svgo').Config} svgo_opts - Options passed to svgo.
+ * @param items - Array of SVG files (src:SVG, dest:SVG) to optimize.
+ * @param svgo_opts - Options passed to svgo.
*/
-async function svg2svg(items, svgo_opts) {
+export const svg2svg = (items: Src2Dest[], svgo_opts: Config) => {
for (const item of items) {
try {
- fs.mkdir(path.dirname(item.dest), { recursive: true }, (err) => {
- if (err) throw err;
- });
+ fs.mkdirSync(path.dirname(item.dest), { recursive: true });
const raw = fs.readFileSync(item.src, "utf8");
const opt = svgo(raw, svgo_opts);
+
fs.writeFileSync(item.dest, opt.data);
console.log(`[svg2svg] optimized: ${item.dest} -- src: ${item.src}`);
} catch (err) {
@@ -59,6 +59,4 @@ async function svg2svg(items, svgo_opts) {
throw err;
}
}
-}
-
-export { svg2png, svg2svg };
+};
diff --git a/client/simple/tools/jinja_svg_catalog.js b/client/simple/tools/jinja_svg_catalog.ts
index b7b0347b5..1fa1a6676 100644
--- a/client/simple/tools/jinja_svg_catalog.js
+++ b/client/simple/tools/jinja_svg_catalog.ts
@@ -2,55 +2,56 @@ import fs from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { Edge } from "edge.js";
-import { optimize as svgo } from "svgo";
+import { type Config as SvgoConfig, optimize as svgo } from "svgo";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __jinja_class_placeholder__ = "__jinja_class_placeholder__";
-// -- types
-
-/**
- * @typedef {object} IconSet - A set of icons
- * @property {object} set - Object of SVG icons, where property name is the
- * name of the icon and value is the src of the SVG (relative to base).
- * @property {string} base - Folder in which the SVG src files are located.
- * @property {import("svgo").Config} svgo_opts - svgo options for this set.
- */
-
-/**
- * @typedef {object} IconSVG - Mapping of icon name to SVG source file.
- * @property {string} name - Name of the icon isource file.
- * @property {string} src - Name of the destination file.
- * @property {import("svgo").Config} svgo_opts - Options passed to svgo.
- */
-
-/**
- * @typedef {object} JinjaMacro - Arguments to create a jinja macro
- * @property {string} name - Name of the jinja macro.
- * @property {string} class - SVG's class name (value of XML class attribute)
- */
-
-// -- functions
+// A set of icons
+export type IconSet = {
+ // Object of SVG icons, where property name is the name of the icon and value is the src of the SVG (relative to base)
+ set: Record<string, string>;
+ // Folder in which the SVG src files are located
+ base: string;
+ // svgo options for this set
+ svgo_opts: SvgoConfig;
+};
+
+// Mapping of icon name to SVG source file
+type IconSVG = {
+ // Name of the icon isource file
+ name: string;
+ // Name of the destination file
+ src: string;
+ // Options passed to svgo
+ svgo_opts: SvgoConfig;
+};
+
+// Arguments to create a jinja macro
+export type JinjaMacro = {
+ // Name of the jinja macro
+ name: string;
+ // SVG's class name (value of XML class attribute)
+ class: string;
+};
/**
* Generate a jinja template with a catalog of SVG icons that can be
- * used in in other HTML jinja templates.
+ * used in other HTML jinja templates.
*
- * @param {string} dest - filename of the generate jinja template.
- * @param {JinjaMacro} macros - Jinja macros to create.
- * @param {IconSVG[]} items - Array of SVG items.
+ * @param dest - filename of the generate jinja template.
+ * @param macros - Jinja macros to create.
+ * @param items - Array of SVG items.
*/
-
-function jinja_svg_catalog(dest, macros, items) {
- const svg_catalog = {};
+export const jinja_svg_catalog = (dest: string, macros: JinjaMacro[], items: IconSVG[]) => {
+ const svg_catalog: Record<string, string> = {};
const edge_template = resolve(__dirname, "jinja_svg_catalog.html.edge");
- items.forEach((item) => {
- /** @type {import("svgo").Config} */
- // JSON.stringify & JSON.parse are used to create a deep copy of the
- // item.svgo_opts object
- const svgo_opts = JSON.parse(JSON.stringify(item.svgo_opts));
- svgo_opts.plugins.push({
+ for (const item of items) {
+ // JSON.stringify & JSON.parse are used to create a deep copy of the item.svgo_opts object
+ const svgo_opts: SvgoConfig = JSON.parse(JSON.stringify(item.svgo_opts));
+
+ svgo_opts.plugins?.push({
name: "addClassesToSVGElement",
params: {
classNames: [__jinja_class_placeholder__]
@@ -60,12 +61,13 @@ function jinja_svg_catalog(dest, macros, items) {
try {
const raw = fs.readFileSync(item.src, "utf8");
const opt = svgo(raw, svgo_opts);
+
svg_catalog[item.name] = opt.data;
} catch (err) {
console.error(`ERROR: jinja_svg_catalog processing ${item.name} src: ${item.src} -- ${err}`);
throw err;
}
- });
+ }
fs.mkdir(dirname(dest), { recursive: true }, (err) => {
if (err) throw err;
@@ -85,35 +87,34 @@ function jinja_svg_catalog(dest, macros, items) {
fs.writeFileSync(dest, jinjatmpl);
console.log(`[jinja_svg_catalog] created: ${dest}`);
-}
+};
/**
* Calls jinja_svg_catalog for a collection of icon sets where each set has its
* own parameters.
*
- * @param {string} dest - filename of the generate jinja template.
- * @param {JinjaMacro} macros - Jinja macros to create.
- * @param {IconSet[]} sets - Array of SVG sets.
+ * @param dest - filename of the generate jinja template.
+ * @param macros - Jinja macros to create.
+ * @param sets - Array of SVG sets.
*/
-function jinja_svg_sets(dest, macros, sets) {
- /** @type IconSVG[] */
- const items = [];
- const all = [];
+export const jinja_svg_sets = (dest: string, macros: JinjaMacro[], sets: IconSet[]) => {
+ const items: IconSVG[] = [];
+ const all: string[] = [];
+
for (const obj of sets) {
for (const [name, file] of Object.entries(obj.set)) {
if (all.includes(name)) {
throw new Error(`ERROR: ${name} has already been defined`);
}
+
+ all.push(name);
items.push({
name: name,
src: resolve(obj.base, file),
svgo_opts: obj.svgo_opts
});
}
- jinja_svg_catalog(dest, macros, items);
}
-}
-
-// -- exports
-export { jinja_svg_sets, jinja_svg_catalog };
+ jinja_svg_catalog(dest, macros, items);
+};
diff --git a/client/simple/tools/plg.js b/client/simple/tools/plg.js
deleted file mode 100644
index 74e488fc4..000000000
--- a/client/simple/tools/plg.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Custom vite plugins to build the web-client components of the simple theme.
- *
- * HINT:
- *
- * This is an inital implementation for the migration of the build process
- * from grunt to vite. For fully support (vite: build & serve) more work is
- * needed.
- */
-
-import { svg2png, svg2svg } from "./img.js";
-
-/**
- * Vite plugin to convert a list of SVG files to PNG.
- *
- * @param {import('./img.js').Src2Dest[]} items - Array of SVG files (src: SVG, dest:PNG) to convert.
- */
-function plg_svg2png(items) {
- return {
- name: "searxng-simple-svg2png",
- apply: "build", // or 'serve'
- async writeBundle() {
- await svg2png(items);
- }
- };
-}
-
-/**
- * Vite plugin to optimize SVG images for WEB.
- *
- * @param {import('./img.js').Src2Dest[]} items - Array of SVG files (src:SVG, dest:SVG) to optimize.
- * @param {import('svgo').Config} svgo_opts - Options passed to svgo.
- */
-function plg_svg2svg(items, svgo_opts) {
- return {
- name: "searxng-simple-svg2png",
- apply: "build", // or 'serve'
- async writeBundle() {
- await svg2svg(items, svgo_opts);
- }
- };
-}
-
-export { plg_svg2png, plg_svg2svg };
diff --git a/client/simple/tools/plg.ts b/client/simple/tools/plg.ts
new file mode 100644
index 000000000..2db891d4f
--- /dev/null
+++ b/client/simple/tools/plg.ts
@@ -0,0 +1,43 @@
+/**
+ * Custom vite plugins to build the web-client components of the simple theme.
+ *
+ * HINT:
+ * This is an inital implementation for the migration of the build process
+ * from grunt to vite. For fully support (vite: build & serve) more work is
+ * needed.
+ */
+
+import type { Config } from "svgo";
+import type { Plugin } from "vite";
+import { type Src2Dest, svg2png, svg2svg } from "./img.ts";
+
+/**
+ * Vite plugin to convert a list of SVG files to PNG.
+ *
+ * @param items - Array of SVG files (src: SVG, dest:PNG) to convert.
+ */
+export const plg_svg2png = (items: Src2Dest[]): Plugin => {
+ return {
+ name: "searxng-simple-svg2png",
+ apply: "build",
+ async writeBundle() {
+ await svg2png(items);
+ }
+ };
+};
+
+/**
+ * Vite plugin to optimize SVG images for WEB.
+ *
+ * @param items - Array of SVG files (src:SVG, dest:SVG) to optimize.
+ * @param svgo_opts - Options passed to svgo.
+ */
+export const plg_svg2svg = (items: Src2Dest[], svgo_opts: Config): Plugin => {
+ return {
+ name: "searxng-simple-svg2svg",
+ apply: "build",
+ writeBundle() {
+ svg2svg(items, svgo_opts);
+ }
+ };
+};
diff --git a/client/simple/tsconfig.json b/client/simple/tsconfig.json
new file mode 100644
index 000000000..dbc3acdf7
--- /dev/null
+++ b/client/simple/tsconfig.json
@@ -0,0 +1,40 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig.json",
+ "compilerOptions": {
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "target": "ES2022",
+
+ "allowImportingTsExtensions": true,
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "incremental": true,
+ "noEmit": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+
+ "strict": true,
+ "allowUnreachableCode": false,
+ "allowUnusedLabels": false,
+ "exactOptionalPropertyTypes": false,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitOverride": true,
+ "noImplicitReturns": true,
+ "noPropertyAccessFromIndexSignature": false,
+ "noUncheckedIndexedAccess": true,
+ "noUncheckedSideEffectImports": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "verbatimModuleSyntax": true,
+
+ "baseUrl": ".",
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
+ "types": ["vite/client"]
+ },
+ "include": ["./"],
+ "exclude": ["./node_modules/"]
+}
diff --git a/client/simple/vite.config.js b/client/simple/vite.config.ts
index b2d409db9..78ca07a2c 100644
--- a/client/simple/vite.config.js
+++ b/client/simple/vite.config.ts
@@ -3,104 +3,89 @@
*/
import { resolve } from "node:path";
-import { defineConfig } from "vite";
-import { viteStaticCopy } from "vite-plugin-static-copy";
-import { plg_svg2png, plg_svg2svg } from "./tools/plg.js";
+import browserslistToEsbuild from "browserslist-to-esbuild";
+import { browserslistToTargets } from "lightningcss";
+import type { Config } from "svgo";
+import type { UserConfig } from "vite";
+import { browserslist } from "./package.json";
+import { plg_svg2png, plg_svg2svg } from "./tools/plg";
-const ROOT = "../.."; // root of the git reposetory
+const ROOT = "../../"; // root of the git repository
const PATH = {
- dist: resolve(ROOT, "searx/static/themes/simple"),
- // dist: resolve(ROOT, "client/simple/dist"),
-
- src: "src",
- modules: "node_modules",
- brand: "src/brand",
- static: resolve(ROOT, "client/simple/static"),
- leaflet: resolve(ROOT, "client/simple/node_modules/leaflet/dist"),
- templates: resolve(ROOT, "searx/templates/simple")
+ brand: "src/brand/",
+ dist: resolve(ROOT, "searx/static/themes/simple/"),
+ modules: "node_modules/",
+ src: "src/",
+ templates: resolve(ROOT, "searx/templates/simple/")
};
-/**
- * @type {import('svgo').Config}
- */
-const svg2svg_opts = {
+const svg2svg_opts: Config = {
plugins: [{ name: "preset-default" }, "sortAttrs", "convertStyleToAttrs"]
};
-/**
- * @type {import('svgo').Config}
- */
-const svg2svg_favicon_opts = {
+const svg2svg_favicon_opts: Config = {
plugins: [{ name: "preset-default" }, "sortAttrs"]
};
-export default defineConfig({
- root: PATH.src,
+export default {
+ base: "/static/themes/simple/",
+ publicDir: "static/",
mode: "production",
// mode: "development",
- // FIXME: missing CCS sourcemaps!!
- // see: https://github.com/vitejs/vite/discussions/13845#discussioncomment-11992084
- //
- // what I have tried so far (see config below):
- //
- // - build.sourcemap
- // - esbuild.sourcemap
- // - css.preprocessorOptions.less.sourceMap
- css: {
- devSourcemap: true
- }, // end: css
-
build: {
- target: ["chrome87", "edge88", "firefox78", "safari14"],
+ target: browserslistToEsbuild(browserslist),
+ cssTarget: browserslistToEsbuild(browserslist),
manifest: "manifest.json",
emptyOutDir: true,
assetsDir: "",
outDir: PATH.dist,
sourcemap: true,
- minify: "esbuild",
- cssMinify: "esbuild",
rollupOptions: {
input: {
// build CSS files
- "css/searxng.min.css": `${PATH.src}/less/style-ltr.less`,
- "css/searxng-rtl.min.css": `${PATH.src}/less/style-rtl.less`,
- "css/rss.min.css": `${PATH.src}/less/rss.less`,
+ "searxng-ltr.min.css": `${PATH.src}/less/style-ltr.less`,
+ "searxng-rtl.min.css": `${PATH.src}/less/style-rtl.less`,
+ "rss.min.css": `${PATH.src}/less/rss.less`,
+
+ // build script files
+ "searxng.min": `${PATH.src}/js/main/index.ts`,
- // build JS files
- "js/searxng.head.min": `${PATH.src}/js/searxng.head.js`,
- "js/searxng.min": `${PATH.src}/js/searxng.js`
+ // ol
+ "ol.min": `${PATH.src}/js/pkg/ol.ts`,
+ "ol.min.css": `${PATH.modules}/ol/ol.css`
},
// file naming conventions / pathnames are relative to outDir (PATH.dist)
output: {
- entryFileNames: "[name].js",
- chunkFileNames: "[name].js",
- assetFileNames: "[name].[ext]"
- // Vite does not support "rollupOptions.output.sourcemap".
- // Please use "build.sourcemap" instead.
- // sourcemap: true,
+ entryFileNames: "js/[name].js",
+ chunkFileNames: "js/[name].js",
+ assetFileNames: ({ names }) => {
+ const [name] = names;
+
+ const extension = name?.split(".").pop();
+ switch (extension) {
+ case "css":
+ return `css/[name][extname]`;
+ case "js":
+ return `js/[name][extname]`;
+ case "png":
+ case "svg":
+ return `img/[name][extname]`;
+ default:
+ console.warn("Unknown asset:", name);
+ return `[name][extname]`;
+ }
+ }
}
}
}, // end: build
plugins: [
- // Leaflet
-
- viteStaticCopy({
- targets: [
- { src: `${PATH.leaflet}/leaflet.{js,js.map}`, dest: `${PATH.dist}/js` },
- { src: `${PATH.leaflet}/images/*.png`, dest: `${PATH.dist}/css/images/` },
- { src: `${PATH.leaflet}/*.{css,css.map}`, dest: `${PATH.dist}/css` },
- { src: `${PATH.static}/**/*`, dest: PATH.dist }
- ]
- }),
-
// -- svg images
-
plg_svg2svg(
[
{ src: `${PATH.src}/svg/empty_favicon.svg`, dest: `${PATH.dist}/img/empty_favicon.svg` },
@@ -111,7 +96,6 @@ export default defineConfig({
),
// SearXNG brand (static)
-
plg_svg2png([
{ src: `${PATH.brand}/searxng-wordmark.svg`, dest: `${PATH.dist}/img/favicon.png` },
{ src: `${PATH.brand}/searxng.svg`, dest: `${PATH.dist}/img/searxng.png` }
@@ -137,5 +121,25 @@ export default defineConfig({
[{ src: `${PATH.brand}/searxng-wordmark.svg`, dest: `${PATH.templates}/searxng-wordmark.min.svg` }],
svg2svg_opts
)
- ] // end: plugins
-});
+ ], // end: plugins
+
+ // FIXME: missing CCS sourcemaps!!
+ // see: https://github.com/vitejs/vite/discussions/13845#discussioncomment-11992084
+ //
+ // what I have tried so far (see config below):
+ //
+ // - build.sourcemap
+ // - esbuild.sourcemap
+ // - css.preprocessorOptions.less.sourceMap
+ css: {
+ transformer: "lightningcss",
+ lightningcss: {
+ targets: browserslistToTargets(browserslist)
+ },
+ devSourcemap: true
+ }, // end: css
+
+ experimental: {
+ enableNativePlugin: true
+ } // end: experimental
+} satisfies UserConfig;
diff --git a/docs/dev/makefile.rst b/docs/dev/makefile.rst
index ea7ddecd8..fa81f3d23 100644
--- a/docs/dev/makefile.rst
+++ b/docs/dev/makefile.rst
@@ -103,8 +103,8 @@ Node.js environment (``make node.env``)
Node.js_ version {{version.node}} or higher is required to build the themes.
If the requirement is not met, the build chain uses nvm_ (Node Version
- Manager) to install latest LTS of Node.js_ locally: there is no need to
- install nvm_ or npm_ on your system.
+ Manager) to install Node.js_ locally: there is no need to install
+ nvm_ or npm_ on your system.
To install NVM_ and Node.js_ in once you can use :ref:`make nvm.nodejs`.
@@ -150,7 +150,7 @@ setup.
``make nvm.nodejs``
-------------------
-Install latest Node.js_ LTS locally (uses nvm_)::
+Install latest Node.js_ locally (uses nvm_)::
$ make nvm.nodejs
INFO: install (update) NVM at /share/searxng/.nvm
diff --git a/package.json b/package.json
index c26fa2742..790ab8648 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,6 @@
{
"name": "searxng.org/devtools",
+ "type": "module",
"dependencies": {
"pyright": "^1.1.403"
},
diff --git a/searx/templates/simple/base.html b/searx/templates/simple/base.html
index deac295b7..2170ccea5 100644
--- a/searx/templates/simple/base.html
+++ b/searx/templates/simple/base.html
@@ -8,21 +8,21 @@
<meta name="referrer" content="no-referrer">
<meta name="robots" content="noarchive">
<meta name="viewport" content="width=device-width, initial-scale=1">
- <meta name="HandheldFriendly" content="True">
- <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
{% block meta %}{% endblock %}
{% if rtl %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/searxng-rtl.min.css') }}" type="text/css" media="screen">
{% else %}
- <link rel="stylesheet" href="{{ url_for('static', filename='css/searxng.min.css') }}" type="text/css" media="screen">
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/searxng-ltr.min.css') }}" type="text/css" media="screen">
{% endif %}
{% if get_setting('server.limiter') or get_setting('server.public_instance') %}
<link rel="stylesheet" href="{{ url_for('client_token', token=link_token) }}" type="text/css">
{% endif %}
- <!--[if gte IE 9]>-->
- <script src="{{ url_for('static', filename='js/searxng.head.min.js') }}" client_settings="{{ client_settings }}"></script>
- <!--<![endif]-->
+ <script>
+ // update the css
+ document.documentElement.classList.remove('no-js');
+ document.documentElement.classList.add('js');
+ </script>
{% block head %}
<link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ opensearch_url }}">
{% endblock %}
@@ -82,8 +82,6 @@
{% endfor %}
</p>
</footer>
- <!--[if gte IE 9]>-->
- <script src="{{ url_for('static', filename='js/searxng.min.js') }}"></script>
- <!--<![endif]-->
+ <script type="module" src="{{ url_for('static', filename='js/searxng.min.js') }}" client_settings="{{ client_settings }}"></script>
</body>
</html>
diff --git a/utils/lib_nvm.sh b/utils/lib_nvm.sh
index 04a9ddbbf..8351e6d22 100755
--- a/utils/lib_nvm.sh
+++ b/utils/lib_nvm.sh
@@ -94,7 +94,7 @@ nvm.: use nvm (without dot) to execute nvm commands directly
install : install NVM locally at $(git rev-parse --show-toplevel)/${NVM_LOCAL_FOLDER}
clean : remove NVM installation
status : prompt some status information about nvm & node
- nodejs : install Node.js latest LTS
+ nodejs : install latest Node.js
cmd ... : run command ... in NVM environment
bash : start bash interpreter with NVM environment sourced
EOF
@@ -163,7 +163,7 @@ nvm.status() {
info_msg "NVM is installed at ${NVM_DIR}"
else
warn_msg "NVM is not installed"
- info_msg "to install NVM and Node.js (LTS) use: ${main_cmd} nvm.nodejs"
+ info_msg "to install NVM and Node.js use: ${main_cmd} nvm.nodejs"
fi
}
diff --git a/utils/lib_sxng_node.sh b/utils/lib_sxng_node.sh
index c072dd40d..79a1f0c1f 100755
--- a/utils/lib_sxng_node.sh
+++ b/utils/lib_sxng_node.sh
@@ -4,7 +4,7 @@
declare _Blue
declare _creset
-export NODE_MINIMUM_VERSION="18.17.0"
+export NODE_MINIMUM_VERSION="23.6.0"
node.help() {
cat <<EOF