mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01: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>/**"
 | 
			
		||||
            ],
 | 
			
		||||
            "env": {
 | 
			
		||||
                "TRILIUM_ENV": "dev"
 | 
			
		||||
                "TRILIUM_ENV": "dev",
 | 
			
		||||
                "TRILIUM_DATA_DIR": "./data"
 | 
			
		||||
            },
 | 
			
		||||
            "outputCapture": "std",
 | 
			
		||||
            "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": {
 | 
			
		||||
      "version": "1.2.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
 | 
			
		||||
      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
 | 
			
		||||
      "version": "1.2.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
 | 
			
		||||
      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/ljharb"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/mkdirp-classic": {
 | 
			
		||||
      "version": "0.5.3",
 | 
			
		||||
@ -1163,9 +1166,9 @@
 | 
			
		||||
      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "minimist": {
 | 
			
		||||
      "version": "1.2.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
 | 
			
		||||
      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
 | 
			
		||||
      "version": "1.2.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
 | 
			
		||||
      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
 | 
			
		||||
    },
 | 
			
		||||
    "mkdirp-classic": {
 | 
			
		||||
      "version": "0.5.3",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								package.json
									
									
									
									
									
								
							@ -2,7 +2,7 @@
 | 
			
		||||
  "name": "trilium",
 | 
			
		||||
  "productName": "Trilium Notes",
 | 
			
		||||
  "description": "Trilium Notes",
 | 
			
		||||
  "version": "0.58.2-beta",
 | 
			
		||||
  "version": "0.58.3-beta",
 | 
			
		||||
  "license": "AGPL-3.0-only",
 | 
			
		||||
  "main": "electron.js",
 | 
			
		||||
  "bin": {
 | 
			
		||||
@ -17,10 +17,10 @@
 | 
			
		||||
    "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-no-dir": "cross-env TRILIUM_ENV=dev electron --inspect=5858 .",
 | 
			
		||||
    "switch-server": "rm -r ./node_modules/better-sqlite3 && npm install",
 | 
			
		||||
    "switch-electron": "rm -r ./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-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",
 | 
			
		||||
    "switch-server": "rm -rf ./node_modules/better-sqlite3 && npm install",
 | 
			
		||||
    "switch-electron": "rm -rf ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild",
 | 
			
		||||
    "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 -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",
 | 
			
		||||
    "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",
 | 
			
		||||
@ -29,6 +29,7 @@
 | 
			
		||||
    "postinstall": "rimraf ./node_modules/canvas"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@braintree/sanitize-url": "^6.0.2",
 | 
			
		||||
    "@electron/remote": "2.0.9",
 | 
			
		||||
    "@excalidraw/excalidraw": "0.13.0",
 | 
			
		||||
    "archiver": "5.3.1",
 | 
			
		||||
 | 
			
		||||
@ -8,5 +8,5 @@
 | 
			
		||||
<h4>Example script</h4>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
alert("Current note is " + api.getActiveContextNote().title);
 | 
			
		||||
api.showMessage("Current note is " + api.getActiveContextNote().title);
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ export default class TreeContextMenu {
 | 
			
		||||
        const isHoisted = note.noteId === appContext.tabManager.getActiveContext().hoistedNoteId;
 | 
			
		||||
        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
 | 
			
		||||
        // it's clear what the user meant to do.
 | 
			
		||||
        const selNodes = this.treeWidget.getSelectedNodes();
 | 
			
		||||
 | 
			
		||||
@ -216,7 +216,7 @@ class Froca {
 | 
			
		||||
    getNotesFromCache(noteIds, silentNotFoundError = false) {
 | 
			
		||||
        return noteIds.map(noteId => {
 | 
			
		||||
            if (!this.notes[noteId] && !silentNotFoundError) {
 | 
			
		||||
                console.trace(`Can't find note "${noteId}"`);
 | 
			
		||||
                console.trace(`Can't find note '${noteId}'`);
 | 
			
		||||
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
@ -235,7 +235,7 @@ class Froca {
 | 
			
		||||
 | 
			
		||||
        return noteIds.map(noteId => {
 | 
			
		||||
            if (!this.notes[noteId] && !silentNotFoundError) {
 | 
			
		||||
                console.trace(`Can't find note "${noteId}"`);
 | 
			
		||||
                console.trace(`Can't find note '${noteId}'`);
 | 
			
		||||
 | 
			
		||||
                return null;
 | 
			
		||||
            } else {
 | 
			
		||||
@ -285,7 +285,7 @@ class Froca {
 | 
			
		||||
    getBranch(branchId, silentNotFoundError = false) {
 | 
			
		||||
        if (!(branchId in this.branches)) {
 | 
			
		||||
            if (!silentNotFoundError) {
 | 
			
		||||
                logError(`Not existing branch ${branchId}`);
 | 
			
		||||
                logError(`Not existing branch '${branchId}'`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
@ -295,13 +295,13 @@ class Froca {
 | 
			
		||||
 | 
			
		||||
    async getBranchId(parentNoteId, childNoteId) {
 | 
			
		||||
        if (childNoteId === 'root') {
 | 
			
		||||
            return 'root';
 | 
			
		||||
            return 'none_root';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const child = await this.getNote(childNoteId);
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
@ -318,9 +318,9 @@ class Froca {
 | 
			
		||||
                .then(row => new FNoteComplement(row))
 | 
			
		||||
                .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 is also a work around for missing invalidation after change
 | 
			
		||||
            // this is also a workaround for missing invalidation after change
 | 
			
		||||
            this.noteComplementPromises[noteId].then(
 | 
			
		||||
                () => setTimeout(() => this.noteComplementPromises[noteId] = null, 1000)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
@ -320,8 +320,6 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
 | 
			
		||||
                && attributeService.isAffecting(attr, this.note));
 | 
			
		||||
 | 
			
		||||
            if (label || relation) {
 | 
			
		||||
                console.log("OOOO");
 | 
			
		||||
 | 
			
		||||
                // probably incorrect event
 | 
			
		||||
                // calling this.refresh() is not enough since the event needs to be propagated to children as well
 | 
			
		||||
                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}`);
 | 
			
		||||
 | 
			
		||||
        if (!resp.success) {
 | 
			
		||||
            alert(resp.message);
 | 
			
		||||
            toastService.showError(resp.message);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ws.waitForMaxKnownEntityChangeId();
 | 
			
		||||
 | 
			
		||||
@ -14,8 +14,8 @@ const BAttribute = require('../../becca/entities/battribute');
 | 
			
		||||
const htmlSanitizer = require('../../services/html_sanitizer');
 | 
			
		||||
const {formatAttrForSearch} = require("../../services/attribute_formatter");
 | 
			
		||||
 | 
			
		||||
function findClippingNote(todayNote, pageUrl) {
 | 
			
		||||
    const notes = todayNote.searchNotesInSubtree(
 | 
			
		||||
function findClippingNote(clipperInboxNote, pageUrl) {
 | 
			
		||||
    const notes = clipperInboxNote.searchNotesInSubtree(
 | 
			
		||||
        formatAttrForSearch({
 | 
			
		||||
            type: 'label',
 | 
			
		||||
            name: "pageUrl",
 | 
			
		||||
@ -47,6 +47,7 @@ function addClipping(req) {
 | 
			
		||||
 | 
			
		||||
    const clipperInbox = getClipperInboxNote();
 | 
			
		||||
 | 
			
		||||
    pageUrl = htmlSanitizer.sanitizeUrl(pageUrl);
 | 
			
		||||
    let clippingNote = findClippingNote(clipperInbox, pageUrl);
 | 
			
		||||
 | 
			
		||||
    if (!clippingNote) {
 | 
			
		||||
@ -57,8 +58,6 @@ function addClipping(req) {
 | 
			
		||||
            type: 'text'
 | 
			
		||||
        }).note;
 | 
			
		||||
 | 
			
		||||
        pageUrl = htmlSanitizer.sanitize(pageUrl);
 | 
			
		||||
 | 
			
		||||
        clippingNote.setLabel('clipType', 'clippings');
 | 
			
		||||
        clippingNote.setLabel('pageUrl', pageUrl);
 | 
			
		||||
        clippingNote.setLabel('iconClass', 'bx bx-globe');
 | 
			
		||||
@ -96,7 +95,7 @@ function createNote(req) {
 | 
			
		||||
    note.setLabel('clipType', clipType);
 | 
			
		||||
 | 
			
		||||
    if (pageUrl) {
 | 
			
		||||
        pageUrl = htmlSanitizer.sanitize(pageUrl);
 | 
			
		||||
        pageUrl = htmlSanitizer.sanitizeUrl(pageUrl);
 | 
			
		||||
 | 
			
		||||
        note.setLabel('pageUrl', pageUrl);
 | 
			
		||||
        note.setLabel('iconClass', 'bx bx-globe');
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ function exportBranch(req, res) {
 | 
			
		||||
    const branch = becca.getBranch(branchId);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
        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 sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl;
 | 
			
		||||
 | 
			
		||||
// intended mainly as protection against XSS via import
 | 
			
		||||
// secondarily it (partly) protects against "CSS takeover"
 | 
			
		||||
@ -50,5 +51,6 @@ function sanitize(dirtyHtml) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    sanitize
 | 
			
		||||
    sanitize,
 | 
			
		||||
    sanitizeUrl
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -48,14 +48,13 @@ class OrderByAndLimitExp extends Expression {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // if both are numbers then parse them for numerical comparison
 | 
			
		||||
                // beware that isNaN will return false for empty string and null
 | 
			
		||||
                if (valA.trim() !== "" && valB.trim() !== "" && !isNaN(valA) && !isNaN(valB)) {
 | 
			
		||||
                if (this.isNumber(valA) && this.isNumber(valB)) {
 | 
			
		||||
                    valA = parseFloat(valA);
 | 
			
		||||
                    valB = parseFloat(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;
 | 
			
		||||
                } else if (!valB || valA < valB) {
 | 
			
		||||
                    return smaller;
 | 
			
		||||
@ -77,6 +76,17 @@ class OrderByAndLimitExp extends Expression {
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Search string is lower cased for case insensitive comparison. But when retrieving properties
 | 
			
		||||
 * we need case sensitive form so we have this translation object.
 | 
			
		||||
 * Search string is lower cased for case-insensitive comparison. But when retrieving properties
 | 
			
		||||
 * we need case-sensitive form, so we have this translation object.
 | 
			
		||||
 */
 | 
			
		||||
const PROP_MAPPING = {
 | 
			
		||||
    "noteid": "noteId",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user