mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-29 02:28:57 +01:00 
			
		
		
		
	Merge branch 'feature/typescript_backend_3' into feature/typescript_backend_4
This commit is contained in:
		
						commit
						0daa4cc89a
					
				| @ -1,7 +0,0 @@ | ||||
| node_modules | ||||
| dist | ||||
| bin | ||||
| docs | ||||
| libraries | ||||
| coverage | ||||
| play | ||||
							
								
								
									
										212
									
								
								.eslintrc.js
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								.eslintrc.js
									
									
									
									
									
								
							| @ -1,212 +0,0 @@ | ||||
| module.exports = { | ||||
|     env: { | ||||
|         browser: true, | ||||
|         commonjs: true, | ||||
|         es2021: true, | ||||
|         node: true, | ||||
|     }, | ||||
|     // plugins: ['prettier'], // to be activated
 | ||||
|     extends: ['eslint:recommended', 'airbnb-base', 'plugin:jsonc/recommended-with-jsonc', 'prettier'], | ||||
|     overrides: [ | ||||
|         { | ||||
|             files: ['*.json', '*.json5', '*.jsonc'], | ||||
|             parser: 'jsonc-eslint-parser', | ||||
|         }, | ||||
|         { | ||||
|             files: ['package.json'], | ||||
|             parser: 'jsonc-eslint-parser', | ||||
|             rules: { | ||||
|                 'jsonc/sort-keys': [ | ||||
|                     'off', | ||||
|                     { | ||||
|                         pathPattern: '^$', | ||||
|                         order: [ | ||||
|                             'name', | ||||
|                             'version', | ||||
|                             'private', | ||||
|                             'packageManager', | ||||
|                             'description', | ||||
|                             'type', | ||||
|                             'keywords', | ||||
|                             'homepage', | ||||
|                             'bugs', | ||||
|                             'license', | ||||
|                             'author', | ||||
|                             'contributors', | ||||
|                             'funding', | ||||
|                             'files', | ||||
|                             'main', | ||||
|                             'module', | ||||
|                             'exports', | ||||
|                             'unpkg', | ||||
|                             'jsdelivr', | ||||
|                             'browser', | ||||
|                             'bin', | ||||
|                             'man', | ||||
|                             'directories', | ||||
|                             'repository', | ||||
|                             'publishConfig', | ||||
|                             'scripts', | ||||
|                             'peerDependencies', | ||||
|                             'peerDependenciesMeta', | ||||
|                             'optionalDependencies', | ||||
|                             'dependencies', | ||||
|                             'devDependencies', | ||||
|                             'engines', | ||||
|                             'config', | ||||
|                             'overrides', | ||||
|                             'pnpm', | ||||
|                             'husky', | ||||
|                             'lint-staged', | ||||
|                             'eslintConfig', | ||||
|                         ], | ||||
|                     }, | ||||
|                     { | ||||
|                         pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies$', | ||||
|                         order: { type: 'asc' }, | ||||
|                     }, | ||||
|                 ], | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
|     globals: { | ||||
|         $: true, | ||||
|         jQuery: true, | ||||
|         glob: true, | ||||
|         log: true, | ||||
|         EditorWatchdog: true, | ||||
|         React: true, | ||||
|         appState: true, | ||||
|         ExcalidrawLib: true, | ||||
|         elements: true, | ||||
|         files: true, | ||||
|         ReactDOM: true, | ||||
|         // src\public\app\widgets\type_widgets\relation_map.js
 | ||||
|         jsPlumb: true, | ||||
|         panzoom: true, | ||||
|         logError: true, | ||||
|         // src\public\app\widgets\type_widgets\image.js
 | ||||
|         WZoom: true, | ||||
|         // \src\public\app\widgets\type_widgets\read_only_text.js
 | ||||
|         renderMathInElement: true, | ||||
|         // \src\public\app\widgets\type_widgets\editable_text.js
 | ||||
|         BalloonEditor: true, | ||||
|         FancytreeNode: true, | ||||
|         CKEditorInspector: true, | ||||
|         // \src\public\app\widgets\type_widgets\editable_code.js
 | ||||
|         CodeMirror: true, | ||||
|         // \src\public\app\services\resizer.js
 | ||||
|         Split: true, | ||||
|         // \src\public\app\services\content_renderer.js
 | ||||
|         mermaid: true, | ||||
|         // src\public\app\services\frontend_script_api.js
 | ||||
|         dayjs: true, | ||||
|         // \src\public\app\widgets\note_map.js
 | ||||
|         ForceGraph: true, | ||||
|         // \src\public\app\setup.js
 | ||||
|         ko: true, | ||||
|         syncInProgress: true, | ||||
|         // src\public\app\services\utils.js
 | ||||
|         logInfo: true, | ||||
|         __non_webpack_require__: true, | ||||
|         describe: true, | ||||
|         it: true, | ||||
|         expect: true | ||||
|     }, | ||||
|     parserOptions: { | ||||
|         ecmaVersion: 'latest', | ||||
|         sourceType: 'module', | ||||
|     }, | ||||
|     rules: { | ||||
|         // eslint:recommended
 | ||||
|         'no-unused-vars': 'off', | ||||
|         'linebreak-style': 'off', | ||||
|         'no-useless-escape': 'off', | ||||
|         'no-empty': 'off', | ||||
|         'no-constant-condition': 'off', | ||||
|         'getter-return': 'off', | ||||
|         'no-cond-assign': 'off', | ||||
|         'no-async-promise-executor': 'off', | ||||
|         'no-extra-semi': 'off', | ||||
|         'no-inner-declarations': 'off', | ||||
| 
 | ||||
|         // prettier
 | ||||
|         'prettier/prettier': ['off', { endOfLine: 'auto' }], | ||||
| 
 | ||||
|         // airbnb-base
 | ||||
|         'no-console': 'off', | ||||
|         'no-plusplus': 'off', | ||||
|         'no-param-reassign': 'off', | ||||
|         'global-require': 'off', | ||||
|         'no-use-before-define': 'off', | ||||
|         'no-await-in-loop': 'off', | ||||
|         radix: 'off', | ||||
|         'import/order': 'off', | ||||
|         'import/no-extraneous-dependencies': 'off', | ||||
|         'prefer-destructuring': 'off', | ||||
|         'no-shadow': 'off', | ||||
|         'no-new': 'off', | ||||
|         'no-restricted-syntax': 'off', | ||||
|         strict: 'off', | ||||
|         'class-methods-use-this': 'off', | ||||
|         'no-else-return': 'off', | ||||
|         'import/no-dynamic-require': 'off', | ||||
|         'no-underscore-dangle': 'off', | ||||
|         'prefer-template': 'off', | ||||
|         'consistent-return': 'off', | ||||
|         'no-continue': 'off', | ||||
|         'object-shorthand': 'off', | ||||
|         'one-var': 'off', | ||||
|         'prefer-const': 'off', | ||||
|         'spaced-comment': 'off', | ||||
|         'no-loop-func': 'off', | ||||
|         'arrow-body-style': 'off', | ||||
| 
 | ||||
|         'guard-for-in': 'off', | ||||
|         'no-return-assign': 'off', | ||||
|         'dot-notation': 'off', | ||||
| 
 | ||||
|         'func-names': 'off', | ||||
|         'import/no-useless-path-segments': 'off', | ||||
|         'default-param-last': 'off', | ||||
|         'prefer-arrow-callback': 'off', | ||||
|         'no-unneeded-ternary': 'off', | ||||
|         'no-return-await': 'off', | ||||
|         'import/extensions': 'off', | ||||
| 
 | ||||
|         'no-var': 'off', | ||||
|         'import/newline-after-import': 'off', | ||||
|         'no-restricted-globals': 'off', | ||||
|         'operator-assignment': 'off', | ||||
|         'no-eval': 'off', | ||||
|         'max-classes-per-file': 'off', | ||||
|         'vars-on-top': 'off', | ||||
|         'no-bitwise': 'off', | ||||
|         'no-lonely-if': 'off', | ||||
|         'no-multi-assign': 'off', | ||||
|         'no-promise-executor-return': 'off', | ||||
|         'no-empty-function': 'off', | ||||
|         'import/no-unresolved': 'off', | ||||
|         camelcase: 'off', | ||||
|         eqeqeq: 'off', | ||||
|         'lines-between-class-members': 'off', | ||||
|         'import/no-cycle': 'off', | ||||
|         'new-cap': 'off', | ||||
|         'prefer-object-spread': 'off', | ||||
|         'no-new-func': 'off', | ||||
|         'no-unused-expressions': 'off', | ||||
|         'lines-around-directive': 'off', | ||||
|         'prefer-exponentiation-operator': 'off', | ||||
|         'no-restricted-properties': 'off', | ||||
|         'prefer-rest-params': 'off', | ||||
|         'no-unreachable-loop': 'off', | ||||
|         'no-alert': 'off', | ||||
|         'no-useless-return': 'off', | ||||
|         'no-nested-ternary': 'off', | ||||
|         'prefer-regex-literals': 'off', | ||||
|         'import/no-named-as-default-member': 'off', | ||||
|         yoda: 'off', | ||||
|         'no-script-url': 'off', | ||||
|         'no-prototype-builtins':'off' | ||||
|     }, | ||||
| }; | ||||
							
								
								
									
										1
									
								
								.husky/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.husky/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +0,0 @@ | ||||
| _ | ||||
| @ -1,4 +0,0 @@ | ||||
| #!/bin/sh | ||||
| . "$(dirname "$0")/_/husky.sh" | ||||
| 
 | ||||
| #npx lint-staged | ||||
							
								
								
									
										6
									
								
								.idea/jsLinters/eslint.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								.idea/jsLinters/eslint.xml
									
									
									
										generated
									
									
									
								
							| @ -1,6 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="EslintConfiguration"> | ||||
|     <option name="fix-on-save" value="true" /> | ||||
|   </component> | ||||
| </project> | ||||
| @ -1,13 +0,0 @@ | ||||
| //https://prettier.io/docs/en/options.html
 | ||||
| module.exports = { | ||||
| 	semi: true, | ||||
| 	trailingComma: 'none', | ||||
| 	singleQuote: true, | ||||
| 	printWidth: 100, | ||||
| 	tabWidth: 4, | ||||
| 	useTabs: false, | ||||
| 	quoteProps: "as-needed", | ||||
| 	bracketSpacing: true, | ||||
| 	arrowParens: "avoid" | ||||
| 	// htmlWhitespaceSensitivity: 'ignore',
 | ||||
| }; | ||||
							
								
								
									
										6
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +0,0 @@ | ||||
| { | ||||
|   "recommendations": [ | ||||
|     "dbaeumer.vscode-eslint", | ||||
|     "esbenp.prettier-vscode", | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										33
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -1,34 +1,5 @@ | ||||
| { | ||||
|   "[javascript]": { | ||||
|     "editor.defaultFormatter": "dbaeumer.vscode-eslint" | ||||
|   }, | ||||
|   "[json]": { | ||||
|     "editor.defaultFormatter": "dbaeumer.vscode-eslint" | ||||
|   }, | ||||
|   "editor.formatOnSave": true, | ||||
|   "eslint.format.enable": true, | ||||
|   "eslint.probe": [ | ||||
|     "javascript", | ||||
|     "javascriptreact", | ||||
|     "typescript", | ||||
|     "typescriptreact", | ||||
|     "html", | ||||
|     "vue", | ||||
|     "markdown", | ||||
|     "json", | ||||
|     "jsonc" | ||||
|   ], | ||||
|   "eslint.validate": [ | ||||
|     "javascript", | ||||
|     "javascriptreact", | ||||
|     "typescript", | ||||
|     "typescriptreact", | ||||
|     "html", | ||||
|     "vue", | ||||
|     "markdown", | ||||
|     "json", | ||||
|     "jsonc" | ||||
|   ], | ||||
|   "files.eol": "\n", | ||||
|   "typescript.tsdk": "node_modules/typescript/lib", | ||||
| } | ||||
|   "typescript.tsdk": "node_modules/typescript/lib" | ||||
| } | ||||
|  | ||||
| @ -2,49 +2,37 @@ | ||||
| 
 | ||||
| SRC_DIR=./dist/trilium-linux-x64-src | ||||
| 
 | ||||
| if [ "$1" != "DONTCOPY" ] | ||||
| then | ||||
|     ./bin/copy-trilium.sh $SRC_DIR | ||||
| fi | ||||
| [ "$1" != "DONTCOPY" ] && ./bin/copy-trilium.sh "$SRC_DIR" | ||||
| 
 | ||||
| rm -r $SRC_DIR/src/public/app-dist/*.mobile.* | ||||
| rm -r "$SRC_DIR"/src/public/app-dist/*.mobile.* | ||||
| 
 | ||||
| echo "Copying required linux-x64 binaries" | ||||
| 
 | ||||
| cp -r bin/better-sqlite3/linux-desktop-better_sqlite3.node $SRC_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node | ||||
| cp -r bin/better-sqlite3/linux-desktop-better_sqlite3.node "$SRC_DIR"/node_modules/better-sqlite3/build/Release/better_sqlite3.node | ||||
| 
 | ||||
| echo "Packaging linux x64 electron build" | ||||
| 
 | ||||
| ./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite | ||||
| ./node_modules/.bin/electron-packager "$SRC_DIR" --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite | ||||
| 
 | ||||
| BUILD_DIR=./dist/trilium-linux-x64 | ||||
| rm -rf $BUILD_DIR | ||||
| rm -rf "$BUILD_DIR" | ||||
| 
 | ||||
| mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR | ||||
| mv "./dist/Trilium Notes-linux-x64" "$BUILD_DIR" | ||||
| 
 | ||||
| cp images/app-icons/png/128x128.png $BUILD_DIR/icon.png | ||||
| cp images/app-icons/png/128x128.png "$BUILD_DIR"/icon.png | ||||
| cp bin/tpl/anonymize-database.sql "$BUILD_DIR"/ | ||||
| 
 | ||||
| cp bin/tpl/anonymize-database.sql $BUILD_DIR/ | ||||
| cp -r dump-db "$BUILD_DIR"/ | ||||
| rm -rf "$BUILD_DIR"/dump-db/node_modules | ||||
| 
 | ||||
| cp -r dump-db $BUILD_DIR/ | ||||
| rm -rf $BUILD_DIR/dump-db/node_modules | ||||
| 
 | ||||
| cp bin/tpl/trilium-portable.sh $BUILD_DIR/ | ||||
| chmod 755 $BUILD_DIR/trilium-portable.sh | ||||
| 
 | ||||
| cp bin/tpl/trilium-safe-mode.sh $BUILD_DIR/ | ||||
| chmod 755 $BUILD_DIR/trilium-safe-mode.sh | ||||
| 
 | ||||
| cp bin/tpl/trilium-no-cert-check.sh $BUILD_DIR/ | ||||
| chmod 755 $BUILD_DIR/trilium-no-cert-check.sh | ||||
| for f in 'trilium-portable' 'trilium-safe-mode' 'trilium-no-cert-check'; do | ||||
|     cp bin/tpl/"$f".sh "$BUILD_DIR"/ | ||||
|     chmod 755 "$BUILD_DIR"/"$f".sh | ||||
| done | ||||
| 
 | ||||
| echo "Packaging linux x64 electron distribution..." | ||||
| VERSION=`jq -r ".version" package.json` | ||||
| 
 | ||||
| cd dist | ||||
| 
 | ||||
| tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64 | ||||
| 
 | ||||
| cd .. | ||||
| pushd dist | ||||
|     tar cJf "trilium-linux-x64-${VERSION}.tar.xz" trilium-linux-x64 | ||||
| popd | ||||
| 
 | ||||
| bin/build-debian.sh | ||||
|  | ||||
| @ -4,47 +4,49 @@ if [[ $# -eq 0 ]] ; then | ||||
|     echo "Missing argument of target directory" | ||||
|     exit 1 | ||||
| fi | ||||
| if ! [[ $(which npm) ]]; then | ||||
|     echo "Missing npm" | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| n exec 18.18.2 npm run webpack | ||||
| n exec 18.18.2 npm run webpack || npm run webpack | ||||
| 
 | ||||
| DIR=$1 | ||||
| DIR="$1" | ||||
| 
 | ||||
| rm -rf $DIR | ||||
| mkdir $DIR | ||||
| rm -rf "$DIR" | ||||
| mkdir -pv "$DIR" | ||||
| 
 | ||||
| echo "Copying Trilium to build directory $DIR" | ||||
| 
 | ||||
| cp -r images $DIR/ | ||||
| cp -r libraries $DIR/ | ||||
| cp -r src $DIR/ | ||||
| cp -r db $DIR/ | ||||
| cp -r package.json $DIR/ | ||||
| cp -r package-lock.json $DIR/ | ||||
| cp -r README.md $DIR/ | ||||
| cp -r LICENSE $DIR/ | ||||
| cp -r config-sample.ini $DIR/ | ||||
| cp -r electron.js $DIR/ | ||||
| cp webpack-* $DIR/ | ||||
| for d in 'images' 'libraries' 'src' 'db'; do | ||||
|     cp -r "$d" "$DIR"/ | ||||
| done | ||||
| for f in 'package.json' 'package-lock.json' 'README.md' 'LICENSE' 'config-sample.ini' 'electron.js'; do | ||||
|     cp "$f" "$DIR"/ | ||||
| done | ||||
| cp webpack-* "$DIR"/      # here warning because there is no 'webpack-*', but webpack.config.js only | ||||
| 
 | ||||
| # run in subshell (so we return to original dir) | ||||
| (cd $DIR && n exec 18.18.2 npm install --only=prod) | ||||
| 
 | ||||
| if [[ -d "$DIR"/node_modules ]]; then | ||||
| # cleanup of useless files in dependencies | ||||
| rm -r $DIR/node_modules/image-q/demo | ||||
| rm -r $DIR/node_modules/better-sqlite3/Release | ||||
| rm -r $DIR/node_modules/better-sqlite3/deps/sqlite3.tar.gz | ||||
| rm -r $DIR/node_modules/@jimp/plugin-print/fonts | ||||
| rm -r $DIR/node_modules/jimp/browser | ||||
| rm -r $DIR/node_modules/jimp/fonts | ||||
|     for d in 'image-q/demo' 'better-sqlite3/Release' 'better-sqlite3/deps/sqlite3.tar.gz' '@jimp/plugin-print/fonts' 'jimp/browser' 'jimp/fonts'; do | ||||
|         [[ -e "$DIR"/node_modules/"$d" ]] && rm -rv "$DIR"/node_modules/"$d" | ||||
|     done | ||||
| 
 | ||||
| # delete all tests (there are often large images as test file for jimp etc.) | ||||
| find $DIR/node_modules -name test -exec rm -rf {} \; | ||||
| find $DIR/node_modules -name docs -exec rm -rf {} \; | ||||
| find $DIR/node_modules -name demo -exec rm -rf {} \; | ||||
|     for d in 'test' 'docs' 'demo'; do | ||||
|         find "$DIR"/node_modules -name "$d" -exec rm -rf {} \; | ||||
|     done | ||||
| fi | ||||
| 
 | ||||
| find $DIR/libraries -name "*.map" -type f -delete | ||||
| 
 | ||||
| cp $DIR/src/public/app/share.js $DIR/src/public/app-dist/ | ||||
| cp -r $DIR/src/public/app/doc_notes $DIR/src/public/app-dist/ | ||||
| d="$DIR"/src/public | ||||
| [[ -d "$d"/app-dist ]] || mkdir -pv "$d"/app-dist | ||||
| cp "$d"/app/share.js "$d"/app-dist/ | ||||
| cp -r "$d"/app/doc_notes "$d"/app-dist/ | ||||
| 
 | ||||
| rm -rf $DIR/src/public/app | ||||
| rm -rf "$d"/app | ||||
| unset f d DIR | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| module.exports = () => { | ||||
|     const beccaLoader = require('../../src/becca/becca_loader'); | ||||
|     const becca = require('../../src/becca/becca.js'); | ||||
|     const becca = require('../../src/becca/becca'); | ||||
|     const cls = require('../../src/services/cls'); | ||||
|     const log = require('../../src/services/log'); | ||||
|     const sql = require('../../src/services/sql'); | ||||
| @ -13,7 +13,7 @@ module.exports = () => { | ||||
| 
 | ||||
|         for (const note of Object.values(becca.notes)) { | ||||
|             try { | ||||
|                 const attachment = note.convertToParentAttachment({autoConversion: true}); | ||||
|                 const attachment = note.convertToParentAttachment({ autoConversion: true }); | ||||
| 
 | ||||
|                 if (attachment) { | ||||
|                     log.info(`Auto-converted note '${note.noteId}' into attachment '${attachment.attachmentId}'.`); | ||||
|  | ||||
| @ -10,7 +10,7 @@ if (config.Network.https) { | ||||
|     process.exit(0); | ||||
| } | ||||
| 
 | ||||
| const port = require('./src/services/port.ts'); | ||||
| const port = require('./src/services/port'); | ||||
| const host = require('./src/services/host'); | ||||
| 
 | ||||
| const options = { timeout: 2000 }; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| const fs = require("fs"); | ||||
| const sanitize = require("sanitize-filename"); | ||||
| const sql = require('./sql'); | ||||
| const sql = require('./sql.js'); | ||||
| const decryptService = require('./decrypt.js'); | ||||
| const dataKeyService = require('./data_key.js'); | ||||
| const extensionService = require('./extension.js'); | ||||
| @ -74,7 +74,7 @@ function dumpDocument(documentPath, targetPath, options) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             let {content} = sql.getRow("SELECT content FROM blobs WHERE blobId = ?", [noteRow.blobId]); | ||||
|             let { content } = sql.getRow("SELECT content FROM blobs WHERE blobId = ?", [noteRow.blobId]); | ||||
| 
 | ||||
|             if (content !== null && noteRow.isProtected && dataKey) { | ||||
|                 content = decryptService.decrypt(dataKey, content); | ||||
| @ -108,7 +108,7 @@ function dumpDocument(documentPath, targetPath, options) { | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 fs.mkdirSync(childTargetPath, {recursive: true}); | ||||
|                 fs.mkdirSync(childTargetPath, { recursive: true }); | ||||
|             } | ||||
|             catch (e) { | ||||
|                 console.error(`DUMPERROR: Creating directory ${childTargetPath} failed with error '${e.message}'`); | ||||
| @ -157,7 +157,7 @@ function validatePaths(documentPath, targetPath) { | ||||
|     } | ||||
| 
 | ||||
|     if (!fs.existsSync(targetPath)) { | ||||
|         const ret = fs.mkdirSync(targetPath, {recursive: true}); | ||||
|         const ret = fs.mkdirSync(targetPath, { recursive: true }); | ||||
| 
 | ||||
|         if (!ret) { | ||||
|             console.error(`Target path '${targetPath}' could not be created. Run with --help to see usage.`); | ||||
|  | ||||
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7293
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7293
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										77
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								package.json
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.63.1-beta", | ||||
|   "version": "0.63.5", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
| @ -31,21 +31,18 @@ | ||||
|     "test-jasmine": "TRILIUM_DATA_DIR=~/trilium/data-test jasmine", | ||||
|     "test-es6": "node -r esm spec-es6/attribute_parser.spec.js ", | ||||
|     "test": "npm run test-jasmine && npm run test-es6", | ||||
|     "postinstall": "rimraf ./node_modules/canvas", | ||||
|     "lint": "eslint .  --cache", | ||||
|     "prepare": "husky install || echo 'Husky install failed, expected on flatpak build'" | ||||
|     "postinstall": "rimraf ./node_modules/canvas" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@braintree/sanitize-url": "6.0.4", | ||||
|     "@electron/remote": "2.1.0", | ||||
|     "@excalidraw/excalidraw": "0.16.1", | ||||
|     "@types/cls-hooked": "^4.3.8", | ||||
|     "archiver": "6.0.1", | ||||
|     "async-mutex": "0.4.0", | ||||
|     "axios": "1.6.2", | ||||
|     "@electron/remote": "2.1.2", | ||||
|     "@excalidraw/excalidraw": "0.17.3", | ||||
|     "archiver": "7.0.0", | ||||
|     "async-mutex": "0.4.1", | ||||
|     "axios": "1.6.7", | ||||
|     "better-sqlite3": "8.4.0", | ||||
|     "boxicons": "2.1.4", | ||||
|     "chokidar": "3.5.3", | ||||
|     "chokidar": "3.6.0", | ||||
|     "cls-hooked": "4.2.2", | ||||
|     "compression": "1.7.4", | ||||
|     "cookie-parser": "1.4.6", | ||||
| @ -55,35 +52,35 @@ | ||||
|     "debounce": "1.2.1", | ||||
|     "ejs": "3.1.9", | ||||
|     "electron-debug": "3.2.0", | ||||
|     "electron-dl": "3.5.1", | ||||
|     "electron-dl": "3.5.2", | ||||
|     "electron-window-state": "5.0.3", | ||||
|     "escape-html": "1.0.3", | ||||
|     "express": "4.18.2", | ||||
|     "express": "4.18.3", | ||||
|     "express-partial-content": "1.0.2", | ||||
|     "express-rate-limit": "7.1.4", | ||||
|     "express-session": "1.17.3", | ||||
|     "force-graph": "1.43.4", | ||||
|     "fs-extra": "11.1.1", | ||||
|     "express-rate-limit": "7.2.0", | ||||
|     "express-session": "1.18.0", | ||||
|     "force-graph": "1.43.5", | ||||
|     "fs-extra": "11.2.0", | ||||
|     "helmet": "7.1.0", | ||||
|     "html": "1.0.0", | ||||
|     "html2plaintext": "2.1.4", | ||||
|     "http-proxy-agent": "7.0.0", | ||||
|     "https-proxy-agent": "7.0.2", | ||||
|     "http-proxy-agent": "7.0.2", | ||||
|     "https-proxy-agent": "7.0.4", | ||||
|     "image-type": "4.1.0", | ||||
|     "ini": "3.0.1", | ||||
|     "is-animated": "2.0.2", | ||||
|     "is-svg": "4.3.2", | ||||
|     "jimp": "0.22.10", | ||||
|     "jimp": "0.22.12", | ||||
|     "joplin-turndown-plugin-gfm": "1.0.12", | ||||
|     "jquery": "3.7.1", | ||||
|     "jquery-hotkeys": "0.2.2", | ||||
|     "jsdom": "22.1.0", | ||||
|     "jsdom": "24.0.0", | ||||
|     "katex": "0.16.9", | ||||
|     "marked": "9.1.6", | ||||
|     "mermaid": "10.6.1", | ||||
|     "marked": "12.0.0", | ||||
|     "mermaid": "10.9.0", | ||||
|     "mime-types": "2.1.35", | ||||
|     "multer": "1.4.5-lts.1", | ||||
|     "node-abi": "3.51.0", | ||||
|     "node-abi": "3.56.0", | ||||
|     "normalize-strings": "1.1.1", | ||||
|     "open": "8.4.1", | ||||
|     "panzoom": "9.4.3", | ||||
| @ -95,25 +92,26 @@ | ||||
|     "rimraf": "5.0.5", | ||||
|     "safe-compare": "1.1.4", | ||||
|     "sanitize-filename": "1.6.3", | ||||
|     "sanitize-html": "2.11.0", | ||||
|     "sanitize-html": "2.12.1", | ||||
|     "sax": "1.3.0", | ||||
|     "semver": "7.5.4", | ||||
|     "semver": "7.6.0", | ||||
|     "serve-favicon": "2.5.0", | ||||
|     "session-file-store": "1.5.0", | ||||
|     "split.js": "1.6.5", | ||||
|     "stream-throttle": "0.1.3", | ||||
|     "striptags": "3.2.0", | ||||
|     "tmp": "0.2.1", | ||||
|     "tmp": "0.2.3", | ||||
|     "tree-kill": "1.2.2", | ||||
|     "turndown": "7.1.2", | ||||
|     "unescape": "1.0.1", | ||||
|     "ws": "8.14.2", | ||||
|     "ws": "8.16.0", | ||||
|     "xml2js": "0.6.2", | ||||
|     "yauzl": "2.10.0" | ||||
|     "yauzl": "3.1.2" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/archiver": "^6.0.2", | ||||
|     "@types/better-sqlite3": "^7.6.9", | ||||
|     "@types/cls-hooked": "^4.3.8", | ||||
|     "@types/escape-html": "^1.0.4", | ||||
|     "@types/express": "^4.17.21", | ||||
|     "@types/html": "^1.0.4", | ||||
| @ -127,35 +125,22 @@ | ||||
|     "@types/xml2js": "^0.4.14", | ||||
|     "cross-env": "7.0.3", | ||||
|     "electron": "25.9.8", | ||||
|     "electron-builder": "24.6.4", | ||||
|     "electron-builder": "24.13.3", | ||||
|     "electron-packager": "17.1.2", | ||||
|     "electron-rebuild": "3.2.9", | ||||
|     "eslint": "8.54.0", | ||||
|     "eslint-config-airbnb-base": "15.0.0", | ||||
|     "eslint-config-prettier": "9.0.0", | ||||
|     "eslint-plugin-import": "2.29.0", | ||||
|     "eslint-plugin-jsonc": "2.10.0", | ||||
|     "eslint-plugin-prettier": "5.0.1", | ||||
|     "esm": "3.2.25", | ||||
|     "husky": "8.0.3", | ||||
|     "jasmine": "5.1.0", | ||||
|     "jsdoc": "4.0.2", | ||||
|     "jsonc-eslint-parser": "2.4.0", | ||||
|     "lint-staged": "15.1.0", | ||||
|     "lorem-ipsum": "2.0.8", | ||||
|     "nodemon": "3.0.1", | ||||
|     "prettier": "3.1.0", | ||||
|     "nodemon": "3.1.0", | ||||
|     "rcedit": "4.0.1", | ||||
|     "ts-node": "^10.9.2", | ||||
|     "tslib": "^2.6.2", | ||||
|     "typescript": "^5.3.3", | ||||
|     "webpack": "5.89.0", | ||||
|     "webpack": "5.90.3", | ||||
|     "webpack-cli": "5.1.4" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "electron-installer-debian": "3.2.0" | ||||
|   }, | ||||
|   "lint-staged": { | ||||
|     "*.js": "eslint --cache --fix" | ||||
|   } | ||||
| } | ||||
| } | ||||
| @ -11,6 +11,7 @@ import BAttachment = require('./entities/battachment'); | ||||
| import { AttachmentRow, RevisionRow } from './entities/rows'; | ||||
| import BBlob = require('./entities/bblob'); | ||||
| import BRecentNote = require('./entities/brecent_note'); | ||||
| import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); | ||||
| 
 | ||||
| interface AttachmentOpts { | ||||
|     includeContentLength?: boolean; | ||||
| @ -20,7 +21,7 @@ interface AttachmentOpts { | ||||
|  * Becca is a backend cache of all notes, branches, and attributes. | ||||
|  * There's a similar frontend cache Froca, and share cache Shaca. | ||||
|  */ | ||||
| class Becca { | ||||
| export default class Becca { | ||||
|     loaded!: boolean; | ||||
| 
 | ||||
|     notes!: Record<string, BNote>; | ||||
| @ -190,7 +191,11 @@ class Becca { | ||||
|             .map(row => new BAttachment(row)); | ||||
|     } | ||||
| 
 | ||||
|     getBlob(entity: { blobId: string }): BBlob | null { | ||||
|     getBlob(entity: { blobId?: string }): BBlob | null { | ||||
|         if (!entity.blobId) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [entity.blobId]); | ||||
| 
 | ||||
|         const BBlob = require('./entities/bblob'); // avoiding circular dependency problems
 | ||||
| @ -209,8 +214,7 @@ class Becca { | ||||
|         return this.etapiTokens[etapiTokenId]; | ||||
|     } | ||||
| 
 | ||||
|     /** @returns {AbstractBeccaEntity|null} */ | ||||
|     getEntity(entityName: string, entityId: string) { | ||||
|     getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null { | ||||
|         if (!entityName || !entityId) { | ||||
|             return null; | ||||
|         } | ||||
| @ -276,4 +280,12 @@ class Becca { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export = Becca; | ||||
| /** | ||||
|  * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. | ||||
|  * For example, all BAttributes will share their content, but all BBranches will have another set of this data.  | ||||
|  */ | ||||
| export interface ConstructorData<T extends AbstractBeccaEntity<T>> { | ||||
|     primaryKeyName: string; | ||||
|     entityName: string; | ||||
|     hashedProperties: (keyof T)[]; | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| import Becca = require("./becca-interface"); | ||||
| import Becca from "./becca-interface"; | ||||
| 
 | ||||
| const becca = new Becca(); | ||||
| 
 | ||||
|  | ||||
| @ -13,6 +13,7 @@ import BEtapiToken = require('./entities/betapi_token'); | ||||
| import cls = require('../services/cls'); | ||||
| import entityConstructor = require('../becca/entity_constructor'); | ||||
| import { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from './entities/rows'; | ||||
| import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); | ||||
| 
 | ||||
| const beccaLoaded = new Promise<void>((res, rej) => { | ||||
|     sqlInit.dbReady.then(() => { | ||||
| @ -75,7 +76,7 @@ function reload(reason: string) { | ||||
|     require('../services/ws').reloadFrontend(reason || "becca reloaded"); | ||||
| } | ||||
| 
 | ||||
| eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED],  ({entityName, entityRow}) => { | ||||
| eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({ entityName, entityRow }) => { | ||||
|     if (!becca.loaded) { | ||||
|         return; | ||||
|     } | ||||
| @ -89,7 +90,7 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED],  ({entity | ||||
|         if (beccaEntity) { | ||||
|             beccaEntity.updateFromRow(entityRow); | ||||
|         } else { | ||||
|             beccaEntity = new EntityClass(); | ||||
|             beccaEntity = new EntityClass() as AbstractBeccaEntity<AbstractBeccaEntity<any>>; | ||||
|             beccaEntity.updateFromRow(entityRow); | ||||
|             beccaEntity.init(); | ||||
|         } | ||||
| @ -98,7 +99,7 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED],  ({entity | ||||
|     postProcessEntityUpdate(entityName, entityRow); | ||||
| }); | ||||
| 
 | ||||
| eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED,  ({entityName, entity}) => { | ||||
| eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({ entityName, entity }) => { | ||||
|     if (!becca.loaded) { | ||||
|         return; | ||||
|     } | ||||
| @ -125,7 +126,7 @@ function postProcessEntityUpdate(entityName: string, entityRow: any) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED],  ({entityName, entityId}) => { | ||||
| eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED], ({ entityName, entityId }) => { | ||||
|     if (!becca.loaded) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @ -9,7 +9,7 @@ import cls = require('../../services/cls'); | ||||
| import log = require('../../services/log'); | ||||
| import protectedSessionService = require('../../services/protected_session'); | ||||
| import blobService = require('../../services/blob'); | ||||
| import Becca = require('../becca-interface'); | ||||
| import Becca, { ConstructorData } from '../becca-interface'; | ||||
| 
 | ||||
| let becca: Becca | null = null; | ||||
| 
 | ||||
| @ -18,26 +18,22 @@ interface ContentOpts { | ||||
|     forceFrontendReload?: boolean; | ||||
| } | ||||
| 
 | ||||
| interface ConstructorData<T extends AbstractBeccaEntity<T>> { | ||||
|     primaryKeyName: string; | ||||
|     entityName: string; | ||||
|     hashedProperties: (keyof T)[]; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Base class for all backend entities. | ||||
|  *  | ||||
|  * @type T the same entity type needed for self-reference in {@link ConstructorData}. | ||||
|  */ | ||||
| abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
| 
 | ||||
|     utcDateModified?: string; | ||||
|     protected dateCreated?: string; | ||||
|     protected dateModified?: string; | ||||
|     protected isSynced?: boolean; | ||||
|      | ||||
|     protected blobId?: string; | ||||
|      | ||||
|     utcDateCreated!: string; | ||||
| 
 | ||||
|     isProtected?: boolean; | ||||
|     isSynced?: boolean; | ||||
|     blobId?: string; | ||||
| 
 | ||||
|     protected beforeSaving() { | ||||
|         const constructorData = (this.constructor as unknown as ConstructorData<T>); | ||||
| @ -46,7 +42,7 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected getUtcDateChanged() { | ||||
|     getUtcDateChanged() { | ||||
|         return this.utcDateModified || this.utcDateCreated; | ||||
|     } | ||||
| 
 | ||||
| @ -70,7 +66,7 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     protected generateHash(isDeleted: boolean): string { | ||||
|     generateHash(isDeleted?: boolean): string { | ||||
|         const constructorData = (this.constructor as unknown as ConstructorData<T>); | ||||
|         let contentToHash = ""; | ||||
| 
 | ||||
| @ -96,6 +92,10 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
| 
 | ||||
|     abstract getPojo(): {}; | ||||
| 
 | ||||
|     abstract init(): void; | ||||
| 
 | ||||
|     abstract updateFromRow(row: unknown): void; | ||||
| 
 | ||||
|     get isDeleted(): boolean { | ||||
|         // TODO: Not sure why some entities don't implement it.
 | ||||
|         return false; | ||||
|  | ||||
| @ -11,7 +11,8 @@ import BNote = require('./bnote'); | ||||
| import BBranch = require('./bbranch'); | ||||
| 
 | ||||
| const attachmentRoleToNoteTypeMapping = { | ||||
|     'image': 'image' | ||||
|     'image': 'image', | ||||
|     'file': 'file' | ||||
| }; | ||||
| 
 | ||||
| interface ContentOpts { | ||||
| @ -36,10 +37,10 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|     noteId?: number; | ||||
|     attachmentId?: string; | ||||
|     /** either noteId or revisionId to which this attachment belongs */ | ||||
|     ownerId: string; | ||||
|     role: string; | ||||
|     mime: string; | ||||
|     title: string; | ||||
|     ownerId!: string; | ||||
|     role!: string; | ||||
|     mime!: string; | ||||
|     title!: string; | ||||
|     type?: keyof typeof attachmentRoleToNoteTypeMapping; | ||||
|     position?: number; | ||||
|     blobId?: string; | ||||
| @ -53,6 +54,11 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|     constructor(row: AttachmentRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|         this.decrypt(); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: AttachmentRow): void { | ||||
|         if (!row.ownerId?.trim()) { | ||||
|             throw new Error("'ownerId' must be given to initialize a Attachment entity"); | ||||
|         } else if (!row.role?.trim()) { | ||||
| @ -75,8 +81,10 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||
|         this.contentLength = row.contentLength; | ||||
|     } | ||||
| 
 | ||||
|         this.decrypt(); | ||||
|     init(): void { | ||||
|         // Do nothing.
 | ||||
|     } | ||||
| 
 | ||||
|     copy(): BAttachment { | ||||
| @ -130,7 +138,7 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|         return this._getContent() as Buffer; | ||||
|     } | ||||
| 
 | ||||
|     setContent(content: any, opts: ContentOpts) { | ||||
|     setContent(content: string | Buffer, opts: ContentOpts) { | ||||
|         this._setContent(content, opts); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,18 +1,24 @@ | ||||
| import AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||
| import { BlobRow } from "./rows"; | ||||
| 
 | ||||
| // TODO: Why this does not extend the abstract becca?
 | ||||
| class BBlob { | ||||
| class BBlob extends AbstractBeccaEntity<BBlob> { | ||||
|     static get entityName() { return "blobs"; } | ||||
|     static get primaryKeyName() { return "blobId"; } | ||||
|     static get hashedProperties() { return ["blobId", "content"]; } | ||||
| 
 | ||||
|     blobId: string; | ||||
|     content: string | Buffer; | ||||
|     contentLength: number; | ||||
|     dateModified: string; | ||||
|     utcDateModified: string; | ||||
|     blobId!: string; | ||||
|     content!: string | Buffer; | ||||
|     contentLength!: number; | ||||
|     dateModified!: string; | ||||
|     utcDateModified!: string; | ||||
| 
 | ||||
|     constructor(row: BlobRow) { | ||||
|         super(); | ||||
|         this.updateFromRow(row); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: BlobRow): void { | ||||
|         this.blobId = row.blobId; | ||||
|         this.content = row.content; | ||||
|         this.contentLength = row.contentLength; | ||||
| @ -20,6 +26,10 @@ class BBlob { | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|     } | ||||
| 
 | ||||
|     init() { | ||||
|         // Nothing to do.
 | ||||
|     } | ||||
| 
 | ||||
|     getPojo() { | ||||
|         return { | ||||
|             blobId: this.blobId, | ||||
|  | ||||
| @ -1657,6 +1657,10 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|             position | ||||
|         }); | ||||
| 
 | ||||
|         if (!content) { | ||||
|             throw new Error("Attempted to save an attachment with no content."); | ||||
|         } | ||||
| 
 | ||||
|         attachment.setContent(content, {forceSave: true}); | ||||
| 
 | ||||
|         return attachment; | ||||
|  | ||||
| @ -32,6 +32,10 @@ class BOption extends AbstractBeccaEntity<BOption> { | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|     } | ||||
| 
 | ||||
|     init(): void { | ||||
|         // Do nothing.
 | ||||
|     } | ||||
| 
 | ||||
|     beforeSaving() { | ||||
|         super.beforeSaving(); | ||||
| 
 | ||||
|  | ||||
| @ -11,19 +11,28 @@ import AbstractBeccaEntity = require('./abstract_becca_entity'); | ||||
| class BRecentNote extends AbstractBeccaEntity<BRecentNote> { | ||||
|     static get entityName() { return "recent_notes"; } | ||||
|     static get primaryKeyName() { return "noteId"; } | ||||
|     static get hashedProperties() { return ["noteId", "notePath"]; } | ||||
| 
 | ||||
|     noteId: string; | ||||
|     notePath: string; | ||||
|     utcDateCreated: string; | ||||
|     noteId!: string; | ||||
|     notePath!: string; | ||||
|     utcDateCreated!: string; | ||||
| 
 | ||||
|     constructor(row: RecentNoteRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: RecentNoteRow): void { | ||||
|         this.noteId = row.noteId; | ||||
|         this.notePath = row.notePath; | ||||
|         this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime(); | ||||
|     } | ||||
| 
 | ||||
|     init(): void { | ||||
|         // Do nothing.
 | ||||
|     } | ||||
| 
 | ||||
|     getPojo() { | ||||
|         return { | ||||
|             noteId: this.noteId, | ||||
|  | ||||
| @ -29,22 +29,30 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|                                             "utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"]; } | ||||
| 
 | ||||
|     revisionId?: string; | ||||
|     noteId: string; | ||||
|     type: string; | ||||
|     mime: string; | ||||
|     isProtected: boolean; | ||||
|     title: string; | ||||
|     noteId!: string; | ||||
|     type!: string; | ||||
|     mime!: string; | ||||
|     isProtected!: boolean; | ||||
|     title!: string; | ||||
|     blobId?: string; | ||||
|     dateLastEdited?: string; | ||||
|     dateCreated: string; | ||||
|     dateCreated!: string; | ||||
|     utcDateLastEdited?: string; | ||||
|     utcDateCreated: string; | ||||
|     utcDateCreated!: string; | ||||
|     contentLength?: number; | ||||
|     content?: string; | ||||
| 
 | ||||
|     constructor(row: RevisionRow, titleDecrypted = false) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|         if (this.isProtected && !titleDecrypted) { | ||||
|             const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null; | ||||
|             this.title = decryptedTitle || "[protected]"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: RevisionRow) { | ||||
|         this.revisionId = row.revisionId; | ||||
|         this.noteId = row.noteId; | ||||
|         this.type = row.type; | ||||
| @ -58,11 +66,10 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|         this.utcDateCreated = row.utcDateCreated; | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|         this.contentLength = row.contentLength; | ||||
|     } | ||||
| 
 | ||||
|         if (this.isProtected && !titleDecrypted) { | ||||
|             const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null; | ||||
|             this.title = decryptedTitle || "[protected]"; | ||||
|         } | ||||
|     init() { | ||||
|         // Do nothing.
 | ||||
|     } | ||||
| 
 | ||||
|     getNote() { | ||||
| @ -115,7 +122,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     setContent(content: any, opts: ContentOpts = {}) { | ||||
|     setContent(content: string | Buffer, opts: ContentOpts = {}) { | ||||
|         this._setContent(content, opts); | ||||
|     } | ||||
| 
 | ||||
| @ -158,6 +165,13 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|         return this.getAttachments().filter(attachment => attachment.title === title)[0]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Revisions are not soft-deletable, they are immediately hard-deleted (erased). | ||||
|      */ | ||||
|     eraseRevision() { | ||||
|         require("../../services/erase.js").eraseRevisions([this.revisionId]); | ||||
|     } | ||||
| 
 | ||||
|     beforeSaving() { | ||||
|         super.beforeSaving(); | ||||
| 
 | ||||
|  | ||||
| @ -108,7 +108,3 @@ export interface NoteRow { | ||||
|     utcDateModified: string; | ||||
|     content?: string; | ||||
| } | ||||
| 
 | ||||
| export interface AttributeRow { | ||||
|      | ||||
| } | ||||
| @ -1,3 +1,5 @@ | ||||
| import { ConstructorData } from './becca-interface'; | ||||
| import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); | ||||
| import BAttachment = require('./entities/battachment'); | ||||
| import BAttribute = require('./entities/battribute'); | ||||
| import BBlob = require('./entities/bblob'); | ||||
| @ -8,7 +10,9 @@ import BOption = require('./entities/boption'); | ||||
| import BRecentNote = require('./entities/brecent_note'); | ||||
| import BRevision = require('./entities/brevision'); | ||||
| 
 | ||||
| const ENTITY_NAME_TO_ENTITY: Record<string, any> = { | ||||
| type EntityClass = new (row?: any) => AbstractBeccaEntity<any>; | ||||
| 
 | ||||
| const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass> = { | ||||
|     "attachments": BAttachment, | ||||
|     "attributes": BAttribute, | ||||
|     "blobs": BBlob, | ||||
|  | ||||
| @ -43,7 +43,7 @@ interface DateLimits { | ||||
| function filterUrlValue(value: string) { | ||||
|     return value | ||||
|         .replace(/https?:\/\//ig, "") | ||||
|         .replace(/www\./ig, "") | ||||
|         .replace(/www.js\./ig, "") | ||||
|         .replace(/(\.net|\.com|\.org|\.info|\.edu)/ig, ""); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -4,6 +4,7 @@ import froca from "./froca.js"; | ||||
| import attributeRenderer from "./attribute_renderer.js"; | ||||
| import libraryLoader from "./library_loader.js"; | ||||
| import treeService from "./tree.js"; | ||||
| import utils from "./utils.js"; | ||||
| 
 | ||||
| const TPL = ` | ||||
| <div class="note-list"> | ||||
| @ -215,7 +216,11 @@ class NoteListRenderer { | ||||
|         if (highlightedTokens.length > 0) { | ||||
|             await libraryLoader.requireLibrary(libraryLoader.MARKJS); | ||||
| 
 | ||||
|             this.highlightRegex = new RegExp(highlightedTokens.join("|"), 'gi'); | ||||
|             const regex = highlightedTokens | ||||
|                 .map(token => utils.escapeRegExp(token)) | ||||
|                 .join("|"); | ||||
| 
 | ||||
|             this.highlightRegex = new RegExp(regex, 'gi'); | ||||
|         } else { | ||||
|             this.highlightRegex = null; | ||||
|         } | ||||
|  | ||||
| @ -487,12 +487,14 @@ function areObjectsEqual () { | ||||
| } | ||||
| 
 | ||||
| function copyHtmlToClipboard(content) { | ||||
|     const clipboardItem = new ClipboardItem({ | ||||
|         'text/html': new Blob([content], {type: 'text/html'}), | ||||
|         'text/plain': new Blob([content], {type: 'text/plain'}) | ||||
|     }); | ||||
| 
 | ||||
|     navigator.clipboard.write([clipboardItem]); | ||||
|     function listener(e) { | ||||
|         e.clipboardData.setData("text/html", content); | ||||
|         e.clipboardData.setData("text/plain", content); | ||||
|         e.preventDefault(); | ||||
|     } | ||||
|     document.addEventListener("copy", listener); | ||||
|     document.execCommand("copy"); | ||||
|     document.removeEventListener("copy", listener); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -1,10 +1,8 @@ | ||||
| import libraryLoader from "../../services/library_loader.js"; | ||||
| import TypeWidget from "./type_widget.js"; | ||||
| import libraryLoader from '../../services/library_loader.js'; | ||||
| import TypeWidget from './type_widget.js'; | ||||
| import utils from '../../services/utils.js'; | ||||
| import linkService from '../../services/link.js'; | ||||
| import debounce from "../../services/debounce.js"; | ||||
| 
 | ||||
| const {sleep} = utils; | ||||
| import debounce from '../../services/debounce.js'; | ||||
| 
 | ||||
| const TPL = ` | ||||
|     <div class="canvas-widget note-detail-canvas note-detail-printable note-detail"> | ||||
| @ -115,7 +113,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         this.currentSceneVersion = this.SCENE_VERSION_INITIAL; | ||||
| 
 | ||||
|         // will be overwritten
 | ||||
|         this.excalidrawRef; | ||||
|         this.$render; | ||||
|         this.$widget; | ||||
|         this.reactHandlers; // used to control react state
 | ||||
| @ -155,7 +152,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 const renderElement = this.$render.get(0); | ||||
| 
 | ||||
|                 ReactDOM.unmountComponentAtNode(renderElement); | ||||
|                 ReactDOM.render(React.createElement(this.createExcalidrawReactApp), renderElement); | ||||
|                 const root = ReactDOM.createRoot(renderElement); | ||||
|                 root.render(React.createElement(this.createExcalidrawReactApp)); | ||||
|             }); | ||||
| 
 | ||||
|         return this.$widget; | ||||
| @ -179,9 +177,9 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         const blob = await note.getBlob(); | ||||
| 
 | ||||
|         // before we load content into excalidraw, make sure excalidraw has loaded
 | ||||
|         while (!this.excalidrawRef?.current) { | ||||
|             console.log("excalidrawRef not yet loaded, sleep 200ms..."); | ||||
|             await sleep(200); | ||||
|         while (!this.excalidrawApi) { | ||||
|             console.log("excalidrawApi not yet loaded, sleep 200ms..."); | ||||
|             await utils.sleep(200); | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
| @ -199,7 +197,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 collaborators: [] | ||||
|             }; | ||||
| 
 | ||||
|             this.excalidrawRef.current.updateScene(sceneData); | ||||
|             this.excalidrawApi.updateScene(sceneData); | ||||
|         } | ||||
|         else if (blob.content) { | ||||
|             // load saved content into excalidraw canvas
 | ||||
| @ -246,9 +244,9 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 fileArray.push(file); | ||||
|             } | ||||
| 
 | ||||
|             this.excalidrawRef.current.updateScene(sceneData); | ||||
|             this.excalidrawRef.current.addFiles(fileArray); | ||||
|             this.excalidrawRef.current.history.clear(); | ||||
|             this.excalidrawApi.updateScene(sceneData); | ||||
|             this.excalidrawApi.addFiles(fileArray); | ||||
|             this.excalidrawApi.history.clear(); | ||||
|         } | ||||
| 
 | ||||
|         Promise.all( | ||||
| @ -261,7 +259,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             } | ||||
| 
 | ||||
|             const libraryItems = blobs.map(blob => blob.getJsonContentSafely()).filter(item => !!item); | ||||
|             this.excalidrawRef.current.updateLibrary({libraryItems, merge: false}); | ||||
|             this.excalidrawApi.updateLibrary({libraryItems, merge: false}); | ||||
|         }); | ||||
| 
 | ||||
|         // set initial scene version
 | ||||
| @ -275,17 +273,17 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|      * this is automatically called after this.saveData(); | ||||
|      */ | ||||
|     async getData() { | ||||
|         const elements = this.excalidrawRef.current.getSceneElements(); | ||||
|         const appState = this.excalidrawRef.current.getAppState(); | ||||
|         const elements = this.excalidrawApi.getSceneElements(); | ||||
|         const appState = this.excalidrawApi.getAppState(); | ||||
| 
 | ||||
|         /** | ||||
|          * A file is not deleted, even though removed from canvas. Therefore, we only keep | ||||
|          * files that are referenced by an element. Maybe this will change with a new excalidraw version? | ||||
|          */ | ||||
|         const files = this.excalidrawRef.current.getFiles(); | ||||
|         const files = this.excalidrawApi.getFiles(); | ||||
| 
 | ||||
|         // parallel svg export to combat bitrot and enable rendering image for note inclusion, preview, and share
 | ||||
|         const svg = await window.ExcalidrawLib.exportToSvg({ | ||||
|         const svg = await ExcalidrawLib.exportToSvg({ | ||||
|             elements, | ||||
|             appState, | ||||
|             exportPadding: 5, // 5 px padding
 | ||||
| @ -321,7 +319,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             // this.libraryChanged is unset in dataSaved()
 | ||||
| 
 | ||||
|             // there's no separate method to get library items, so have to abuse this one
 | ||||
|             const libraryItems = await this.excalidrawRef.current.updateLibrary({merge: true}); | ||||
|             const libraryItems = await this.excalidrawApi.updateLibrary({merge: true}); | ||||
| 
 | ||||
|             let position = 10; | ||||
| 
 | ||||
| @ -379,9 +377,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|     createExcalidrawReactApp() { | ||||
|         const React = window.React; | ||||
|         const { Excalidraw } = window.ExcalidrawLib; | ||||
| 
 | ||||
|         const excalidrawRef = React.useRef(null); | ||||
|         this.excalidrawRef = excalidrawRef; | ||||
|         const excalidrawWrapperRef = React.useRef(null); | ||||
|         this.excalidrawWrapperRef = excalidrawWrapperRef; | ||||
|         const [dimensions, setDimensions] = React.useState({ | ||||
| @ -439,7 +434,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 React.createElement(Excalidraw, { | ||||
|                     // this makes sure that 1) manual theme switch button is hidden 2) theme stays as it should after opening menu
 | ||||
|                     theme: this.themeStyle, | ||||
|                     ref: excalidrawRef, | ||||
|                     excalidrawAPI: api => { this.excalidrawApi = api; }, | ||||
|                     width: dimensions.width, | ||||
|                     height: dimensions.height, | ||||
|                     onPaste: (data, event) => { | ||||
| @ -483,8 +478,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|     } | ||||
| 
 | ||||
|     getSceneVersion() { | ||||
|         if (this.excalidrawRef) { | ||||
|             const elements = this.excalidrawRef.current.getSceneElements(); | ||||
|         if (this.excalidrawApi) { | ||||
|             const elements = this.excalidrawApi.getSceneElements(); | ||||
|             return window.ExcalidrawLib.getSceneVersion(elements); | ||||
|         } else { | ||||
|             return this.SCENE_VERSION_ERROR; | ||||
|  | ||||
| @ -88,3 +88,7 @@ body .CodeMirror { | ||||
| .excalidraw.theme--dark { | ||||
|     --theme-filter: invert(80%) hue-rotate(180deg) !important; | ||||
| } | ||||
| 
 | ||||
| body .todo-list input[type="checkbox"]:not(:checked):before { | ||||
|     border-color: var(--muted-text-color) !important; | ||||
| } | ||||
|  | ||||
| @ -20,7 +20,7 @@ function getBlobPojo(entityName: string, entityId: string) { | ||||
|     if (!entity.hasStringContent()) { | ||||
|         pojo.content = null; | ||||
|     } else { | ||||
|         pojo.content = processContent(pojo.content, entity.isProtected, true); | ||||
|         pojo.content = processContent(pojo.content, !!entity.isProtected, true); | ||||
|     } | ||||
| 
 | ||||
|     return pojo; | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| export = { buildDate:"2024-01-21T23:49:23+01:00", buildRevision: "4f8073daa7cff1b8b6737ae45792b2e87c2adf33" }; | ||||
| export = { buildDate:"2024-03-28T07:11:39+01:00", buildRevision: "399458b52f250b22be22d980a78de0b3390d7521" }; | ||||
|  | ||||
| @ -20,6 +20,6 @@ export interface EntityRow { | ||||
| } | ||||
| 
 | ||||
| export interface EntityChangeRecord { | ||||
|     entityChange: EntityChange; | ||||
|     entity?: EntityRow; | ||||
| 	entityChange: EntityChange; | ||||
| 	entity?: EntityRow; | ||||
| } | ||||
|  | ||||
| @ -1,15 +1,15 @@ | ||||
| interface DefinitionObject { | ||||
|     isPromoted: boolean; | ||||
|     labelType: string; | ||||
|     multiplicity: string; | ||||
|     numberPrecision: number; | ||||
|     promotedAlias: string; | ||||
|     inverseRelation: string; | ||||
|     isPromoted?: boolean; | ||||
|     labelType?: string; | ||||
|     multiplicity?: string; | ||||
|     numberPrecision?: number; | ||||
|     promotedAlias?: string; | ||||
|     inverseRelation?: string; | ||||
| } | ||||
| 
 | ||||
| function parse(value: string): DefinitionObject { | ||||
|     const tokens = value.split(',').map(t => t.trim()); | ||||
|     const defObj: Partial<DefinitionObject> = {}; | ||||
|     const defObj: DefinitionObject = {}; | ||||
| 
 | ||||
|     for (const token of tokens) { | ||||
|         if (token === 'promoted') { | ||||
| @ -41,7 +41,7 @@ function parse(value: string): DefinitionObject { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return defObj as DefinitionObject; | ||||
|     return defObj; | ||||
| } | ||||
| 
 | ||||
| export = { | ||||
|  | ||||
| @ -128,11 +128,7 @@ class NoteContentFulltextExp extends Expression { | ||||
| 
 | ||||
|         if (type === 'text' && mime === 'text/html') { | ||||
|             if (!this.raw && content.length < 20000) { // striptags is slow for very large notes
 | ||||
|                 // allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
 | ||||
|                 content = striptags(content, ['a'], ' '); | ||||
| 
 | ||||
|                 // at least the closing tag can be easily stripped
 | ||||
|                 content = content.replace(/<\/a>/ig, ""); | ||||
|                 content = this.stripTags(content); | ||||
|             } | ||||
| 
 | ||||
|             content = content.replace(/ /g, ' '); | ||||
| @ -140,6 +136,23 @@ class NoteContentFulltextExp extends Expression { | ||||
| 
 | ||||
|         return content.trim(); | ||||
|     } | ||||
| 
 | ||||
|     stripTags(content: string) { | ||||
|         // we want to allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
 | ||||
|         // we want to insert space in place of block tags (because they imply text separation)
 | ||||
|         // but we don't want to insert text for typical formatting inline tags which can occur within one word
 | ||||
|         const linkTag = 'a'; | ||||
|         const inlineFormattingTags = ['b', 'strong', 'em', 'i', 'span', 'big', 'small', 'font', 'sub', 'sup']; | ||||
| 
 | ||||
|         // replace tags which imply text separation with a space
 | ||||
|         content = striptags(content, [linkTag, ...inlineFormattingTags], ' '); | ||||
| 
 | ||||
|         // replace the inline formatting tags (but not links) without a space
 | ||||
|         content = striptags(content, [linkTag], ''); | ||||
| 
 | ||||
|         // at least the closing link tag can be easily stripped
 | ||||
|         return content.replace(/<\/a>/ig, ""); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export = NoteContentFulltextExp; | ||||
|  | ||||
| @ -25,7 +25,7 @@ class OrderByAndLimitExp extends Expression { | ||||
|     constructor(orderDefinitions: Pick<OrderDefinition, "direction" | "valueExtractor">[], limit?: number) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.orderDefinitions = orderDefinitions as unknown as OrderDefinition[]; | ||||
|         this.orderDefinitions = orderDefinitions as OrderDefinition[]; | ||||
| 
 | ||||
|         for (const od of this.orderDefinitions) { | ||||
|             od.smaller = od.direction === "asc" ? -1 : 1; | ||||
|  | ||||
| @ -51,9 +51,7 @@ class SearchResult { | ||||
|     addScoreForStrings(tokens: string[], str: string, factor: number) { | ||||
|         const chunks = str.toLowerCase().split(" "); | ||||
| 
 | ||||
|         if (!this.score) { | ||||
|             this.score = 0; | ||||
|         } | ||||
|         this.score = 0; | ||||
| 
 | ||||
|         for (const chunk of chunks) { | ||||
|             for (const token of tokens) { | ||||
|  | ||||
| @ -113,7 +113,7 @@ class ValueExtractor { | ||||
|                 i++; | ||||
| 
 | ||||
|                 const attr = cursor.getAttributeCaseInsensitive('relation', cur()); | ||||
|                 cursor = (attr ? attr.targetNote || null : null); | ||||
|                 cursor = attr?.targetNote || null; | ||||
|             } | ||||
|             else if (cur() === 'parents') { | ||||
|                 cursor = cursor.parents[0]; | ||||
|  | ||||
| @ -57,7 +57,7 @@ class TaskContext { | ||||
|                 type: 'taskProgressCount', | ||||
|                 taskId: this.taskId, | ||||
|                 taskType: this.taskType, | ||||
|                 data: this.data || undefined, | ||||
|                 data: this.data, | ||||
|                 progressCount: this.progressCount | ||||
|             }); | ||||
|         } | ||||
| @ -68,7 +68,7 @@ class TaskContext { | ||||
|             type: 'taskError', | ||||
|             taskId: this.taskId, | ||||
|             taskType: this.taskType, | ||||
|             data: this.data || undefined, | ||||
|             data: this.data, | ||||
|             message: message | ||||
|         }); | ||||
|     } | ||||
| @ -78,7 +78,7 @@ class TaskContext { | ||||
|             type: 'taskSucceeded', | ||||
|             taskId: this.taskId, | ||||
|             taskType: this.taskType, | ||||
|             data: this.data || undefined, | ||||
|             data: this.data, | ||||
|             result: result | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @ -3,11 +3,7 @@ import path = require('path'); | ||||
| import windowService = require('./window'); | ||||
| import optionService = require('./options'); | ||||
| 
 | ||||
| const UPDATE_TRAY_EVENTS = [ | ||||
|     'minimize', 'maximize', 'show', 'hide' | ||||
| ] as const; | ||||
| 
 | ||||
| let tray: Tray | null = null; | ||||
| let tray: Tray; | ||||
| // `mainWindow.isVisible` doesn't work with `mainWindow.show` and `mainWindow.hide` - it returns `false` when the window
 | ||||
| // is minimized
 | ||||
| let isVisible = true; | ||||
| @ -42,14 +38,15 @@ const registerVisibilityListener = () => { | ||||
|     // They need to be registered before the tray updater is registered
 | ||||
|     mainWindow.on('show', () => { | ||||
|         isVisible = true; | ||||
|         updateTrayMenu(); | ||||
|     }); | ||||
|     mainWindow.on('hide', () => { | ||||
|         isVisible = false; | ||||
|         updateTrayMenu(); | ||||
|     }); | ||||
| 
 | ||||
|     UPDATE_TRAY_EVENTS.forEach((eventName) => { | ||||
|         mainWindow.on(eventName as any, updateTrayMenu) | ||||
|     }); | ||||
|     mainWindow.on("minimize", updateTrayMenu); | ||||
|     mainWindow.on("maximize", updateTrayMenu); | ||||
| } | ||||
| 
 | ||||
| const updateTrayMenu = () => { | ||||
|  | ||||
| @ -17,7 +17,7 @@ let setupWindow: BrowserWindow | null; | ||||
| async function createExtraWindow(extraWindowHash: string) { | ||||
|     const spellcheckEnabled = optionService.getOptionBool('spellCheckEnabled'); | ||||
| 
 | ||||
|     const {BrowserWindow} = require('electron'); | ||||
|     const { BrowserWindow } = require('electron'); | ||||
| 
 | ||||
|     const win = new BrowserWindow({ | ||||
|         width: 1000, | ||||
| @ -53,7 +53,7 @@ async function createMainWindow(app: App) { | ||||
| 
 | ||||
|     const spellcheckEnabled = optionService.getOptionBool('spellCheckEnabled'); | ||||
| 
 | ||||
|     const {BrowserWindow} = require('electron'); // should not be statically imported
 | ||||
|     const { BrowserWindow } = require('electron'); // should not be statically imported
 | ||||
| 
 | ||||
|     mainWindow = new BrowserWindow({ | ||||
|         x: mainWindowState.x, | ||||
| @ -128,7 +128,7 @@ function getIcon() { | ||||
| } | ||||
| 
 | ||||
| async function createSetupWindow() { | ||||
|     const {BrowserWindow} = require('electron'); // should not be statically imported
 | ||||
|     const { BrowserWindow } = require('electron'); // should not be statically imported
 | ||||
|     setupWindow = new BrowserWindow({ | ||||
|         width: 800, | ||||
|         height: 800, | ||||
| @ -152,7 +152,7 @@ function closeSetupWindow() { | ||||
| } | ||||
| 
 | ||||
| async function registerGlobalShortcuts() { | ||||
|     const {globalShortcut} = require('electron'); | ||||
|     const { globalShortcut } = require('electron'); | ||||
| 
 | ||||
|     await sqlInit.dbReady; | ||||
| 
 | ||||
|  | ||||
| @ -29,11 +29,11 @@ let lastSyncedPush: number | null = null; | ||||
| interface Message { | ||||
|     type: string; | ||||
|     data?: { | ||||
|         lastSyncedPush?: number, | ||||
|         lastSyncedPush?: number | null, | ||||
|         entityChanges?: any[], | ||||
|         safeImport?: boolean | ||||
|     }, | ||||
|     lastSyncedPush?: number, | ||||
|     lastSyncedPush?: number | null, | ||||
|      | ||||
|     progressCount?: number; | ||||
|     taskId?: string; | ||||
| @ -143,7 +143,7 @@ function fillInAdditionalProperties(entityChange: EntityChange) { | ||||
|         if (!entityChange.entity) { | ||||
|             entityChange.entity = sql.getRow(`SELECT * FROM notes WHERE noteId = ?`, [entityChange.entityId]); | ||||
| 
 | ||||
|             if (entityChange.entity && entityChange.entity.isProtected) { | ||||
|             if (entityChange.entity?.isProtected) { | ||||
|                 entityChange.entity.title = protectedSessionService.decryptString(entityChange.entity.title || ""); | ||||
|             } | ||||
|         } | ||||
| @ -158,7 +158,7 @@ function fillInAdditionalProperties(entityChange: EntityChange) { | ||||
| 
 | ||||
|         if (parentNote) { | ||||
|             for (const childBranch of parentNote.getChildBranches()) { | ||||
|                 if (childBranch && childBranch.branchId) { | ||||
|                 if (childBranch?.branchId) { | ||||
|                     entityChange.positions[childBranch.branchId] = childBranch.notePosition; | ||||
|                 } | ||||
|             } | ||||
| @ -223,7 +223,7 @@ function sendPing(client: WebSocket, entityChangeIds = []) { | ||||
|     sendMessage(client, { | ||||
|         type: 'frontend-update', | ||||
|         data: { | ||||
|             lastSyncedPush: lastSyncedPush || undefined, | ||||
|             lastSyncedPush, | ||||
|             entityChanges | ||||
|         } | ||||
|     }); | ||||
| @ -238,19 +238,19 @@ function sendTransactionEntityChangesToAllClients() { | ||||
| } | ||||
| 
 | ||||
| function syncPullInProgress() { | ||||
|     sendMessageToAllClients({ type: 'sync-pull-in-progress', lastSyncedPush: lastSyncedPush || undefined }); | ||||
|     sendMessageToAllClients({ type: 'sync-pull-in-progress', lastSyncedPush }); | ||||
| } | ||||
| 
 | ||||
| function syncPushInProgress() { | ||||
|     sendMessageToAllClients({ type: 'sync-push-in-progress', lastSyncedPush: lastSyncedPush || undefined }); | ||||
|     sendMessageToAllClients({ type: 'sync-push-in-progress', lastSyncedPush }); | ||||
| } | ||||
| 
 | ||||
| function syncFinished() { | ||||
|     sendMessageToAllClients({ type: 'sync-finished', lastSyncedPush: lastSyncedPush || undefined }); | ||||
|     sendMessageToAllClients({ type: 'sync-finished', lastSyncedPush }); | ||||
| } | ||||
| 
 | ||||
| function syncFailed() { | ||||
|     sendMessageToAllClients({ type: 'sync-failed', lastSyncedPush: lastSyncedPush || undefined }); | ||||
|     sendMessageToAllClients({ type: 'sync-failed', lastSyncedPush }); | ||||
| } | ||||
| 
 | ||||
| function reloadFrontend(reason: string) { | ||||
|  | ||||
| @ -105,10 +105,10 @@ function renderText(result, note) { | ||||
| 
 | ||||
|         if (result.content.includes(`<span class="math-tex">`)) { | ||||
|             result.header += ` | ||||
| <script src="../../${assetPath}/node_modules/katex/dist/katex.min.js"></script> | ||||
| <link rel="stylesheet" href="../../${assetPath}/node_modules/katex/dist/katex.min.css"> | ||||
| <script src="../../${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js"></script> | ||||
| <script src="../../${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js"></script> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/katex.min.js"></script> | ||||
| <link rel="stylesheet" href="../${assetPath}/node_modules/katex/dist/katex.min.css"> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js"></script> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js"></script> | ||||
| <script> | ||||
| document.addEventListener("DOMContentLoaded", function() { | ||||
|     renderMathInElement(document.getElementById('content')); | ||||
|  | ||||
							
								
								
									
										40
									
								
								src/www.js
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/www.js
									
									
									
									
									
								
							| @ -45,7 +45,7 @@ function startTrilium() { | ||||
|      * instead of the new one. This is complicated by the fact that it is possible to run multiple instances of Trilium | ||||
|      * if port and data dir are configured separately. This complication is the source of the following weird usage. | ||||
|      * | ||||
|      * The line below makes sure that the "second-instance" (process in window) is fired. Normally it returns a boolean | ||||
|      * The line below makes sure that the "second-instance" (process in window.ts) is fired. Normally it returns a boolean | ||||
|      * indicating whether another instance is running or not, but we ignore that and kill the app only based on the port conflict. | ||||
|      * | ||||
|      * A bit weird is that "second-instance" is triggered also on the valid usecases (different port/data dir) and | ||||
| @ -126,26 +126,26 @@ function startHttpServer() { | ||||
|     } | ||||
| 
 | ||||
|     httpServer.on('error', error => { | ||||
|             if (!listenOnTcp || error.syscall !== 'listen') { | ||||
|                 throw error; | ||||
|             } | ||||
| 
 | ||||
|             // handle specific listen errors with friendly messages
 | ||||
|             switch (error.code) { | ||||
|                 case 'EACCES': | ||||
|                     console.error(`Port ${port} requires elevated privileges. It's recommended to use port above 1024.`); | ||||
|                     process.exit(1); | ||||
|                     break; | ||||
| 
 | ||||
|                 case 'EADDRINUSE': | ||||
|                     console.error(`Port ${port} is already in use. Most likely, another Trilium process is already running. You might try to find it, kill it, and try again.`); | ||||
|                     process.exit(1); | ||||
|                     break; | ||||
| 
 | ||||
|                 default: | ||||
|                     throw error; | ||||
|             } | ||||
|         if (!listenOnTcp || error.syscall !== 'listen') { | ||||
|             throw error; | ||||
|         } | ||||
| 
 | ||||
|         // handle specific listen errors with friendly messages
 | ||||
|         switch (error.code) { | ||||
|             case 'EACCES': | ||||
|                 console.error(`Port ${port} requires elevated privileges. It's recommended to use port above 1024.`); | ||||
|                 process.exit(1); | ||||
|                 break; | ||||
| 
 | ||||
|             case 'EADDRINUSE': | ||||
|                 console.error(`Port ${port} is already in use. Most likely, another Trilium process is already running. You might try to find it, kill it, and try again.`); | ||||
|                 process.exit(1); | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 throw error; | ||||
|         } | ||||
|     } | ||||
|     ) | ||||
| 
 | ||||
|     httpServer.on('listening', () => { | ||||
|  | ||||
| @ -3,11 +3,11 @@ | ||||
|       "moduleResolution": "Node", | ||||
| 	  "declaration": false, | ||||
| 	  "sourceMap": true, | ||||
| 	  "outDir": "./build", | ||||
| 	  "outDir": "./dist", | ||||
| 	  "strict": true, | ||||
| 	  "noImplicitAny": true, | ||||
| 	  "resolveJsonModule": true, | ||||
| 	  "lib": ["ES2021"], | ||||
| 	  "lib": ["ES2022"], | ||||
| 	  "downlevelIteration": true | ||||
| 	}, | ||||
| 	"include": [ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran