mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	Merge branch 'master' into dev
# Conflicts: # package-lock.json # package.json
This commit is contained in:
		
						commit
						ac51d0d569
					
				
							
								
								
									
										3
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @ -9,7 +9,8 @@ | |||||||
|                 "<node_internals>/**" |                 "<node_internals>/**" | ||||||
|             ], |             ], | ||||||
|             "env": { |             "env": { | ||||||
|                 "TRILIUM_ENV": "dev" |                 "TRILIUM_ENV": "dev", | ||||||
|  |                 "TRILIUM_DATA_DIR": "./data" | ||||||
|             }, |             }, | ||||||
|             "outputCapture": "std", |             "outputCapture": "std", | ||||||
|             "program": "${workspaceFolder}/src/www" |             "program": "${workspaceFolder}/src/www" | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								dump-db/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								dump-db/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -387,9 +387,12 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/minimist": { |     "node_modules/minimist": { | ||||||
|       "version": "1.2.5", |       "version": "1.2.7", | ||||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", |       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", | ||||||
|       "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" |       "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/mkdirp-classic": { |     "node_modules/mkdirp-classic": { | ||||||
|       "version": "0.5.3", |       "version": "0.5.3", | ||||||
| @ -1163,9 +1166,9 @@ | |||||||
|       "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" |       "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" | ||||||
|     }, |     }, | ||||||
|     "minimist": { |     "minimist": { | ||||||
|       "version": "1.2.5", |       "version": "1.2.7", | ||||||
|       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", |       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", | ||||||
|       "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" |       "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" | ||||||
|     }, |     }, | ||||||
|     "mkdirp-classic": { |     "mkdirp-classic": { | ||||||
|       "version": "0.5.3", |       "version": "0.5.3", | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								package.json
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "Trilium Notes", |   "productName": "Trilium Notes", | ||||||
|   "description": "Trilium Notes", |   "description": "Trilium Notes", | ||||||
|   "version": "0.58.2-beta", |   "version": "0.58.3-beta", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "electron.js", |   "main": "electron.js", | ||||||
|   "bin": { |   "bin": { | ||||||
| @ -17,10 +17,10 @@ | |||||||
|     "start-server-no-dir": "cross-env TRILIUM_ENV=dev node ./src/www", |     "start-server-no-dir": "cross-env TRILIUM_ENV=dev node ./src/www", | ||||||
|     "start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev electron --inspect=5858 .", |     "start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
|     "start-electron-no-dir": "cross-env TRILIUM_ENV=dev electron --inspect=5858 .", |     "start-electron-no-dir": "cross-env TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
|     "switch-server": "rm -r ./node_modules/better-sqlite3 && npm install", |     "switch-server": "rm -rf ./node_modules/better-sqlite3 && npm install", | ||||||
|     "switch-electron": "rm -r ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild", |     "switch-electron": "rm -rf ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild", | ||||||
|     "build-backend-docs": "rm -r ./docs/backend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/becca/entities/*.js src/services/backend_script_api.js src/services/sql.js", |     "build-backend-docs": "rm -rf ./docs/backend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/becca/entities/*.js src/services/backend_script_api.js src/services/sql.js", | ||||||
|     "build-frontend-docs": "rm -r ./docs/frontend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/right_panel_widget.js", |     "build-frontend-docs": "rm -rf ./docs/frontend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/right_panel_widget.js", | ||||||
|     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", |     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", | ||||||
|     "webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js", |     "webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js", | ||||||
|     "test-jasmine": "jasmine", |     "test-jasmine": "jasmine", | ||||||
| @ -29,6 +29,7 @@ | |||||||
|     "postinstall": "rimraf ./node_modules/canvas" |     "postinstall": "rimraf ./node_modules/canvas" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "@braintree/sanitize-url": "^6.0.2", | ||||||
|     "@electron/remote": "2.0.9", |     "@electron/remote": "2.0.9", | ||||||
|     "@excalidraw/excalidraw": "0.13.0", |     "@excalidraw/excalidraw": "0.13.0", | ||||||
|     "archiver": "5.3.1", |     "archiver": "5.3.1", | ||||||
|  | |||||||
| @ -8,5 +8,5 @@ | |||||||
| <h4>Example script</h4> | <h4>Example script</h4> | ||||||
| 
 | 
 | ||||||
| <pre> | <pre> | ||||||
| alert("Current note is " + api.getActiveContextNote().title); | api.showMessage("Current note is " + api.getActiveContextNote().title); | ||||||
| </pre> | </pre> | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ export default class TreeContextMenu { | |||||||
|         const isHoisted = note.noteId === appContext.tabManager.getActiveContext().hoistedNoteId; |         const isHoisted = note.noteId === appContext.tabManager.getActiveContext().hoistedNoteId; | ||||||
|         const parentNote = isNotRoot ? await froca.getNote(branch.parentNoteId) : null; |         const parentNote = isNotRoot ? await froca.getNote(branch.parentNoteId) : null; | ||||||
| 
 | 
 | ||||||
|         // some actions don't support multi-note so they are disabled when notes are selected
 |         // some actions don't support multi-note, so they are disabled when notes are selected
 | ||||||
|         // the only exception is when the only selected note is the one that was right-clicked, then
 |         // the only exception is when the only selected note is the one that was right-clicked, then
 | ||||||
|         // it's clear what the user meant to do.
 |         // it's clear what the user meant to do.
 | ||||||
|         const selNodes = this.treeWidget.getSelectedNodes(); |         const selNodes = this.treeWidget.getSelectedNodes(); | ||||||
|  | |||||||
| @ -216,7 +216,7 @@ class Froca { | |||||||
|     getNotesFromCache(noteIds, silentNotFoundError = false) { |     getNotesFromCache(noteIds, silentNotFoundError = false) { | ||||||
|         return noteIds.map(noteId => { |         return noteIds.map(noteId => { | ||||||
|             if (!this.notes[noteId] && !silentNotFoundError) { |             if (!this.notes[noteId] && !silentNotFoundError) { | ||||||
|                 console.trace(`Can't find note "${noteId}"`); |                 console.trace(`Can't find note '${noteId}'`); | ||||||
| 
 | 
 | ||||||
|                 return null; |                 return null; | ||||||
|             } |             } | ||||||
| @ -235,7 +235,7 @@ class Froca { | |||||||
| 
 | 
 | ||||||
|         return noteIds.map(noteId => { |         return noteIds.map(noteId => { | ||||||
|             if (!this.notes[noteId] && !silentNotFoundError) { |             if (!this.notes[noteId] && !silentNotFoundError) { | ||||||
|                 console.trace(`Can't find note "${noteId}"`); |                 console.trace(`Can't find note '${noteId}'`); | ||||||
| 
 | 
 | ||||||
|                 return null; |                 return null; | ||||||
|             } else { |             } else { | ||||||
| @ -285,7 +285,7 @@ class Froca { | |||||||
|     getBranch(branchId, silentNotFoundError = false) { |     getBranch(branchId, silentNotFoundError = false) { | ||||||
|         if (!(branchId in this.branches)) { |         if (!(branchId in this.branches)) { | ||||||
|             if (!silentNotFoundError) { |             if (!silentNotFoundError) { | ||||||
|                 logError(`Not existing branch ${branchId}`); |                 logError(`Not existing branch '${branchId}'`); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
| @ -295,13 +295,13 @@ class Froca { | |||||||
| 
 | 
 | ||||||
|     async getBranchId(parentNoteId, childNoteId) { |     async getBranchId(parentNoteId, childNoteId) { | ||||||
|         if (childNoteId === 'root') { |         if (childNoteId === 'root') { | ||||||
|             return 'root'; |             return 'none_root'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const child = await this.getNote(childNoteId); |         const child = await this.getNote(childNoteId); | ||||||
| 
 | 
 | ||||||
|         if (!child) { |         if (!child) { | ||||||
|             logError(`Could not find branchId for parent=${parentNoteId}, child=${childNoteId} since child does not exist`); |             logError(`Could not find branchId for parent '${parentNoteId}', child '${childNoteId}' since child does not exist`); | ||||||
| 
 | 
 | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| @ -318,7 +318,7 @@ class Froca { | |||||||
|                 .then(row => new FNoteComplement(row)) |                 .then(row => new FNoteComplement(row)) | ||||||
|                 .catch(e => console.error(`Cannot get note complement for note '${noteId}'`)); |                 .catch(e => console.error(`Cannot get note complement for note '${noteId}'`)); | ||||||
| 
 | 
 | ||||||
|             // we don't want to keep large payloads forever in memory so we clean that up quite quickly
 |             // we don't want to keep large payloads forever in memory, so we clean that up quite quickly
 | ||||||
|             // this cache is more meant to share the data between different components within one business transaction (e.g. loading of the note into the tab context and all the components)
 |             // this cache is more meant to share the data between different components within one business transaction (e.g. loading of the note into the tab context and all the components)
 | ||||||
|             // this is also a workaround for missing invalidation after change
 |             // this is also a workaround for missing invalidation after change
 | ||||||
|             this.noteComplementPromises[noteId].then( |             this.noteComplementPromises[noteId].then( | ||||||
|  | |||||||
| @ -320,8 +320,6 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { | |||||||
|                 && attributeService.isAffecting(attr, this.note)); |                 && attributeService.isAffecting(attr, this.note)); | ||||||
| 
 | 
 | ||||||
|             if (label || relation) { |             if (label || relation) { | ||||||
|                 console.log("OOOO"); |  | ||||||
| 
 |  | ||||||
|                 // probably incorrect event
 |                 // probably incorrect event
 | ||||||
|                 // calling this.refresh() is not enough since the event needs to be propagated to children as well
 |                 // calling this.refresh() is not enough since the event needs to be propagated to children as well
 | ||||||
|                 this.triggerEvent('noteTypeMimeChanged', {noteId: this.noteId}); |                 this.triggerEvent('noteTypeMimeChanged', {noteId: this.noteId}); | ||||||
|  | |||||||
| @ -1606,7 +1606,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { | |||||||
|         const resp = await server.post(`special-notes/launchers/${node.data.noteId}/${launcherType}`); |         const resp = await server.post(`special-notes/launchers/${node.data.noteId}/${launcherType}`); | ||||||
| 
 | 
 | ||||||
|         if (!resp.success) { |         if (!resp.success) { | ||||||
|             alert(resp.message); |             toastService.showError(resp.message); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         await ws.waitForMaxKnownEntityChangeId(); |         await ws.waitForMaxKnownEntityChangeId(); | ||||||
|  | |||||||
| @ -14,8 +14,8 @@ const BAttribute = require('../../becca/entities/battribute'); | |||||||
| const htmlSanitizer = require('../../services/html_sanitizer'); | const htmlSanitizer = require('../../services/html_sanitizer'); | ||||||
| const {formatAttrForSearch} = require("../../services/attribute_formatter"); | const {formatAttrForSearch} = require("../../services/attribute_formatter"); | ||||||
| 
 | 
 | ||||||
| function findClippingNote(todayNote, pageUrl) { | function findClippingNote(clipperInboxNote, pageUrl) { | ||||||
|     const notes = todayNote.searchNotesInSubtree( |     const notes = clipperInboxNote.searchNotesInSubtree( | ||||||
|         formatAttrForSearch({ |         formatAttrForSearch({ | ||||||
|             type: 'label', |             type: 'label', | ||||||
|             name: "pageUrl", |             name: "pageUrl", | ||||||
| @ -47,6 +47,7 @@ function addClipping(req) { | |||||||
| 
 | 
 | ||||||
|     const clipperInbox = getClipperInboxNote(); |     const clipperInbox = getClipperInboxNote(); | ||||||
| 
 | 
 | ||||||
|  |     pageUrl = htmlSanitizer.sanitizeUrl(pageUrl); | ||||||
|     let clippingNote = findClippingNote(clipperInbox, pageUrl); |     let clippingNote = findClippingNote(clipperInbox, pageUrl); | ||||||
| 
 | 
 | ||||||
|     if (!clippingNote) { |     if (!clippingNote) { | ||||||
| @ -57,8 +58,6 @@ function addClipping(req) { | |||||||
|             type: 'text' |             type: 'text' | ||||||
|         }).note; |         }).note; | ||||||
| 
 | 
 | ||||||
|         pageUrl = htmlSanitizer.sanitize(pageUrl); |  | ||||||
| 
 |  | ||||||
|         clippingNote.setLabel('clipType', 'clippings'); |         clippingNote.setLabel('clipType', 'clippings'); | ||||||
|         clippingNote.setLabel('pageUrl', pageUrl); |         clippingNote.setLabel('pageUrl', pageUrl); | ||||||
|         clippingNote.setLabel('iconClass', 'bx bx-globe'); |         clippingNote.setLabel('iconClass', 'bx bx-globe'); | ||||||
| @ -96,7 +95,7 @@ function createNote(req) { | |||||||
|     note.setLabel('clipType', clipType); |     note.setLabel('clipType', clipType); | ||||||
| 
 | 
 | ||||||
|     if (pageUrl) { |     if (pageUrl) { | ||||||
|         pageUrl = htmlSanitizer.sanitize(pageUrl); |         pageUrl = htmlSanitizer.sanitizeUrl(pageUrl); | ||||||
| 
 | 
 | ||||||
|         note.setLabel('pageUrl', pageUrl); |         note.setLabel('pageUrl', pageUrl); | ||||||
|         note.setLabel('iconClass', 'bx bx-globe'); |         note.setLabel('iconClass', 'bx bx-globe'); | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ function exportBranch(req, res) { | |||||||
|     const branch = becca.getBranch(branchId); |     const branch = becca.getBranch(branchId); | ||||||
| 
 | 
 | ||||||
|     if (!branch) { |     if (!branch) { | ||||||
|         const message = `Cannot export branch ${branchId} since it does not exist.`; |         const message = `Cannot export branch '${branchId}' since it does not exist.`; | ||||||
|         log.error(message); |         log.error(message); | ||||||
| 
 | 
 | ||||||
|         res.setHeader("Content-Type", "text/plain") |         res.setHeader("Content-Type", "text/plain") | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| module.exports = { buildDate:"2022-12-29T00:12:54+01:00", buildRevision: "d36cf47974cd8bc6bd45c1da774a9a55d45f998e" }; | module.exports = { buildDate:"2023-01-04T22:36:31+01:00", buildRevision: "3a5fa2954dea0ff2ecdce9a28b3bb01f039d314d" }; | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| const sanitizeHtml = require('sanitize-html'); | const sanitizeHtml = require('sanitize-html'); | ||||||
|  | const sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl; | ||||||
| 
 | 
 | ||||||
| // intended mainly as protection against XSS via import
 | // intended mainly as protection against XSS via import
 | ||||||
| // secondarily it (partly) protects against "CSS takeover"
 | // secondarily it (partly) protects against "CSS takeover"
 | ||||||
| @ -50,5 +51,6 @@ function sanitize(dirtyHtml) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     sanitize |     sanitize, | ||||||
|  |     sanitizeUrl | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -48,14 +48,13 @@ class OrderByAndLimitExp extends Expression { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // if both are numbers then parse them for numerical comparison
 |                 // if both are numbers then parse them for numerical comparison
 | ||||||
|                 // beware that isNaN will return false for empty string and null
 |                 if (this.isNumber(valA) && this.isNumber(valB)) { | ||||||
|                 if (valA.trim() !== "" && valB.trim() !== "" && !isNaN(valA) && !isNaN(valB)) { |  | ||||||
|                     valA = parseFloat(valA); |                     valA = parseFloat(valA); | ||||||
|                     valB = parseFloat(valB); |                     valB = parseFloat(valB); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (!valA && !valB) { |                 if (!valA && !valB) { | ||||||
|                     // the attribute is not defined in either note so continue to next order definition
 |                     // the attribute value is empty/zero in both notes so continue to the next order definition
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } else if (!valB || valA < valB) { |                 } else if (!valB || valA < valB) { | ||||||
|                     return smaller; |                     return smaller; | ||||||
| @ -77,6 +76,17 @@ class OrderByAndLimitExp extends Expression { | |||||||
| 
 | 
 | ||||||
|         return noteSet; |         return noteSet; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     isNumber(x) { | ||||||
|  |         if (typeof x === 'number') { | ||||||
|  |             return true; | ||||||
|  |         } else if (typeof x === 'string') { | ||||||
|  |             // isNaN will return false for blank string
 | ||||||
|  |             return x.trim() !== "" && !isNaN(x); | ||||||
|  |         } else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = OrderByAndLimitExp; | module.exports = OrderByAndLimitExp; | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Search string is lower cased for case insensitive comparison. But when retrieving properties |  * Search string is lower cased for case-insensitive comparison. But when retrieving properties | ||||||
|  * we need case sensitive form so we have this translation object. |  * we need case-sensitive form, so we have this translation object. | ||||||
|  */ |  */ | ||||||
| const PROP_MAPPING = { | const PROP_MAPPING = { | ||||||
|     "noteid": "noteId", |     "noteid": "noteId", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam