mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	Merge develop into test_server-utils
				
					
				
			This commit is contained in:
		
						commit
						892734bce3
					
				| @ -1,12 +1,17 @@ | |||||||
| [Desktop Entry] | [Desktop Entry] | ||||||
| <% if (productName) { %>Name=<%= productName %> | <%= | ||||||
| <% } %><% if (description) { %>Comment=<%= description %> | Object.entries({ | ||||||
| <% } %><% if (genericName) { %>GenericName=<%= genericName %> |     "Name": productName, | ||||||
| <% } %><% if (name) { %>Exec=<%= name %> %U |     "Comment": description, | ||||||
| Icon=<%= name %> |     "GenericName": genericName, | ||||||
| <% } %>Type=Application |     "Exec": name ? `${name} %U` : undefined, | ||||||
| StartupNotify=true |     "Icon": name, | ||||||
| <% if (productName) { %>StartupWMClass=<%= productName %> |     "Type": "Application", | ||||||
| <% } if (categories && categories.length) { %>Categories=<%= categories.join(';') %>; |     "StartupNotify": "true", | ||||||
| <% } %><% if (mimeType && mimeType.length) { %>MimeType=<%= mimeType.join(';') %>; |     "StartupWMClass": productName, | ||||||
| <% } %> |     "Categories": categories?.length ? `${categories.join(";")};` : undefined, | ||||||
|  |     "MimeType": mimeType?.length ? `${mimeType.join(";")};` : undefined | ||||||
|  | }) | ||||||
|  | .map(line => line[1] ? line.join("=") : undefined) | ||||||
|  | .filter(line => !!line) | ||||||
|  | .join("\n")%> | ||||||
| @ -26,6 +26,8 @@ electronDl({ saveAs: true }); | |||||||
| // needed for excalidraw export https://github.com/zadam/trilium/issues/4271
 | // needed for excalidraw export https://github.com/zadam/trilium/issues/4271
 | ||||||
| electron.app.commandLine.appendSwitch("enable-experimental-web-platform-features"); | electron.app.commandLine.appendSwitch("enable-experimental-web-platform-features"); | ||||||
| 
 | 
 | ||||||
|  | electron.app.userAgentFallback = `${electron.app.getName()} ${electron.app.getVersion()}`; | ||||||
|  | 
 | ||||||
| // Quit when all windows are closed, except on macOS. There, it's common
 | // Quit when all windows are closed, except on macOS. There, it's common
 | ||||||
| // for applications and their menu bar to stay active until the user quits
 | // for applications and their menu bar to stay active until the user quits
 | ||||||
| // explicitly with Cmd + Q.
 | // explicitly with Cmd + Q.
 | ||||||
|  | |||||||
							
								
								
									
										165
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										165
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -69,6 +69,7 @@ | |||||||
|         "katex": "0.16.21", |         "katex": "0.16.21", | ||||||
|         "knockout": "3.5.1", |         "knockout": "3.5.1", | ||||||
|         "leaflet": "1.9.4", |         "leaflet": "1.9.4", | ||||||
|  |         "leaflet-gpx": "2.1.2", | ||||||
|         "mark.js": "8.11.1", |         "mark.js": "8.11.1", | ||||||
|         "marked": "15.0.6", |         "marked": "15.0.6", | ||||||
|         "mermaid": "11.4.1", |         "mermaid": "11.4.1", | ||||||
| @ -85,7 +86,6 @@ | |||||||
|         "sanitize-filename": "1.6.3", |         "sanitize-filename": "1.6.3", | ||||||
|         "sanitize-html": "2.14.0", |         "sanitize-html": "2.14.0", | ||||||
|         "sax": "1.4.1", |         "sax": "1.4.1", | ||||||
|         "semver": "7.7.0", |  | ||||||
|         "serve-favicon": "2.5.0", |         "serve-favicon": "2.5.0", | ||||||
|         "session-file-store": "1.5.0", |         "session-file-store": "1.5.0", | ||||||
|         "source-map-support": "0.5.21", |         "source-map-support": "0.5.21", | ||||||
| @ -112,7 +112,7 @@ | |||||||
|         "@electron-forge/maker-zip": "7.6.1", |         "@electron-forge/maker-zip": "7.6.1", | ||||||
|         "@electron-forge/plugin-auto-unpack-natives": "7.6.1", |         "@electron-forge/plugin-auto-unpack-natives": "7.6.1", | ||||||
|         "@electron/rebuild": "3.7.1", |         "@electron/rebuild": "3.7.1", | ||||||
|         "@playwright/test": "1.50.0", |         "@playwright/test": "1.50.1", | ||||||
|         "@types/archiver": "6.0.3", |         "@types/archiver": "6.0.3", | ||||||
|         "@types/better-sqlite3": "7.6.12", |         "@types/better-sqlite3": "7.6.12", | ||||||
|         "@types/bootstrap": "5.2.10", |         "@types/bootstrap": "5.2.10", | ||||||
| @ -132,14 +132,14 @@ | |||||||
|         "@types/jasmine": "5.1.5", |         "@types/jasmine": "5.1.5", | ||||||
|         "@types/jquery": "3.5.32", |         "@types/jquery": "3.5.32", | ||||||
|         "@types/jsdom": "21.1.7", |         "@types/jsdom": "21.1.7", | ||||||
|  |         "@types/leaflet-gpx": "1.3.7", | ||||||
|         "@types/mime-types": "2.1.4", |         "@types/mime-types": "2.1.4", | ||||||
|         "@types/multer": "1.4.12", |         "@types/multer": "1.4.12", | ||||||
|         "@types/node": "22.12.0", |         "@types/node": "22.13.1", | ||||||
|         "@types/react": "18.3.18", |         "@types/react": "18.3.18", | ||||||
|         "@types/safe-compare": "1.1.2", |         "@types/safe-compare": "1.1.2", | ||||||
|         "@types/sanitize-html": "2.13.0", |         "@types/sanitize-html": "2.13.0", | ||||||
|         "@types/sax": "1.2.7", |         "@types/sax": "1.2.7", | ||||||
|         "@types/semver": "7.5.8", |  | ||||||
|         "@types/serve-favicon": "2.5.7", |         "@types/serve-favicon": "2.5.7", | ||||||
|         "@types/session-file-store": "1.2.5", |         "@types/session-file-store": "1.2.5", | ||||||
|         "@types/source-map-support": "0.5.10", |         "@types/source-map-support": "0.5.10", | ||||||
| @ -149,7 +149,7 @@ | |||||||
|         "@types/ws": "8.5.14", |         "@types/ws": "8.5.14", | ||||||
|         "@types/xml2js": "0.4.14", |         "@types/xml2js": "0.4.14", | ||||||
|         "@types/yargs": "17.0.33", |         "@types/yargs": "17.0.33", | ||||||
|         "@vitest/coverage-v8": "3.0.4", |         "@vitest/coverage-v8": "3.0.5", | ||||||
|         "cross-env": "7.0.3", |         "cross-env": "7.0.3", | ||||||
|         "electron": "34.0.2", |         "electron": "34.0.2", | ||||||
|         "esm": "3.2.25", |         "esm": "3.2.25", | ||||||
| @ -164,7 +164,7 @@ | |||||||
|         "tsx": "4.19.2", |         "tsx": "4.19.2", | ||||||
|         "typedoc": "0.27.6", |         "typedoc": "0.27.6", | ||||||
|         "typescript": "5.7.3", |         "typescript": "5.7.3", | ||||||
|         "vitest": "3.0.4", |         "vitest": "3.0.5", | ||||||
|         "webpack": "5.97.1", |         "webpack": "5.97.1", | ||||||
|         "webpack-cli": "6.0.1", |         "webpack-cli": "6.0.1", | ||||||
|         "webpack-dev-middleware": "7.4.2" |         "webpack-dev-middleware": "7.4.2" | ||||||
| @ -2878,13 +2878,13 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@playwright/test": { |     "node_modules/@playwright/test": { | ||||||
|       "version": "1.50.0", |       "version": "1.50.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.0.tgz", |       "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", | ||||||
|       "integrity": "sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==", |       "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "Apache-2.0", |       "license": "Apache-2.0", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "playwright": "1.50.0" |         "playwright": "1.50.1" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "playwright": "cli.js" |         "playwright": "cli.js" | ||||||
| @ -3839,6 +3839,16 @@ | |||||||
|         "@types/geojson": "*" |         "@types/geojson": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/leaflet-gpx": { | ||||||
|  |       "version": "1.3.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/leaflet-gpx/-/leaflet-gpx-1.3.7.tgz", | ||||||
|  |       "integrity": "sha512-IDshIOLZ7dUUjRiCE3DuJcAGavgUCw0xQ93dc/3YvsA6jrFc+nx8eXr0tqZIf2SaWMgqiDj/n7N24WWNh/898g==", | ||||||
|  |       "dev": true, | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/leaflet": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@types/linkify-it": { |     "node_modules/@types/linkify-it": { | ||||||
|       "version": "5.0.0", |       "version": "5.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", |       "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", | ||||||
| @ -3897,9 +3907,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@types/node": { |     "node_modules/@types/node": { | ||||||
|       "version": "22.12.0", |       "version": "22.13.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz", |       "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", | ||||||
|       "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", |       "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "undici-types": "~6.20.0" |         "undici-types": "~6.20.0" | ||||||
| @ -3990,13 +4000,6 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@types/semver": { |  | ||||||
|       "version": "7.5.8", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", |  | ||||||
|       "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", |  | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |  | ||||||
|     }, |  | ||||||
|     "node_modules/@types/send": { |     "node_modules/@types/send": { | ||||||
|       "version": "0.17.4", |       "version": "0.17.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", |       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", | ||||||
| @ -4151,9 +4154,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/coverage-v8": { |     "node_modules/@vitest/coverage-v8": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.5.tgz", | ||||||
|       "integrity": "sha512-f0twgRCHgbs24Dp8cLWagzcObXMcuKtAwgxjJV/nnysPAJJk1JiKu/W0gIehZLmkljhJXU/E0/dmuQzsA/4jhA==", |       "integrity": "sha512-zOOWIsj5fHh3jjGwQg+P+J1FW3s4jBu1Zqga0qW60yutsBtqEqNEJKWYh7cYn1yGD+1bdPsPdC/eL4eVK56xMg==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @ -4174,8 +4177,8 @@ | |||||||
|         "url": "https://opencollective.com/vitest" |         "url": "https://opencollective.com/vitest" | ||||||
|       }, |       }, | ||||||
|       "peerDependencies": { |       "peerDependencies": { | ||||||
|         "@vitest/browser": "3.0.4", |         "@vitest/browser": "3.0.5", | ||||||
|         "vitest": "3.0.4" |         "vitest": "3.0.5" | ||||||
|       }, |       }, | ||||||
|       "peerDependenciesMeta": { |       "peerDependenciesMeta": { | ||||||
|         "@vitest/browser": { |         "@vitest/browser": { | ||||||
| @ -4184,14 +4187,14 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/expect": { |     "node_modules/@vitest/expect": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.5.tgz", | ||||||
|       "integrity": "sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==", |       "integrity": "sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/spy": "3.0.4", |         "@vitest/spy": "3.0.5", | ||||||
|         "@vitest/utils": "3.0.4", |         "@vitest/utils": "3.0.5", | ||||||
|         "chai": "^5.1.2", |         "chai": "^5.1.2", | ||||||
|         "tinyrainbow": "^2.0.0" |         "tinyrainbow": "^2.0.0" | ||||||
|       }, |       }, | ||||||
| @ -4200,13 +4203,13 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/mocker": { |     "node_modules/@vitest/mocker": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.5.tgz", | ||||||
|       "integrity": "sha512-gEef35vKafJlfQbnyOXZ0Gcr9IBUsMTyTLXsEQwuyYAerpHqvXhzdBnDFuHLpFqth3F7b6BaFr4qV/Cs1ULx5A==", |       "integrity": "sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/spy": "3.0.4", |         "@vitest/spy": "3.0.5", | ||||||
|         "estree-walker": "^3.0.3", |         "estree-walker": "^3.0.3", | ||||||
|         "magic-string": "^0.30.17" |         "magic-string": "^0.30.17" | ||||||
|       }, |       }, | ||||||
| @ -4227,9 +4230,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/pretty-format": { |     "node_modules/@vitest/pretty-format": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.5.tgz", | ||||||
|       "integrity": "sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==", |       "integrity": "sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @ -4240,13 +4243,13 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/runner": { |     "node_modules/@vitest/runner": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.5.tgz", | ||||||
|       "integrity": "sha512-dKHzTQ7n9sExAcWH/0sh1elVgwc7OJ2lMOBrAm73J7AH6Pf9T12Zh3lNE1TETZaqrWFXtLlx3NVrLRb5hCK+iw==", |       "integrity": "sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/utils": "3.0.4", |         "@vitest/utils": "3.0.5", | ||||||
|         "pathe": "^2.0.2" |         "pathe": "^2.0.2" | ||||||
|       }, |       }, | ||||||
|       "funding": { |       "funding": { | ||||||
| @ -4261,13 +4264,13 @@ | |||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/snapshot": { |     "node_modules/@vitest/snapshot": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.5.tgz", | ||||||
|       "integrity": "sha512-+p5knMLwIk7lTQkM3NonZ9zBewzVp9EVkVpvNta0/PlFWpiqLaRcF4+33L1it3uRUCh0BGLOaXPPGEjNKfWb4w==", |       "integrity": "sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/pretty-format": "3.0.4", |         "@vitest/pretty-format": "3.0.5", | ||||||
|         "magic-string": "^0.30.17", |         "magic-string": "^0.30.17", | ||||||
|         "pathe": "^2.0.2" |         "pathe": "^2.0.2" | ||||||
|       }, |       }, | ||||||
| @ -4283,9 +4286,9 @@ | |||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/spy": { |     "node_modules/@vitest/spy": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.5.tgz", | ||||||
|       "integrity": "sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==", |       "integrity": "sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @ -4296,13 +4299,13 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@vitest/utils": { |     "node_modules/@vitest/utils": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.5.tgz", | ||||||
|       "integrity": "sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==", |       "integrity": "sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/pretty-format": "3.0.4", |         "@vitest/pretty-format": "3.0.5", | ||||||
|         "loupe": "^3.1.2", |         "loupe": "^3.1.2", | ||||||
|         "tinyrainbow": "^2.0.0" |         "tinyrainbow": "^2.0.0" | ||||||
|       }, |       }, | ||||||
| @ -11431,6 +11434,12 @@ | |||||||
|       "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", |       "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", | ||||||
|       "license": "BSD-2-Clause" |       "license": "BSD-2-Clause" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/leaflet-gpx": { | ||||||
|  |       "version": "2.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/leaflet-gpx/-/leaflet-gpx-2.1.2.tgz", | ||||||
|  |       "integrity": "sha512-lKoEPlAWel9KXn9keg6Dmyt7gmj5IYyD8CKuxivN+77GpZr2bpKliwFvZJxLUHmNu4fICmCySyxhm5qjZuvvQg==", | ||||||
|  |       "license": "BSD-2-Clause" | ||||||
|  |     }, | ||||||
|     "node_modules/limiter": { |     "node_modules/limiter": { | ||||||
|       "version": "1.1.5", |       "version": "1.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", |       "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", | ||||||
| @ -13302,13 +13311,13 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/playwright": { |     "node_modules/playwright": { | ||||||
|       "version": "1.50.0", |       "version": "1.50.1", | ||||||
|       "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.0.tgz", |       "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", | ||||||
|       "integrity": "sha512-+GinGfGTrd2IfX1TA4N2gNmeIksSb+IAe589ZH+FlmpV3MYTx6+buChGIuDLQwrGNCw2lWibqV50fU510N7S+w==", |       "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "Apache-2.0", |       "license": "Apache-2.0", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "playwright-core": "1.50.0" |         "playwright-core": "1.50.1" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "playwright": "cli.js" |         "playwright": "cli.js" | ||||||
| @ -13321,9 +13330,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/playwright-core": { |     "node_modules/playwright-core": { | ||||||
|       "version": "1.50.0", |       "version": "1.50.1", | ||||||
|       "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.0.tgz", |       "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", | ||||||
|       "integrity": "sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==", |       "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "Apache-2.0", |       "license": "Apache-2.0", | ||||||
|       "bin": { |       "bin": { | ||||||
| @ -14703,9 +14712,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/semver": { |     "node_modules/semver": { | ||||||
|       "version": "7.7.0", |       "version": "7.7.1", | ||||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", |       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", | ||||||
|       "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", |       "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", | ||||||
|       "license": "ISC", |       "license": "ISC", | ||||||
|       "bin": { |       "bin": { | ||||||
|         "semver": "bin/semver.js" |         "semver": "bin/semver.js" | ||||||
| @ -16838,9 +16847,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/vite-node": { |     "node_modules/vite-node": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.5.tgz", | ||||||
|       "integrity": "sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==", |       "integrity": "sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @ -17332,19 +17341,19 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/vitest": { |     "node_modules/vitest": { | ||||||
|       "version": "3.0.4", |       "version": "3.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.4.tgz", |       "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.5.tgz", | ||||||
|       "integrity": "sha512-6XG8oTKy2gnJIFTHP6LD7ExFeNLxiTkK3CfMvT7IfR8IN+BYICCf0lXUQmX7i7JoxUP8QmeP4mTnWXgflu4yjw==", |       "integrity": "sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@vitest/expect": "3.0.4", |         "@vitest/expect": "3.0.5", | ||||||
|         "@vitest/mocker": "3.0.4", |         "@vitest/mocker": "3.0.5", | ||||||
|         "@vitest/pretty-format": "^3.0.4", |         "@vitest/pretty-format": "^3.0.5", | ||||||
|         "@vitest/runner": "3.0.4", |         "@vitest/runner": "3.0.5", | ||||||
|         "@vitest/snapshot": "3.0.4", |         "@vitest/snapshot": "3.0.5", | ||||||
|         "@vitest/spy": "3.0.4", |         "@vitest/spy": "3.0.5", | ||||||
|         "@vitest/utils": "3.0.4", |         "@vitest/utils": "3.0.5", | ||||||
|         "chai": "^5.1.2", |         "chai": "^5.1.2", | ||||||
|         "debug": "^4.4.0", |         "debug": "^4.4.0", | ||||||
|         "expect-type": "^1.1.0", |         "expect-type": "^1.1.0", | ||||||
| @ -17356,7 +17365,7 @@ | |||||||
|         "tinypool": "^1.0.2", |         "tinypool": "^1.0.2", | ||||||
|         "tinyrainbow": "^2.0.0", |         "tinyrainbow": "^2.0.0", | ||||||
|         "vite": "^5.0.0 || ^6.0.0", |         "vite": "^5.0.0 || ^6.0.0", | ||||||
|         "vite-node": "3.0.4", |         "vite-node": "3.0.5", | ||||||
|         "why-is-node-running": "^2.3.0" |         "why-is-node-running": "^2.3.0" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
| @ -17372,8 +17381,8 @@ | |||||||
|         "@edge-runtime/vm": "*", |         "@edge-runtime/vm": "*", | ||||||
|         "@types/debug": "^4.1.12", |         "@types/debug": "^4.1.12", | ||||||
|         "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", |         "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", | ||||||
|         "@vitest/browser": "3.0.4", |         "@vitest/browser": "3.0.5", | ||||||
|         "@vitest/ui": "3.0.4", |         "@vitest/ui": "3.0.5", | ||||||
|         "happy-dom": "*", |         "happy-dom": "*", | ||||||
|         "jsdom": "*" |         "jsdom": "*" | ||||||
|       }, |       }, | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @ -114,6 +114,7 @@ | |||||||
|     "katex": "0.16.21", |     "katex": "0.16.21", | ||||||
|     "knockout": "3.5.1", |     "knockout": "3.5.1", | ||||||
|     "leaflet": "1.9.4", |     "leaflet": "1.9.4", | ||||||
|  |     "leaflet-gpx": "2.1.2", | ||||||
|     "mark.js": "8.11.1", |     "mark.js": "8.11.1", | ||||||
|     "marked": "15.0.6", |     "marked": "15.0.6", | ||||||
|     "mermaid": "11.4.1", |     "mermaid": "11.4.1", | ||||||
| @ -130,7 +131,6 @@ | |||||||
|     "sanitize-filename": "1.6.3", |     "sanitize-filename": "1.6.3", | ||||||
|     "sanitize-html": "2.14.0", |     "sanitize-html": "2.14.0", | ||||||
|     "sax": "1.4.1", |     "sax": "1.4.1", | ||||||
|     "semver": "7.7.0", |  | ||||||
|     "serve-favicon": "2.5.0", |     "serve-favicon": "2.5.0", | ||||||
|     "session-file-store": "1.5.0", |     "session-file-store": "1.5.0", | ||||||
|     "source-map-support": "0.5.21", |     "source-map-support": "0.5.21", | ||||||
| @ -154,7 +154,7 @@ | |||||||
|     "@electron-forge/maker-zip": "7.6.1", |     "@electron-forge/maker-zip": "7.6.1", | ||||||
|     "@electron-forge/plugin-auto-unpack-natives": "7.6.1", |     "@electron-forge/plugin-auto-unpack-natives": "7.6.1", | ||||||
|     "@electron/rebuild": "3.7.1", |     "@electron/rebuild": "3.7.1", | ||||||
|     "@playwright/test": "1.50.0", |     "@playwright/test": "1.50.1", | ||||||
|     "@types/archiver": "6.0.3", |     "@types/archiver": "6.0.3", | ||||||
|     "@types/better-sqlite3": "7.6.12", |     "@types/better-sqlite3": "7.6.12", | ||||||
|     "@types/bootstrap": "5.2.10", |     "@types/bootstrap": "5.2.10", | ||||||
| @ -174,14 +174,14 @@ | |||||||
|     "@types/jasmine": "5.1.5", |     "@types/jasmine": "5.1.5", | ||||||
|     "@types/jquery": "3.5.32", |     "@types/jquery": "3.5.32", | ||||||
|     "@types/jsdom": "21.1.7", |     "@types/jsdom": "21.1.7", | ||||||
|  |     "@types/leaflet-gpx": "1.3.7", | ||||||
|     "@types/mime-types": "2.1.4", |     "@types/mime-types": "2.1.4", | ||||||
|     "@types/multer": "1.4.12", |     "@types/multer": "1.4.12", | ||||||
|     "@types/node": "22.12.0", |     "@types/node": "22.13.1", | ||||||
|     "@types/react": "18.3.18", |     "@types/react": "18.3.18", | ||||||
|     "@types/safe-compare": "1.1.2", |     "@types/safe-compare": "1.1.2", | ||||||
|     "@types/sanitize-html": "2.13.0", |     "@types/sanitize-html": "2.13.0", | ||||||
|     "@types/sax": "1.2.7", |     "@types/sax": "1.2.7", | ||||||
|     "@types/semver": "7.5.8", |  | ||||||
|     "@types/serve-favicon": "2.5.7", |     "@types/serve-favicon": "2.5.7", | ||||||
|     "@types/session-file-store": "1.2.5", |     "@types/session-file-store": "1.2.5", | ||||||
|     "@types/source-map-support": "0.5.10", |     "@types/source-map-support": "0.5.10", | ||||||
| @ -191,7 +191,7 @@ | |||||||
|     "@types/ws": "8.5.14", |     "@types/ws": "8.5.14", | ||||||
|     "@types/xml2js": "0.4.14", |     "@types/xml2js": "0.4.14", | ||||||
|     "@types/yargs": "17.0.33", |     "@types/yargs": "17.0.33", | ||||||
|     "@vitest/coverage-v8": "3.0.4", |     "@vitest/coverage-v8": "3.0.5", | ||||||
|     "cross-env": "7.0.3", |     "cross-env": "7.0.3", | ||||||
|     "electron": "34.0.2", |     "electron": "34.0.2", | ||||||
|     "esm": "3.2.25", |     "esm": "3.2.25", | ||||||
| @ -206,7 +206,7 @@ | |||||||
|     "tsx": "4.19.2", |     "tsx": "4.19.2", | ||||||
|     "typedoc": "0.27.6", |     "typedoc": "0.27.6", | ||||||
|     "typescript": "5.7.3", |     "typescript": "5.7.3", | ||||||
|     "vitest": "3.0.4", |     "vitest": "3.0.5", | ||||||
|     "webpack": "5.97.1", |     "webpack": "5.97.1", | ||||||
|     "webpack-cli": "6.0.1", |     "webpack-cli": "6.0.1", | ||||||
|     "webpack-dev-middleware": "7.4.2" |     "webpack-dev-middleware": "7.4.2" | ||||||
|  | |||||||
| @ -83,7 +83,7 @@ export type CommandMappings = { | |||||||
|     }; |     }; | ||||||
|     showExportDialog: CommandData & { |     showExportDialog: CommandData & { | ||||||
|         notePath: string; |         notePath: string; | ||||||
|         defaultType: "single"; |         defaultType: "single" | "subtree"; | ||||||
|     }; |     }; | ||||||
|     showDeleteNotesDialog: CommandData & { |     showDeleteNotesDialog: CommandData & { | ||||||
|         branchIdsToDelete: string[]; |         branchIdsToDelete: string[]; | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import noteTooltipService from "./services/note_tooltip.js"; | |||||||
| import bundleService from "./services/bundle.js"; | import bundleService from "./services/bundle.js"; | ||||||
| import toastService from "./services/toast.js"; | import toastService from "./services/toast.js"; | ||||||
| import noteAutocompleteService from "./services/note_autocomplete.js"; | import noteAutocompleteService from "./services/note_autocomplete.js"; | ||||||
| import macInit from "./services/mac_init.js"; |  | ||||||
| import electronContextMenu from "./menus/electron_context_menu.js"; | import electronContextMenu from "./menus/electron_context_menu.js"; | ||||||
| import glob from "./services/glob.js"; | import glob from "./services/glob.js"; | ||||||
| import { t } from "./services/i18n.js"; | import { t } from "./services/i18n.js"; | ||||||
| @ -35,8 +34,6 @@ if (utils.isElectron()) { | |||||||
|     initOnElectron(); |     initOnElectron(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| macInit.init(); |  | ||||||
| 
 |  | ||||||
| noteTooltipService.setupGlobalTooltip(); | noteTooltipService.setupGlobalTooltip(); | ||||||
| 
 | 
 | ||||||
| noteAutocompleteService.init(); | noteAutocompleteService.init(); | ||||||
|  | |||||||
| @ -1,26 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Mac specific initialization |  | ||||||
|  */ |  | ||||||
| import utils from "./utils.js"; |  | ||||||
| import shortcutService from "./shortcuts.js"; |  | ||||||
| 
 |  | ||||||
| function init() { |  | ||||||
|     if (utils.isElectron() && utils.isMac()) { |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+c", () => exec("copy")); |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+v", () => exec("paste")); |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+x", () => exec("cut")); |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+a", () => exec("selectAll")); |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+z", () => exec("undo")); |  | ||||||
|         shortcutService.bindGlobalShortcut("meta+y", () => exec("redo")); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function exec(cmd: string) { |  | ||||||
|     document.execCommand(cmd); |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default { |  | ||||||
|     init |  | ||||||
| }; |  | ||||||
| @ -1,9 +1,6 @@ | |||||||
| import utils from "./services/utils.js"; | import utils from "./services/utils.js"; | ||||||
| import macInit from "./services/mac_init.js"; |  | ||||||
| import ko from "knockout"; | import ko from "knockout"; | ||||||
| 
 | 
 | ||||||
| macInit.init(); |  | ||||||
| 
 |  | ||||||
| // TriliumNextTODO: properly make use of below types
 | // TriliumNextTODO: properly make use of below types
 | ||||||
| // type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
 | // type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
 | ||||||
| // type SetupModelStep = "sync-in-progress" | "setup-type" | "new-document-in-progress" | "sync-from-desktop";
 | // type SetupModelStep = "sync-in-progress" | "setup-type" | "new-document-in-progress" | "sync-from-desktop";
 | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -39,6 +39,7 @@ interface CustomGlobals { | |||||||
|     maxEntityChangeIdAtLoad: number; |     maxEntityChangeIdAtLoad: number; | ||||||
|     maxEntityChangeSyncIdAtLoad: number; |     maxEntityChangeSyncIdAtLoad: number; | ||||||
|     assetPath: string; |     assetPath: string; | ||||||
|  |     appPath: string; | ||||||
|     instanceName: string; |     instanceName: string; | ||||||
|     appCssNoteIds: string[]; |     appCssNoteIds: string[]; | ||||||
|     triliumVersion: string; |     triliumVersion: string; | ||||||
|  | |||||||
| @ -67,6 +67,10 @@ const TPL = ` | |||||||
|         .attr-detail input[readonly] { |         .attr-detail input[readonly] { | ||||||
|             background-color: var(--accented-background-color) !important; |             background-color: var(--accented-background-color) !important; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         .attr-edit-table td { | ||||||
|  |             padding: 4px 0; | ||||||
|  |         } | ||||||
|     </style> |     </style> | ||||||
| 
 | 
 | ||||||
|     <div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |     <div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> | ||||||
| @ -97,8 +101,13 @@ const TPL = ` | |||||||
|         </tr> |         </tr> | ||||||
|         <tr class="attr-row-promoted" |         <tr class="attr-row-promoted" | ||||||
|             title="${t("attribute_detail.promoted_title")}"> |             title="${t("attribute_detail.promoted_title")}"> | ||||||
|             <th>${t("attribute_detail.promoted")}</th> |             <th></th> | ||||||
|             <td><input type="checkbox" class="attr-input-promoted form-check" /></td> |             <td> | ||||||
|  |                 <label class="tn-checkbox"> | ||||||
|  |                     <input type="checkbox" class="attr-input-promoted form-check" /> | ||||||
|  |                     ${t("attribute_detail.promoted")} | ||||||
|  |                 </label> | ||||||
|  |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|         <tr class="attr-row-promoted-alias"> |         <tr class="attr-row-promoted-alias"> | ||||||
|             <th title="${t("attribute_detail.promoted_alias_title")}">${t("attribute_detail.promoted_alias")}</th> |             <th title="${t("attribute_detail.promoted_alias_title")}">${t("attribute_detail.promoted_alias")}</th> | ||||||
| @ -149,8 +158,13 @@ const TPL = ` | |||||||
|             </td> |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|         <tr title="${t("attribute_detail.inheritable_title")}"> |         <tr title="${t("attribute_detail.inheritable_title")}"> | ||||||
|             <th>${t("attribute_detail.inheritable")}</th> |             <th></th> | ||||||
|             <td><input type="checkbox" class="attr-input-inheritable form-check" /></td> |             <td> | ||||||
|  |                 <label class="tn-checkbox"> | ||||||
|  |                     <input type="checkbox" class="attr-input-inheritable form-check" /> | ||||||
|  |                     ${t("attribute_detail.inheritable")} | ||||||
|  |                 </label> | ||||||
|  |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|     </table> |     </table> | ||||||
| 
 | 
 | ||||||
| @ -242,7 +256,9 @@ const ATTR_HELP: Record<string, Record<string, string>> = { | |||||||
|         executeDescription: t("attribute_detail.execute_description"), |         executeDescription: t("attribute_detail.execute_description"), | ||||||
|         excludeFromNoteMap: t("attribute_detail.exclude_from_note_map"), |         excludeFromNoteMap: t("attribute_detail.exclude_from_note_map"), | ||||||
|         newNotesOnTop: t("attribute_detail.new_notes_on_top"), |         newNotesOnTop: t("attribute_detail.new_notes_on_top"), | ||||||
|         hideHighlightWidget: t("attribute_detail.hide_highlight_widget") |         hideHighlightWidget: t("attribute_detail.hide_highlight_widget"), | ||||||
|  |         printLandscape: t("attribute_detail.print_landscape"), | ||||||
|  |         printPageSize: t("attribute_detail.print_page_size") | ||||||
|     }, |     }, | ||||||
|     relation: { |     relation: { | ||||||
|         runOnNoteCreation: t("attribute_detail.run_on_note_creation"), |         runOnNoteCreation: t("attribute_detail.run_on_note_creation"), | ||||||
|  | |||||||
| @ -77,8 +77,8 @@ const TPL = ` | |||||||
| 
 | 
 | ||||||
|     <div class="attribute-list-editor" tabindex="200"></div> |     <div class="attribute-list-editor" tabindex="200"></div> | ||||||
| 
 | 
 | ||||||
|     <div class="bx bx-save save-attributes-button" title="${escapeQuotes(t("attribute_editor.save_attributes"))}"></div> |     <div class="bx bx-save save-attributes-button tn-tool-button" title="${escapeQuotes(t("attribute_editor.save_attributes"))}"></div> | ||||||
|     <div class="bx bx-plus add-new-attribute-button" title="${escapeQuotes(t("attribute_editor.add_a_new_attribute"))}"></div> |     <div class="bx bx-plus add-new-attribute-button tn-tool-button" title="${escapeQuotes(t("attribute_editor.add_a_new_attribute"))}"></div> | ||||||
| 
 | 
 | ||||||
|     <div class="attribute-errors" style="display: none;"></div> |     <div class="attribute-errors" style="display: none;"></div> | ||||||
| </div> | </div> | ||||||
|  | |||||||
| @ -1,11 +1,12 @@ | |||||||
| import treeService from "../../services/tree.js"; | import treeService from "../../services/tree.js"; | ||||||
| import utils from "../../services/utils.js"; | import utils from "../../services/utils.js"; | ||||||
| import ws from "../../services/ws.js"; | import ws from "../../services/ws.js"; | ||||||
| import toastService from "../../services/toast.js"; | import toastService, { type ToastOptions } from "../../services/toast.js"; | ||||||
| import froca from "../../services/froca.js"; | import froca from "../../services/froca.js"; | ||||||
| import openService from "../../services/open.js"; | import openService from "../../services/open.js"; | ||||||
| import BasicWidget from "../basic_widget.js"; | import BasicWidget from "../basic_widget.js"; | ||||||
| import { t } from "../../services/i18n.js"; | import { t } from "../../services/i18n.js"; | ||||||
|  | import type { EventData } from "../../components/app_context.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="export-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | <div class="export-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | ||||||
| @ -105,6 +106,13 @@ const TPL = ` | |||||||
|                                 ${t("export.format_markdown")} |                                 ${t("export.format_markdown")} | ||||||
|                             </label> |                             </label> | ||||||
|                         </div> |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <label class="form-check-label tn-radio"> | ||||||
|  |                                 <input class="form-check-input" type="radio" name="export-single-format" value="pdf"> | ||||||
|  |                                 ${t("export.format_pdf")} | ||||||
|  |                             </label> | ||||||
|  |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="modal-footer"> |                 <div class="modal-footer"> | ||||||
| @ -116,6 +124,19 @@ const TPL = ` | |||||||
| </div>`;
 | </div>`;
 | ||||||
| 
 | 
 | ||||||
| export default class ExportDialog extends BasicWidget { | export default class ExportDialog extends BasicWidget { | ||||||
|  | 
 | ||||||
|  |     private taskId: string; | ||||||
|  |     private branchId: string | null; | ||||||
|  |     private modal?: bootstrap.Modal; | ||||||
|  |     private $form!: JQuery<HTMLElement>; | ||||||
|  |     private $noteTitle!: JQuery<HTMLElement>; | ||||||
|  |     private $subtreeFormats!: JQuery<HTMLElement>; | ||||||
|  |     private $singleFormats!: JQuery<HTMLElement>; | ||||||
|  |     private $subtreeType!: JQuery<HTMLElement>; | ||||||
|  |     private $singleType!: JQuery<HTMLElement>; | ||||||
|  |     private $exportButton!: JQuery<HTMLElement>; | ||||||
|  |     private $opmlVersions!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
| @ -125,6 +146,8 @@ export default class ExportDialog extends BasicWidget { | |||||||
| 
 | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|  |         // Remove once bootstrap is fixed.
 | ||||||
|  |         // @ts-ignore
 | ||||||
|         this.modal = bootstrap.Modal.getOrCreateInstance(this.$widget); |         this.modal = bootstrap.Modal.getOrCreateInstance(this.$widget); | ||||||
|         this.$form = this.$widget.find(".export-form"); |         this.$form = this.$widget.find(".export-form"); | ||||||
|         this.$noteTitle = this.$widget.find(".export-note-title"); |         this.$noteTitle = this.$widget.find(".export-note-title"); | ||||||
| @ -136,7 +159,7 @@ export default class ExportDialog extends BasicWidget { | |||||||
|         this.$opmlVersions = this.$widget.find(".opml-versions"); |         this.$opmlVersions = this.$widget.find(".opml-versions"); | ||||||
| 
 | 
 | ||||||
|         this.$form.on("submit", () => { |         this.$form.on("submit", () => { | ||||||
|             this.modal.hide(); |             this.modal?.hide(); | ||||||
| 
 | 
 | ||||||
|             const exportType = this.$widget.find("input[name='export-type']:checked").val(); |             const exportType = this.$widget.find("input[name='export-type']:checked").val(); | ||||||
| 
 | 
 | ||||||
| @ -149,13 +172,15 @@ export default class ExportDialog extends BasicWidget { | |||||||
| 
 | 
 | ||||||
|             const exportVersion = exportFormat === "opml" ? this.$widget.find("input[name='opml-version']:checked").val() : "1.0"; |             const exportVersion = exportFormat === "opml" ? this.$widget.find("input[name='opml-version']:checked").val() : "1.0"; | ||||||
| 
 | 
 | ||||||
|             this.exportBranch(this.branchId, exportType, exportFormat, exportVersion); |             if (this.branchId) { | ||||||
|  |                 this.exportBranch(this.branchId, String(exportType), String(exportFormat), String(exportVersion)); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.$widget.find("input[name=export-type]").on("change", (e) => { |         this.$widget.find("input[name=export-type]").on("change", (e) => { | ||||||
|             if (e.currentTarget.value === "subtree") { |             if ((e.currentTarget as HTMLInputElement).value === "subtree") { | ||||||
|                 if (this.$widget.find("input[name=export-subtree-format]:checked").length === 0) { |                 if (this.$widget.find("input[name=export-subtree-format]:checked").length === 0) { | ||||||
|                     this.$widget.find("input[name=export-subtree-format]:first").prop("checked", true); |                     this.$widget.find("input[name=export-subtree-format]:first").prop("checked", true); | ||||||
|                 } |                 } | ||||||
| @ -173,7 +198,7 @@ export default class ExportDialog extends BasicWidget { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.$widget.find("input[name=export-subtree-format]").on("change", (e) => { |         this.$widget.find("input[name=export-subtree-format]").on("change", (e) => { | ||||||
|             if (e.currentTarget.value === "opml") { |             if ((e.currentTarget as HTMLInputElement).value === "opml") { | ||||||
|                 this.$opmlVersions.slideDown(); |                 this.$opmlVersions.slideDown(); | ||||||
|             } else { |             } else { | ||||||
|                 this.$opmlVersions.slideUp(); |                 this.$opmlVersions.slideUp(); | ||||||
| @ -181,7 +206,7 @@ export default class ExportDialog extends BasicWidget { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async showExportDialogEvent({ notePath, defaultType }) { |     async showExportDialogEvent({ notePath, defaultType }: EventData<"showExportDialog">) { | ||||||
|         this.taskId = ""; |         this.taskId = ""; | ||||||
|         this.$exportButton.removeAttr("disabled"); |         this.$exportButton.removeAttr("disabled"); | ||||||
| 
 | 
 | ||||||
| @ -201,11 +226,15 @@ export default class ExportDialog extends BasicWidget { | |||||||
| 
 | 
 | ||||||
|         const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath); |         const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath); | ||||||
| 
 | 
 | ||||||
|         this.branchId = await froca.getBranchId(parentNoteId, noteId); |         if (parentNoteId) { | ||||||
|         this.$noteTitle.text(await treeService.getNoteTitle(noteId)); |             this.branchId = await froca.getBranchId(parentNoteId, noteId); | ||||||
|  |         } | ||||||
|  |         if (noteId) { | ||||||
|  |             this.$noteTitle.text(await treeService.getNoteTitle(noteId)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     exportBranch(branchId, type, format, version) { |     exportBranch(branchId: string, type: string, format: string, version: string) { | ||||||
|         this.taskId = utils.randomString(10); |         this.taskId = utils.randomString(10); | ||||||
| 
 | 
 | ||||||
|         const url = openService.getUrlForDownload(`api/branches/${branchId}/export/${type}/${format}/${version}/${this.taskId}`); |         const url = openService.getUrlForDownload(`api/branches/${branchId}/export/${type}/${format}/${version}/${this.taskId}`); | ||||||
| @ -215,12 +244,14 @@ export default class ExportDialog extends BasicWidget { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ws.subscribeToMessages(async (message) => { | ws.subscribeToMessages(async (message) => { | ||||||
|     const makeToast = (id, message) => ({ |     function makeToast(id: string, message: string): ToastOptions { | ||||||
|         id: id, |         return { | ||||||
|         title: t("export.export_status"), |             id: id, | ||||||
|         message: message, |             title: t("export.export_status"), | ||||||
|         icon: "arrow-square-up-right" |             message: message, | ||||||
|     }); |             icon: "arrow-square-up-right" | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     if (message.taskType !== "export") { |     if (message.taskType !== "export") { | ||||||
|         return; |         return; | ||||||
| @ -25,16 +25,22 @@ const TPL = ` | |||||||
|                     ${t("include_note.box_size_prompt")} |                     ${t("include_note.box_size_prompt")} | ||||||
| 
 | 
 | ||||||
|                     <div class="form-check"> |                     <div class="form-check"> | ||||||
|                         <input class="form-check-input" type="radio" name="include-note-box-size" value="small"> |                         <label class="form-check-label tn-radio"> | ||||||
|                         <label class="form-check-label">${t("include_note.box_size_small")}</label> |                             <input class="form-check-input" type="radio" name="include-note-box-size" value="small"> | ||||||
|  |                             ${t("include_note.box_size_small")} | ||||||
|  |                         </label> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="form-check"> |                     <div class="form-check"> | ||||||
|                         <input class="form-check-input" type="radio" name="include-note-box-size" value="medium" checked> |                         <label class="form-check-label tn-radio"> | ||||||
|                         <label class="form-check-label">${t("include_note.box_size_medium")}</label> |                             <input class="form-check-input" type="radio" name="include-note-box-size" value="medium" checked> | ||||||
|  |                             ${t("include_note.box_size_medium")} | ||||||
|  |                         </label> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="form-check"> |                     <div class="form-check"> | ||||||
|                         <input class="form-check-input" type="radio" name="include-note-box-size" value="full"> |                         <label class="form-check-label tn-radio"> | ||||||
|                         <label class="form-check-label">${t("include_note.box_size_full")}</label> |                             <input class="form-check-input" type="radio" name="include-note-box-size" value="full"> | ||||||
|  |                             ${t("include_note.box_size_full")} | ||||||
|  |                         </label> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="modal-footer"> |                 <div class="modal-footer"> | ||||||
|  | |||||||
| @ -33,11 +33,15 @@ const TPL = ` | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         .find-widget-found-wrapper { |         .find-widget-found-wrapper { | ||||||
|             font-weight: bold; |             justify-content: center; | ||||||
|  |             min-width: 60px; | ||||||
|  |             padding: 0 4px; | ||||||
|  |             font-size: .85em; | ||||||
|  |             text-align: center; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         .find-widget-search-term-input-group, .replace-widget-replacetext-input { |         .find-widget-search-term-input-group, .replace-widget-replacetext-input { | ||||||
|             max-width: 300px; |             max-width: 350px; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         .find-widget-spacer { |         .find-widget-spacer { | ||||||
| @ -49,6 +53,13 @@ const TPL = ` | |||||||
|         <div class="input-group find-widget-search-term-input-group"> |         <div class="input-group find-widget-search-term-input-group"> | ||||||
|             <input type="text" class="form-control find-widget-search-term-input" placeholder="${t("find.find_placeholder")}"> |             <input type="text" class="form-control find-widget-search-term-input" placeholder="${t("find.find_placeholder")}"> | ||||||
|             <button class="btn btn-outline-secondary bx bxs-chevron-up find-widget-previous-button" type="button"></button> |             <button class="btn btn-outline-secondary bx bxs-chevron-up find-widget-previous-button" type="button"></button> | ||||||
|  |             <div class="find-widget-found-wrapper input-group-text"> | ||||||
|  |                 <span> | ||||||
|  |                     <span class="find-widget-current-found">0</span> | ||||||
|  |                     / | ||||||
|  |                     <span class="find-widget-total-found">0</span> | ||||||
|  |                 <span> | ||||||
|  |             </div> | ||||||
|             <button class="btn btn-outline-secondary bx bxs-chevron-down find-widget-next-button" type="button"></button> |             <button class="btn btn-outline-secondary bx bxs-chevron-down find-widget-next-button" type="button"></button> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
| @ -66,11 +77,7 @@ const TPL = ` | |||||||
|             </label> |             </label> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="find-widget-found-wrapper"> | 
 | ||||||
|             <span class="find-widget-current-found">0</span> |  | ||||||
|             / |  | ||||||
|             <span class="find-widget-total-found">0</span> |  | ||||||
|         </div> |  | ||||||
| 
 | 
 | ||||||
|         <div class="find-widget-spacer"></div> |         <div class="find-widget-spacer"></div> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -261,6 +261,7 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { | |||||||
|         const { ipcRenderer } = utils.dynamicRequire("electron"); |         const { ipcRenderer } = utils.dynamicRequire("electron"); | ||||||
|         ipcRenderer.send("export-as-pdf", { |         ipcRenderer.send("export-as-pdf", { | ||||||
|             title: this.note.title, |             title: this.note.title, | ||||||
|  |             pageSize: this.note.getAttributeValue("label", "printPageSize") ?? "Letter", | ||||||
|             landscape: this.note.hasAttribute("label", "printLandscape") |             landscape: this.note.hasAttribute("label", "printLandscape") | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ const TPL = ` | |||||||
|         } |         } | ||||||
|     </style> |     </style> | ||||||
| 
 | 
 | ||||||
|     <div class="links-wrapper"></div> |     <div class="links-wrapper use-tn-links"></div> | ||||||
| 
 | 
 | ||||||
|     <div class="attachment-wrapper"></div> |     <div class="attachment-wrapper"></div> | ||||||
| </div>`; | </div>`; | ||||||
| @ -57,7 +57,7 @@ export default class AttachmentDetailTypeWidget extends TypeWidget { | |||||||
| 
 | 
 | ||||||
|         this.$linksWrapper.empty().append( |         this.$linksWrapper.empty().append( | ||||||
|             t("attachment_detail.owning_note"), |             t("attachment_detail.owning_note"), | ||||||
|             await linkService.createLink(this.noteId), |             (await linkService.createLink(this.noteId)), | ||||||
|             t("attachment_detail.you_can_also_open"), |             t("attachment_detail.you_can_also_open"), | ||||||
|             await linkService.createLink(this.noteId, { |             await linkService.createLink(this.noteId, { | ||||||
|                 title: t("attachment_detail.list_of_all_attachments"), |                 title: t("attachment_detail.list_of_all_attachments"), | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import type FNote from "../../entities/fnote.js"; | ||||||
| import TypeWidget from "./type_widget.js"; | import TypeWidget from "./type_widget.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = `<div class="note-detail-doc note-detail-printable">
 | const TPL = `<div class="note-detail-doc note-detail-printable">
 | ||||||
| @ -18,6 +19,9 @@ const TPL = `<div class="note-detail-doc note-detail-printable"> | |||||||
| </div>`;
 | </div>`;
 | ||||||
| 
 | 
 | ||||||
| export default class DocTypeWidget extends TypeWidget { | export default class DocTypeWidget extends TypeWidget { | ||||||
|  | 
 | ||||||
|  |     private $content!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     static getType() { |     static getType() { | ||||||
|         return "doc"; |         return "doc"; | ||||||
|     } |     } | ||||||
| @ -29,7 +33,7 @@ export default class DocTypeWidget extends TypeWidget { | |||||||
|         super.doRender(); |         super.doRender(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async doRefresh(note) { |     async doRefresh(note: FNote) { | ||||||
|         const docName = note.getLabelValue("docName"); |         const docName = note.getLabelValue("docName"); | ||||||
| 
 | 
 | ||||||
|         if (docName) { |         if (docName) { | ||||||
| @ -1,4 +1,4 @@ | |||||||
| import { Marker, type LatLng, type LeafletMouseEvent } from "leaflet"; | import { GPX, Marker, type LatLng, type LeafletMouseEvent } from "leaflet"; | ||||||
| import type FNote from "../../entities/fnote.js"; | import type FNote from "../../entities/fnote.js"; | ||||||
| import GeoMapWidget, { type InitCallback, type Leaflet } from "../geo_map.js"; | import GeoMapWidget, { type InitCallback, type Leaflet } from "../geo_map.js"; | ||||||
| import TypeWidget from "./type_widget.js" | import TypeWidget from "./type_widget.js" | ||||||
| @ -91,8 +91,6 @@ interface CreateChildResponse { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type MarkerData = Record<string, Marker>; |  | ||||||
| 
 |  | ||||||
| enum State { | enum State { | ||||||
|     Normal, |     Normal, | ||||||
|     NewNote |     NewNote | ||||||
| @ -103,7 +101,9 @@ export default class GeoMapTypeWidget extends TypeWidget { | |||||||
|     private geoMapWidget: GeoMapWidget; |     private geoMapWidget: GeoMapWidget; | ||||||
|     private _state: State; |     private _state: State; | ||||||
|     private L!: Leaflet; |     private L!: Leaflet; | ||||||
|     private currentMarkerData: MarkerData; |     private currentMarkerData: Record<string, Marker>; | ||||||
|  |     private currentTrackData: Record<string, GPX>; | ||||||
|  |     private gpxLoaded?: boolean; | ||||||
| 
 | 
 | ||||||
|     static getType() { |     static getType() { | ||||||
|         return "geoMap"; |         return "geoMap"; | ||||||
| @ -114,6 +114,7 @@ export default class GeoMapTypeWidget extends TypeWidget { | |||||||
| 
 | 
 | ||||||
|         this.geoMapWidget = new GeoMapWidget("type", (L: Leaflet) => this.#onMapInitialized(L)); |         this.geoMapWidget = new GeoMapWidget("type", (L: Leaflet) => this.#onMapInitialized(L)); | ||||||
|         this.currentMarkerData = {}; |         this.currentMarkerData = {}; | ||||||
|  |         this.currentTrackData = {}; | ||||||
|         this._state = State.Normal; |         this._state = State.Normal; | ||||||
| 
 | 
 | ||||||
|         this.child(this.geoMapWidget); |         this.child(this.geoMapWidget); | ||||||
| @ -159,9 +160,7 @@ export default class GeoMapTypeWidget extends TypeWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async #reloadMarkers() { |     async #reloadMarkers() { | ||||||
|         const map = this.geoMapWidget.map; |         if (!this.note) { | ||||||
| 
 |  | ||||||
|         if (!this.note || !map) { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -170,51 +169,91 @@ export default class GeoMapTypeWidget extends TypeWidget { | |||||||
|             marker.remove(); |             marker.remove(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // Delete all existing tracks
 | ||||||
|  |         for (const track of Object.values(this.currentTrackData)) { | ||||||
|  |             track.remove(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // Add the new markers.
 |         // Add the new markers.
 | ||||||
|         this.currentMarkerData = {}; |         this.currentMarkerData = {}; | ||||||
|         const childNotes = await this.note.getChildNotes(); |         const childNotes = await this.note.getChildNotes(); | ||||||
|         const L = this.L; |  | ||||||
|         for (const childNote of childNotes) { |         for (const childNote of childNotes) { | ||||||
|             const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE); |             if (childNote.mime === "application/gpx+xml") { | ||||||
|             if (!latLng) { |                 this.#processNoteWithGpxTrack(childNote); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const [ lat, lng ] = latLng.split(",", 2).map((el) => parseFloat(el)); |             const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE); | ||||||
|             const icon = L.divIcon({ |             if (latLng) { | ||||||
|                 html: `\ |                 this.#processNoteWithMarker(childNote, latLng); | ||||||
|                     <img class="icon" src="${asset_path}/node_modules/leaflet/dist/images/marker-icon.png" /> |             } | ||||||
|                     <img class="icon-shadow" src="${asset_path}/node_modules/leaflet/dist/images/marker-shadow.png" /> |         } | ||||||
|                     <span class="bx ${childNote.getIcon()}"></span> |     } | ||||||
|                     <span class="title-label">${childNote.title}</span>`,
 |  | ||||||
|                 iconSize: [ 25, 41 ], |  | ||||||
|                 iconAnchor: [ 12, 41 ] |  | ||||||
|             }) |  | ||||||
| 
 | 
 | ||||||
|             const marker = L.marker(L.latLng(lat, lng), { |     async #processNoteWithGpxTrack(note: FNote) { | ||||||
|                 icon, |         if (!this.L || !this.geoMapWidget.map) { | ||||||
|                 draggable: true, |             return; | ||||||
|                 autoPan: true, |         } | ||||||
|                 autoPanSpeed: 5, |  | ||||||
|             }) |  | ||||||
|                 .addTo(map) |  | ||||||
|                 .on("moveend", e => { |  | ||||||
|                     this.moveMarker(childNote.noteId, (e.target as Marker).getLatLng()); |  | ||||||
|                 }); |  | ||||||
| 
 | 
 | ||||||
|             marker.on("contextmenu", (e) => { |         if (!this.gpxLoaded) { | ||||||
|                 openContextMenu(childNote.noteId, e.originalEvent); |             await import("leaflet-gpx"); | ||||||
|  |             this.gpxLoaded = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // TODO: This is not very efficient as it's probably a string response that is parsed and then converted back to string and parsed again.
 | ||||||
|  |         const xmlResponse = await server.get<XMLDocument>(`notes/${note.noteId}/open`); | ||||||
|  |         const stringResponse = new XMLSerializer().serializeToString(xmlResponse); | ||||||
|  | 
 | ||||||
|  |         const track = new this.L.GPX(stringResponse, {}); | ||||||
|  |         track.addTo(this.geoMapWidget.map); | ||||||
|  |         this.currentTrackData[note.noteId] = track; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #processNoteWithMarker(note: FNote, latLng: string) { | ||||||
|  |         const map = this.geoMapWidget.map; | ||||||
|  |         if (!map) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const [ lat, lng ] = latLng.split(",", 2).map((el) => parseFloat(el)); | ||||||
|  |         const L = this.L; | ||||||
|  |         const icon = this.#buildIcon(note.getIcon(), note.title); | ||||||
|  | 
 | ||||||
|  |         const marker = L.marker(L.latLng(lat, lng), { | ||||||
|  |             icon, | ||||||
|  |             draggable: true, | ||||||
|  |             autoPan: true, | ||||||
|  |             autoPanSpeed: 5, | ||||||
|  |         }) | ||||||
|  |             .addTo(map) | ||||||
|  |             .on("moveend", e => { | ||||||
|  |                 this.moveMarker(note.noteId, (e.target as Marker).getLatLng()); | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             const el = marker.getElement(); |         marker.on("contextmenu", (e) => { | ||||||
|             if (el) { |             openContextMenu(note.noteId, e.originalEvent); | ||||||
|                 const $el = $(el); |         }); | ||||||
|                 $el.attr("data-href", `#${childNote.noteId}`); |  | ||||||
|                 note_tooltip.setupElementTooltip($($el)); |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             this.currentMarkerData[childNote.noteId] = marker; |         const el = marker.getElement(); | ||||||
|  |         if (el) { | ||||||
|  |             const $el = $(el); | ||||||
|  |             $el.attr("data-href", `#${note.noteId}`); | ||||||
|  |             note_tooltip.setupElementTooltip($($el)); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         this.currentMarkerData[note.noteId] = marker; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #buildIcon(bxIconClass: string, title: string) { | ||||||
|  |         return this.L.divIcon({ | ||||||
|  |             html: `\ | ||||||
|  |                 <img class="icon" src="${asset_path}/node_modules/leaflet/dist/images/marker-icon.png" /> | ||||||
|  |                 <img class="icon-shadow" src="${asset_path}/node_modules/leaflet/dist/images/marker-shadow.png" /> | ||||||
|  |                 <span class="bx ${bxIconClass}"></span> | ||||||
|  |                 <span class="title-label">${title}</span>`,
 | ||||||
|  |             iconSize: [ 25, 41 ], | ||||||
|  |             iconAnchor: [ 12, 41 ] | ||||||
|  |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #changeState(newState: State) { |     #changeState(newState: State) { | ||||||
| @ -299,6 +338,14 @@ export default class GeoMapTypeWidget extends TypeWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { |     entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { | ||||||
|  |         // If any of the children branches are altered.
 | ||||||
|  |         if (loadResults.getBranchRows().find((branch) => branch.parentNoteId === this.noteId)) { | ||||||
|  |             this.#reloadMarkers(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // If any of note has its location attribute changed.
 | ||||||
|  |         // TODO: Should probably filter by parent here as well.
 | ||||||
|         const attributeRows = loadResults.getAttributeRows(); |         const attributeRows = loadResults.getAttributeRows(); | ||||||
|         if (attributeRows.find((at) => at.name === LOCATION_ATTRIBUTE)) { |         if (attributeRows.find((at) => at.name === LOCATION_ATTRIBUTE)) { | ||||||
|             this.#reloadMarkers(); |             this.#reloadMarkers(); | ||||||
|  | |||||||
| @ -9,6 +9,12 @@ const TPL = ` | |||||||
|         width: 300px; |         width: 300px; | ||||||
|         margin: 30px auto auto; |         margin: 30px auto auto; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .protected-session-password-component input, | ||||||
|  |     .protected-session-password-component button { | ||||||
|  |         margin-top: 12px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     </style> |     </style> | ||||||
| 
 | 
 | ||||||
|     <form class="protected-session-password-form"> |     <form class="protected-session-password-form"> | ||||||
|  | |||||||
| @ -4,6 +4,21 @@ | |||||||
|     --launcher-pane-background-color: var(--main-background-color); |     --launcher-pane-background-color: var(--main-background-color); | ||||||
|     --main-text-color: black; |     --main-text-color: black; | ||||||
|     --input-text-color: var(--main-text-color); |     --input-text-color: var(--main-text-color); | ||||||
|  | 
 | ||||||
|  |     --print-font-size: 11pt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @page { | ||||||
|  |     margin: 2cm; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ck-content { | ||||||
|  |     font-size: var(--print-font-size); | ||||||
|  |     text-align: justify; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-readonly-text { | ||||||
|  |     padding: 0 !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .no-print, | .no-print, | ||||||
| @ -141,13 +156,6 @@ span[style] { | |||||||
|     outline: unset !important; |     outline: unset !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Fix visibility of checkbox checkmarks |  | ||||||
|     see https://github.com/TriliumNext/Notes/issues/901 */ |  | ||||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable="false"] > input[checked]::after { |  | ||||||
|     /* fallback to default ck-editor green */ |  | ||||||
|     border-color: hsl(126, 64%, 41%); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .include-note .include-note-content { | .include-note .include-note-content { | ||||||
|     max-height: unset !important; |     max-height: unset !important; | ||||||
|     overflow: unset !important; |     overflow: unset !important; | ||||||
| @ -160,3 +168,138 @@ span[style] { | |||||||
|     border: unset !important; |     border: unset !important; | ||||||
|     border-radius: unset !important; |     border-radius: unset !important; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Links | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .note-detail-printable a { | ||||||
|  |     text-decoration: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable a:not([href^="#root/"]) { | ||||||
|  |     text-decoration: underline; | ||||||
|  |     color: #374a75; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable a::after { | ||||||
|  |     /* Hide the external link trailing arrow */ | ||||||
|  |     display: none !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * TODO list check boxes | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .note-detail-printable .todo-list__label * { | ||||||
|  |     -webkit-print-color-adjust: exact; | ||||||
|  |     print-color-adjust: exact;   | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @supports selector(.todo-list__label__description:has(*)) and (height: 1lh) { | ||||||
|  |     .note-detail-printable .todo-list__label__description { | ||||||
|  | 
 | ||||||
|  |         /* The percentage of the line height that the check box occupies */ | ||||||
|  |         --box-ratio: .75; | ||||||
|  |         /* The size of the gap between the check box and the caption */ | ||||||
|  |         --box-text-gap: 0.25em; | ||||||
|  | 
 | ||||||
|  |         --box-size: calc(1lh * var(--box-ratio)); | ||||||
|  |         --box-vert-offset: calc((1lh - var(--box-size)) / 2); | ||||||
|  | 
 | ||||||
|  |         display: inline-block; | ||||||
|  |         padding-left: calc(var(--box-size) + var(--box-text-gap)); | ||||||
|  |         /* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */ | ||||||
|  |         background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e"); | ||||||
|  |         background-position: 0 var(--box-vert-offset); | ||||||
|  |         background-size: var(--box-size); | ||||||
|  |         background-repeat: no-repeat; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .note-detail-printable .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description { | ||||||
|  |         /* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */ | ||||||
|  |         background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .note-detail-printable .todo-list__label input[type="checkbox"] { | ||||||
|  |         display: none !important; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Blockquotes | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .note-detail-printable blockquote { | ||||||
|  |     box-shadow: unset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*  | ||||||
|  |  * Figures | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .note-detail-printable figcaption { | ||||||
|  |     --accented-background-color: transparent; | ||||||
|  | 
 | ||||||
|  |     font-style: italic; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Footnotes | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .note-detail-printable .footnote-reference a, | ||||||
|  | .footnote-back-link a { | ||||||
|  |     text-decoration: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Make the "^" link cover the whole area of the footnote item */ | ||||||
|  | 
 | ||||||
|  | .footnote-section { | ||||||
|  |     clear: both; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable li.footnote-item { | ||||||
|  |     position: relative; | ||||||
|  |     width: fit-content; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable .footnote-back-link, | ||||||
|  | .note-detail-printable .footnote-back-link *, | ||||||
|  | .note-detail-printable .footnote-back-link a { | ||||||
|  |     display: block; | ||||||
|  |     position: absolute; | ||||||
|  | 
 | ||||||
|  |     top: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable .footnote-back-link a { | ||||||
|  |     color: transparent; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .note-detail-printable .footnote-content { | ||||||
|  |     display: inline-block; | ||||||
|  |     width: unset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Widows and orphans | ||||||
|  |  */ | ||||||
|  | p, | ||||||
|  | blockquote { | ||||||
|  |     widows: 4; | ||||||
|  |     orphans: 4; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pre > code { | ||||||
|  |     widows: 6; | ||||||
|  |     orphans: 6; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | h1, h2, h3, h4, h5, h6 { | ||||||
|  |     page-break-after: avoid; | ||||||
|  |     break-after: avoid; | ||||||
|  | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| @import url(./forms.css); | @import url(./forms.css); | ||||||
| @import url(./shell.css); | @import url(./shell.css); | ||||||
| @import url(./settings.css); | @import url(./settings.css); | ||||||
|  | @import url(./notes/empty.css); | ||||||
| @import url(./notes/text.css); | @import url(./notes/text.css); | ||||||
| 
 | 
 | ||||||
| @font-face { | @font-face { | ||||||
| @ -64,3 +65,29 @@ | |||||||
|     /* Theme capabilities */ |     /* Theme capabilities */ | ||||||
|     --tab-note-icons: true; |     --tab-note-icons: true; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Note search suggestions | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* List body */ | ||||||
|  | .jump-to-note-dialog .jump-to-note-results .aa-suggestions, | ||||||
|  | .note-detail-empty .aa-suggestions { | ||||||
|  |     padding: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* List item */ | ||||||
|  | .jump-to-note-dialog .aa-suggestions div, | ||||||
|  | .note-detail-empty .aa-suggestions div { | ||||||
|  |     border-radius: 6px; | ||||||
|  |     padding: 6px 12px; | ||||||
|  |     color: var(--menu-text-color); | ||||||
|  |     cursor: default; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Selected list item */ | ||||||
|  | .jump-to-note-dialog .aa-suggestions div.aa-cursor, | ||||||
|  | .note-detail-empty .aa-suggestions div.aa-cursor { | ||||||
|  |     background: var(--hover-item-background-color); | ||||||
|  |     color: var(--hover-item-text-color); | ||||||
|  | } | ||||||
| @ -78,10 +78,11 @@ button.btn.btn-success kbd { | |||||||
|  * Icon buttons |  * Icon buttons | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| :root .icon-action:not(.global-menu-button) { | :root .icon-action:not(.global-menu-button), | ||||||
|  | :root .tn-tool-button { | ||||||
|     width: var(--icon-button-size); |     width: var(--icon-button-size); | ||||||
|     height: var(--icon-button-size); |     height: var(--icon-button-size); | ||||||
|     border: unset; |     border: unset !important; | ||||||
|     border-radius: 8px; |     border-radius: 8px; | ||||||
|     padding: 0; |     padding: 0; | ||||||
|     text-align: center; |     text-align: center; | ||||||
| @ -89,7 +90,8 @@ button.btn.btn-success kbd { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* The "x" icon button */ | /* The "x" icon button */ | ||||||
| :root .icon-action.bx-x { | :root .icon-action.bx-x, | ||||||
|  | :root .tn-tool-button.bx-x { | ||||||
|     --icon-button-hover-background: var(--tab-close-button-hover-background); |     --icon-button-hover-background: var(--tab-close-button-hover-background); | ||||||
|     --icon-button-hover-color: var(--tab-close-button-hover-color); |     --icon-button-hover-color: var(--tab-close-button-hover-color); | ||||||
|     --icon-button-size: 24px; |     --icon-button-size: 24px; | ||||||
| @ -99,23 +101,28 @@ button.btn.btn-success kbd { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* The icon */ | /* The icon */ | ||||||
| :root .icon-action:not(.global-menu-button)::before { | :root .icon-action:not(.global-menu-button)::before, | ||||||
|  | :root .tn-tool-button::before { | ||||||
|     display: block; |     display: block; | ||||||
|     line-height: var(--icon-button-size); |     line-height: var(--icon-button-size); | ||||||
|     font-size: calc(var(--icon-button-size) * var(--icon-button-icon-ratio)); |     font-size: calc(var(--icon-button-size) * var(--icon-button-icon-ratio)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :root .icon-action:not(.global-menu-button):hover, | :root .icon-action:not(.global-menu-button):hover, | ||||||
| :root .icon-action:not(.global-menu-button).show { | :root .icon-action:not(.global-menu-button).show, | ||||||
|  | :root .tn-tool-button:hover, | ||||||
|  | :root .tn-tool-button.show { | ||||||
|     background: var(--icon-button-hover-background); |     background: var(--icon-button-hover-background); | ||||||
|     color: var(--icon-button-hover-color); |     color: var(--icon-button-hover-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :root .icon-action:not(.global-menu-button):active::before { | :root .icon-action:not(.global-menu-button):active::before, | ||||||
|  | :root .tn-tool-button:active::before { | ||||||
|     transform: scale(.85); |     transform: scale(.85); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :root .icon-action:not(.global-menu-button):focus-visible { | :root .icon-action:not(.global-menu-button):focus-visible, | ||||||
|  | :root .tn-tool-button:focus-visible { | ||||||
|     outline: 2px solid var(--input-focus-outline-color); |     outline: 2px solid var(--input-focus-outline-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -216,6 +223,7 @@ input::selection, | |||||||
| .input-group button, | .input-group button, | ||||||
| .input-group a { | .input-group a { | ||||||
|     display: flex; |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|     --bs-border-width: 0; |     --bs-border-width: 0; | ||||||
|     --accented-background-color: transparent; |     --accented-background-color: transparent; | ||||||
|     background: transparent; |     background: transparent; | ||||||
| @ -228,15 +236,21 @@ input::selection, | |||||||
| .input-group button:hover, | .input-group button:hover, | ||||||
| .input-group a:hover { | .input-group a:hover { | ||||||
|     --muted-text-color: var(--input-action-button-hover); |     --muted-text-color: var(--input-action-button-hover); | ||||||
|  |     color: var(--input-action-button-hover); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .input-group button:focus-visible, | .input-group button:focus-visible, | ||||||
| .input-group a:focus-visible { | .input-group a:focus-visible { | ||||||
|  |     box-shadow: unset; | ||||||
|     outline: transparent; |     outline: transparent; | ||||||
|     border: transparent; |     border: transparent; | ||||||
|     text-shadow: 0 0 3px var(--input-action-button-hover); |     text-shadow: 0 0 3px var(--input-action-button-hover); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .input-group button:active { | ||||||
|  |     background: transparent !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .input-group a.disabled { | .input-group a.disabled { | ||||||
|     opacity: .5; |     opacity: .5; | ||||||
|     /* Workaround to set the "background" property. */ |     /* Workaround to set the "background" property. */ | ||||||
| @ -247,7 +261,7 @@ input::selection, | |||||||
|     background: transparent !important; |     background: transparent !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .input-group .input-group-text { | .input-group .input-group-text:not(button):not(a) { | ||||||
|     /* Background color hijack */ |     /* Background color hijack */ | ||||||
|     --accented-background-color: transparent; |     --accented-background-color: transparent; | ||||||
|      |      | ||||||
| @ -273,6 +287,7 @@ input::selection, | |||||||
| 
 | 
 | ||||||
| select, | select, | ||||||
| select.form-select, | select.form-select, | ||||||
|  | select.form-control, | ||||||
| .select-button.dropdown-toggle.btn { | .select-button.dropdown-toggle.btn { | ||||||
|     outline: 3px solid transparent; |     outline: 3px solid transparent; | ||||||
|     outline-offset: 6px; |     outline-offset: 6px; | ||||||
| @ -285,6 +300,7 @@ select.form-select, | |||||||
| 
 | 
 | ||||||
| select:hover, | select:hover, | ||||||
| select.form-select:hover, | select.form-select:hover, | ||||||
|  | select.form-control:hover, | ||||||
| .select-button.dropdown-toggle.btn:hover { | .select-button.dropdown-toggle.btn:hover { | ||||||
|     background-color: var(--input-hover-background); |     background-color: var(--input-hover-background); | ||||||
|     color: var(--input-hover-color); |     color: var(--input-hover-color); | ||||||
| @ -297,6 +313,7 @@ button.select-button.dropdown-toggle.btn:active { | |||||||
| 
 | 
 | ||||||
| select:focus, | select:focus, | ||||||
| select.form-select:focus, | select.form-select:focus, | ||||||
|  | select.form-control:focus, | ||||||
| .select-button.dropdown-toggle.btn:focus { | .select-button.dropdown-toggle.btn:focus { | ||||||
|     box-shadow: unset; |     box-shadow: unset; | ||||||
|     outline: 3px solid var(--input-focus-outline-color); |     outline: 3px solid var(--input-focus-outline-color); | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								src/public/stylesheets/theme-next/notes/empty.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/public/stylesheets/theme-next/notes/empty.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | /* The container */ | ||||||
|  | div.note-detail-empty { | ||||||
|  |     max-width: 70%; | ||||||
|  |     margin: 50px auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* The search results list */ | ||||||
|  | .note-detail-empty span.aa-dropdown-menu { | ||||||
|  |     margin-top: 1em; | ||||||
|  |     border: unset; | ||||||
|  | } | ||||||
| @ -126,3 +126,34 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child { | |||||||
|     border: 0 !important; |     border: 0 !important; | ||||||
|     border-top: 1px solid var(--main-border-color) !important; |     border-top: 1px solid var(--main-border-color) !important; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Search in text panel | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | .find-replace-widget > div { | ||||||
|  |     padding: 8px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .find-replace-widget > div + div { | ||||||
|  |     padding-top: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.find-replace-widget div.find-widget-found-wrapper { | ||||||
|  |     min-width: 50px; | ||||||
|  |     font-style: normal; | ||||||
|  |     font-weight: normal; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |  /* The up / down buttons of the "Find in text" input */ | ||||||
|  | .find-replace-widget .input-group button { | ||||||
|  |     font-size: 1.3em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .find-replace-widget .form-check { | ||||||
|  |     padding-left: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .find-replace-widget .form-check .form-check-input { | ||||||
|  |     margin-left: 0; | ||||||
|  | } | ||||||
| @ -227,6 +227,12 @@ body.layout-horizontal > .horizontal { | |||||||
|     --hover-item-background-color: transparent; |     --hover-item-background-color: transparent; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #launcher-pane.horizontal .global-menu-button .global-menu-button-update-available { | ||||||
|  |     right: -23px; | ||||||
|  |     bottom: -22px; | ||||||
|  |     transform: scale(0.85); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .tooltip .tooltip-arrow { | .tooltip .tooltip-arrow { | ||||||
|     display: none; |     display: none; | ||||||
| } | } | ||||||
| @ -1237,25 +1243,6 @@ body .calendar-dropdown-widget .calendar-body a:hover { | |||||||
|     background: transparent !important; |     background: transparent !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* List body */ |  | ||||||
| .jump-to-note-dialog .jump-to-note-results .aa-suggestions { |  | ||||||
|     padding: 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* List item */ |  | ||||||
| .jump-to-note-dialog .aa-suggestions div { |  | ||||||
|     border-radius: 6px; |  | ||||||
|     padding: 6px 12px; |  | ||||||
|     color: var(--menu-text-color); |  | ||||||
|     cursor: default; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Selected list item */ |  | ||||||
| .jump-to-note-dialog .aa-suggestions div.aa-cursor { |  | ||||||
|     background: var(--hover-item-background-color); |  | ||||||
|     color: var(--hover-item-text-color); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* | /* | ||||||
|  * Recent changes list |  * Recent changes list | ||||||
|  */ |  */ | ||||||
| @ -1656,3 +1643,8 @@ body .calendar-dropdown-widget .calendar-body a:hover { | |||||||
|     border-radius: 8px; |     border-radius: 8px; | ||||||
|     padding-left: 12px; |     padding-left: 12px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* Promoted attributes */ | ||||||
|  | .promoted-attribute-cell div.input-group { | ||||||
|  |     margin: 1px 0;     | ||||||
|  | } | ||||||
| @ -109,7 +109,8 @@ | |||||||
|     "choose_export_type": "Choose export type first please", |     "choose_export_type": "Choose export type first please", | ||||||
|     "export_status": "Export status", |     "export_status": "Export status", | ||||||
|     "export_in_progress": "Export in progress: {{progressCount}}", |     "export_in_progress": "Export in progress: {{progressCount}}", | ||||||
|     "export_finished_successfully": "Export finished successfully." |     "export_finished_successfully": "Export finished successfully.", | ||||||
|  |     "format_pdf": "PDF - for printing or sharing purposes." | ||||||
|   }, |   }, | ||||||
|   "help": { |   "help": { | ||||||
|     "fullDocumentation": "Help (full documentation is available <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)", |     "fullDocumentation": "Help (full documentation is available <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)", | ||||||
| @ -437,7 +438,9 @@ | |||||||
|     "share_favicon": "Favicon note to be set in the shared page. Typically you want to set it to share root and make it inheritable. Favicon note must be in the shared sub-tree as well. Consider using 'share_hidden_from_tree'.", |     "share_favicon": "Favicon note to be set in the shared page. Typically you want to set it to share root and make it inheritable. Favicon note must be in the shared sub-tree as well. Consider using 'share_hidden_from_tree'.", | ||||||
|     "is_owned_by_note": "is owned by note", |     "is_owned_by_note": "is owned by note", | ||||||
|     "other_notes_with_name": "Other notes with {{attributeType}} name \"{{attributeName}}\"", |     "other_notes_with_name": "Other notes with {{attributeType}} name \"{{attributeName}}\"", | ||||||
|     "and_more": "... and {{count}} more." |     "and_more": "... and {{count}} more.", | ||||||
|  |     "print_landscape": "When exporting to PDF, changes the orientation of the page to landscape instead of portrait.", | ||||||
|  |     "print_page_size": "When exporting to PDF, changes the size of the page. Supported values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>." | ||||||
|   }, |   }, | ||||||
|   "attribute_editor": { |   "attribute_editor": { | ||||||
|     "help_text_body1": "To add label, just type e.g. <code>#rock</code> or if you want to add also value then e.g. <code>#year = 2020</code>", |     "help_text_body1": "To add label, just type e.g. <code>#rock</code> or if you want to add also value then e.g. <code>#year = 2020</code>", | ||||||
|  | |||||||
| @ -31,6 +31,7 @@ async function register(app: express.Application) { | |||||||
|             target: productionConfig.target |             target: productionConfig.target | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         app.use(`/${assetPath}/app/doc_notes`, persistentCacheStatic(path.join(srcRoot, "public/app/doc_notes"))); | ||||||
|         app.use(`/${assetPath}/app`, webpackMiddleware(frontendCompiler)); |         app.use(`/${assetPath}/app`, webpackMiddleware(frontendCompiler)); | ||||||
|     } else { |     } else { | ||||||
|         app.use(`/${assetPath}/app`, persistentCacheStatic(path.join(srcRoot, "public/app"))); |         app.use(`/${assetPath}/app`, persistentCacheStatic(path.join(srcRoot, "public/app"))); | ||||||
|  | |||||||
| @ -72,6 +72,9 @@ export default [ | |||||||
|     { type: "label", name: "webViewSrc", isDangerous: true }, |     { type: "label", name: "webViewSrc", isDangerous: true }, | ||||||
|     { type: "label", name: "hideHighlightWidget" }, |     { type: "label", name: "hideHighlightWidget" }, | ||||||
| 
 | 
 | ||||||
|  |     { type: "label", name: "printLandscape" }, | ||||||
|  |     { type: "label", name: "printPageSize" }, | ||||||
|  | 
 | ||||||
|     // relation names
 |     // relation names
 | ||||||
|     { type: "relation", name: "internalLink" }, |     { type: "relation", name: "internalLink" }, | ||||||
|     { type: "relation", name: "imageLink" }, |     { type: "relation", name: "imageLink" }, | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								src/services/export/pdf.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/services/export/pdf.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | import { describe, it, expect } from "vitest"; | ||||||
|  | import { processMindmapContent } from "./note_content_fulltext.js"; | ||||||
|  | 
 | ||||||
|  | describe("processMindmapContent", () => { | ||||||
|  |     it("supports empty JSON", () => { | ||||||
|  |         expect(processMindmapContent("{}")).toEqual(""); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("supports blank text / invalid JSON", () => { | ||||||
|  |         expect(processMindmapContent("")).toEqual(""); | ||||||
|  |         expect(processMindmapContent(`{ "node": " }`)).toEqual(""); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
| @ -131,52 +131,7 @@ class NoteContentFulltextExp extends Expression { | |||||||
| 
 | 
 | ||||||
|             content = content.replace(/ /g, " "); |             content = content.replace(/ /g, " "); | ||||||
|         } else if (type === "mindMap" && mime === "application/json") { |         } else if (type === "mindMap" && mime === "application/json") { | ||||||
|             let mindMapcontent = JSON.parse(content); |             content = processMindmapContent(content); | ||||||
| 
 |  | ||||||
|             // Define interfaces for the JSON structure
 |  | ||||||
|             interface MindmapNode { |  | ||||||
|                 id: string; |  | ||||||
|                 topic: string; |  | ||||||
|                 children: MindmapNode[]; // Recursive structure
 |  | ||||||
|                 direction?: number; |  | ||||||
|                 expanded?: boolean; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             interface MindmapData { |  | ||||||
|                 nodedata: MindmapNode; |  | ||||||
|                 arrows: any[]; // If you know the structure, replace `any` with the correct type
 |  | ||||||
|                 summaries: any[]; |  | ||||||
|                 direction: number; |  | ||||||
|                 theme: { |  | ||||||
|                     name: string; |  | ||||||
|                     type: string; |  | ||||||
|                     palette: string[]; |  | ||||||
|                     cssvar: Record<string, string>; // Object with string keys and string values
 |  | ||||||
|                 }; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Recursive function to collect all topics
 |  | ||||||
|             function collectTopics(node: MindmapNode): string[] { |  | ||||||
|                 // Collect the current node's topic
 |  | ||||||
|                 let topics = [node.topic]; |  | ||||||
| 
 |  | ||||||
|                 // If the node has children, collect topics recursively
 |  | ||||||
|                 if (node.children && node.children.length > 0) { |  | ||||||
|                     for (const child of node.children) { |  | ||||||
|                         topics = topics.concat(collectTopics(child)); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 return topics; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Start extracting from the root node
 |  | ||||||
|             const topicsArray = collectTopics(mindMapcontent.nodedata); |  | ||||||
| 
 |  | ||||||
|             // Combine topics into a single string
 |  | ||||||
|             const topicsString = topicsArray.join(", "); |  | ||||||
| 
 |  | ||||||
|             content = normalize(topicsString.toString()); |  | ||||||
|         } else if (type === "canvas" && mime === "application/json") { |         } else if (type === "canvas" && mime === "application/json") { | ||||||
|             interface Element { |             interface Element { | ||||||
|                 type: string; |                 type: string; | ||||||
| @ -215,4 +170,63 @@ class NoteContentFulltextExp extends Expression { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export function processMindmapContent(content: string) { | ||||||
|  |     let mindMapcontent; | ||||||
|  | 
 | ||||||
|  |     try { | ||||||
|  |         mindMapcontent = JSON.parse(content); | ||||||
|  |     } catch (e) { | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Define interfaces for the JSON structure
 | ||||||
|  |     interface MindmapNode { | ||||||
|  |         id: string; | ||||||
|  |         topic: string; | ||||||
|  |         children: MindmapNode[]; // Recursive structure
 | ||||||
|  |         direction?: number; | ||||||
|  |         expanded?: boolean; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     interface MindmapData { | ||||||
|  |         nodedata: MindmapNode; | ||||||
|  |         arrows: any[]; // If you know the structure, replace `any` with the correct type
 | ||||||
|  |         summaries: any[]; | ||||||
|  |         direction: number; | ||||||
|  |         theme: { | ||||||
|  |             name: string; | ||||||
|  |             type: string; | ||||||
|  |             palette: string[]; | ||||||
|  |             cssvar: Record<string, string>; // Object with string keys and string values
 | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Recursive function to collect all topics
 | ||||||
|  |     function collectTopics(node?: MindmapNode): string[] { | ||||||
|  |         if (!node) { | ||||||
|  |             return []; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Collect the current node's topic
 | ||||||
|  |         let topics = [node.topic]; | ||||||
|  | 
 | ||||||
|  |         // If the node has children, collect topics recursively
 | ||||||
|  |         if (node.children && node.children.length > 0) { | ||||||
|  |             for (const child of node.children) { | ||||||
|  |                 topics = topics.concat(collectTopics(child)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return topics; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Start extracting from the root node
 | ||||||
|  |     const topicsArray = collectTopics(mindMapcontent.nodedata); | ||||||
|  | 
 | ||||||
|  |     // Combine topics into a single string
 | ||||||
|  |     const topicsString = topicsArray.join(", "); | ||||||
|  | 
 | ||||||
|  |     return normalize(topicsString.toString()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default NoteContentFulltextExp; | export default NoteContentFulltextExp; | ||||||
|  | |||||||
| @ -282,7 +282,50 @@ export function getResourceDir() { | |||||||
|     return join(dirname(fileURLToPath(import.meta.url)), "..", ".."); |     return join(dirname(fileURLToPath(import.meta.url)), "..", ".."); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // TODO: Deduplicate with src/public/app/services/utils.ts
 | ||||||
|  | /** | ||||||
|  |  * Compares two semantic version strings. | ||||||
|  |  * Returns: | ||||||
|  |  *   1  if v1 is greater than v2 | ||||||
|  |  *   0  if v1 is equal to v2 | ||||||
|  |  *   -1 if v1 is less than v2 | ||||||
|  |  * | ||||||
|  |  * @param v1 First version string | ||||||
|  |  * @param v2 Second version string | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function compareVersions(v1: string, v2: string): number { | ||||||
|  |     // Remove 'v' prefix and everything after dash if present
 | ||||||
|  |     v1 = v1.replace(/^v/, "").split("-")[0]; | ||||||
|  |     v2 = v2.replace(/^v/, "").split("-")[0]; | ||||||
|  | 
 | ||||||
|  |     const v1parts = v1.split(".").map(Number); | ||||||
|  |     const v2parts = v2.split(".").map(Number); | ||||||
|  | 
 | ||||||
|  |     // Pad shorter version with zeros
 | ||||||
|  |     while (v1parts.length < 3) v1parts.push(0); | ||||||
|  |     while (v2parts.length < 3) v2parts.push(0); | ||||||
|  | 
 | ||||||
|  |     // Compare major version
 | ||||||
|  |     if (v1parts[0] !== v2parts[0]) { | ||||||
|  |         return v1parts[0] > v2parts[0] ? 1 : -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Compare minor version
 | ||||||
|  |     if (v1parts[1] !== v2parts[1]) { | ||||||
|  |         return v1parts[1] > v2parts[1] ? 1 : -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Compare patch version
 | ||||||
|  |     if (v1parts[2] !== v2parts[2]) { | ||||||
|  |         return v1parts[2] > v2parts[2] ? 1 : -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default { | export default { | ||||||
|  |     compareVersions, | ||||||
|     crash, |     crash, | ||||||
|     deferred, |     deferred, | ||||||
|     envToBoolean, |     envToBoolean, | ||||||
|  | |||||||
| @ -51,6 +51,7 @@ ipcMain.on("create-extra-window", (event, arg) => { | |||||||
| interface ExportAsPdfOpts { | interface ExportAsPdfOpts { | ||||||
|     title: string; |     title: string; | ||||||
|     landscape: boolean; |     landscape: boolean; | ||||||
|  |     pageSize: "A0" | "A1" | "A2" | "A3" | "A4" | "A5" | "A6" | "Legal" | "Letter" | "Tabloid" | "Ledger"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => { | ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => { | ||||||
| @ -76,11 +77,14 @@ ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => { | |||||||
|     try { |     try { | ||||||
|         buffer = await browserWindow.webContents.printToPDF({ |         buffer = await browserWindow.webContents.printToPDF({ | ||||||
|             landscape: opts.landscape, |             landscape: opts.landscape, | ||||||
|  |             pageSize: opts.pageSize, | ||||||
|  |             generateDocumentOutline: true, | ||||||
|  |             generateTaggedPDF: true, | ||||||
|  |             printBackground: true, | ||||||
|             displayHeaderFooter: true, |             displayHeaderFooter: true, | ||||||
|             headerTemplate: `<div></div>`, |             headerTemplate: `<div></div>`, | ||||||
|             footerTemplate: ` |             footerTemplate: ` | ||||||
|                 <div style="width: 100%; text-align: center; font-size: 10pt;"> |                 <div class="pageNumber" style="width: 100%; text-align: center; font-size: 10pt;"> | ||||||
|                     <span class="pageNumber"></span> |  | ||||||
|                 </div> |                 </div> | ||||||
|             ` |             ` | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -56,18 +56,26 @@ | |||||||
|         <div id="setup-type" data-bind="visible: step() == 'setup-type'" style="margin-top: 20px;"> |         <div id="setup-type" data-bind="visible: step() == 'setup-type'" style="margin-top: 20px;"> | ||||||
|             <form data-bind="submit: selectSetupType"> |             <form data-bind="submit: selectSetupType"> | ||||||
| 
 | 
 | ||||||
|               <div class="radio" style="margin-bottom: 15px;"> |             <div class="radio" style="margin-bottom: 15px;"> | ||||||
|                   <label><input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType""> |                 <label class="tn-radio"> | ||||||
|                       <%= t("setup.new-document") %></label> |                     <input type="radio" name="setup-type" value="new-document" data-bind="checked: setupType"> | ||||||
|               </div> |                     <%= t("setup.new-document") %> | ||||||
|               <div class="radio" style="margin-bottom: 15px;"> |                 </label> | ||||||
|                   <label><input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType"> |             </div> | ||||||
|                       <%= t("setup.sync-from-desktop") %></label> | 
 | ||||||
|               </div> |             <div class="radio" style="margin-bottom: 15px;"> | ||||||
|               <div class="radio" style="margin-bottom: 15px;"> |                 <label class="tn-radio"> | ||||||
|                   <label><input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType""> |                     <input type="radio" name="setup-type" value="sync-from-desktop" data-bind="checked: setupType"> | ||||||
|                       <%= t("setup.sync-from-server") %></label> |                     <%= t("setup.sync-from-desktop") %> | ||||||
|               </div> |                 </label> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div class="radio" style="margin-bottom: 15px;"> | ||||||
|  |                 <label class="tn-radio"> | ||||||
|  |                     <input type="radio" name="setup-type" value="sync-from-server" data-bind="checked: setupType"> | ||||||
|  |                     <%= t("setup.sync-from-server") %> | ||||||
|  |                 </label> | ||||||
|  |             </div> | ||||||
| 
 | 
 | ||||||
|               <button type="submit" data-bind="disable: !setupTypeSelected()" class="btn btn-primary"><%= t("setup.next") %></button> |               <button type="submit" data-bind="disable: !setupTypeSelected()" class="btn btn-primary"><%= t("setup.next") %></button> | ||||||
|             </form> |             </form> | ||||||
|  | |||||||
| @ -12,7 +12,8 @@ import ws from "./services/ws.js"; | |||||||
| import utils from "./services/utils.js"; | import utils from "./services/utils.js"; | ||||||
| import port from "./services/port.js"; | import port from "./services/port.js"; | ||||||
| import host from "./services/host.js"; | import host from "./services/host.js"; | ||||||
| import semver from "semver"; | 
 | ||||||
|  | const MINIMUM_NODE_VERSION = "22.0.0"; | ||||||
| 
 | 
 | ||||||
| // setup basic error handling even before requiring dependencies, since those can produce errors as well
 | // setup basic error handling even before requiring dependencies, since those can produce errors as well
 | ||||||
| 
 | 
 | ||||||
| @ -32,8 +33,8 @@ function exit() { | |||||||
| process.on("SIGINT", exit); | process.on("SIGINT", exit); | ||||||
| process.on("SIGTERM", exit); | process.on("SIGTERM", exit); | ||||||
| 
 | 
 | ||||||
| if (!semver.satisfies(process.version, ">=10.5.0")) { | if (utils.compareVersions(process.version, MINIMUM_NODE_VERSION) < 0) { | ||||||
|     console.error("Trilium only supports node.js 10.5 and later"); |     console.error(`\nTrilium requires Node.js ${MINIMUM_NODE_VERSION} and later.\n`); | ||||||
|     process.exit(1); |     process.exit(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran