From e70cca4736cb127613218ca51574d7a7370a0583 Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 29 Mar 2023 23:07:47 +0200 Subject: [PATCH 1/9] fix trailing slash in shared note in IE, closes #3782 --- src/public/app/widgets/shared_info.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/public/app/widgets/shared_info.js b/src/public/app/widgets/shared_info.js index 8029ba24b..ebdfbb108 100644 --- a/src/public/app/widgets/shared_info.js +++ b/src/public/app/widgets/shared_info.js @@ -39,7 +39,14 @@ export default class SharedInfoWidget extends NoteContextAwareWidget { this.$sharedText.text("This note is shared publicly on"); } else { - link = `${location.protocol}//${location.host}${location.pathname}share/${shareId}`; + let host = location.host; + if (host.endsWith('/')) { + // seems like IE has trailing slash + // https://github.com/zadam/trilium/issues/3782 + host = host.substr(0, host.length - 1); + } + + link = `${location.protocol}//${host}${location.pathname}share/${shareId}`; this.$sharedText.text("This note is shared locally on"); } From 72b1cc4d8926c7f63f77344287cba0f3a3f9c055 Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 29 Mar 2023 23:16:45 +0200 Subject: [PATCH 2/9] fixed loading of parent to froca when e.g. sharing (cloning into not yet loaded _share parent) --- src/public/app/services/froca_updater.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/public/app/services/froca_updater.js b/src/public/app/services/froca_updater.js index 64eb653c0..070d6c2a2 100644 --- a/src/public/app/services/froca_updater.js +++ b/src/public/app/services/froca_updater.js @@ -14,7 +14,7 @@ async function processEntityChanges(entityChanges) { if (ec.entityName === 'notes') { processNoteChange(loadResults, ec); } else if (ec.entityName === 'branches') { - processBranchChange(loadResults, ec); + await processBranchChange(loadResults, ec); } else if (ec.entityName === 'attributes') { processAttributeChange(loadResults, ec); } else if (ec.entityName === 'note_reordering') { @@ -105,7 +105,7 @@ function processNoteChange(loadResults, ec) { } } -function processBranchChange(loadResults, ec) { +async function processBranchChange(loadResults, ec) { if (ec.isErased && ec.entityId in froca.branches) { utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); return; @@ -139,7 +139,15 @@ function processBranchChange(loadResults, ec) { loadResults.addBranch(ec.entityId, ec.componentId); const childNote = froca.notes[ec.entity.noteId]; - const parentNote = froca.notes[ec.entity.parentNoteId]; + let parentNote = froca.notes[ec.entity.parentNoteId]; + + if (childNote && !parentNote) { + // a branch cannot exist without the parent + // a note loaded into froca has to also contain all its ancestors + // this problem happened e.g. in sharing where _share was hidden and thus not loaded + // sharing meant cloning into _share, which crashed because _share was not loaded + parentNote = await froca.getNote(ec.entity.parentNoteId); + } if (branch) { branch.update(ec.entity); From d100b0dc07ad9c0caf4ce950c8b9c0358f30cf93 Mon Sep 17 00:00:00 2001 From: zadam Date: Mon, 3 Apr 2023 21:08:32 +0200 Subject: [PATCH 3/9] allow #newNotesOnTop=false to negate previous setting, closes #3796 --- package-lock.json | 4 ++-- src/becca/entities/bnote.js | 14 ++++++++++++++ src/public/app/entities/fnote.js | 14 ++++++++++++++ src/services/notes.js | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8117a4a56..f6fd5eaef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "trilium", - "version": "0.59.2", + "version": "0.59.3", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.59.2", + "version": "0.59.3", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 07ebd612f..960b35234 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -532,6 +532,20 @@ class BNote extends AbstractBeccaEntity { */ hasLabel(name, value) { return this.hasAttribute(LABEL, name, value); } + /** + * @param {string} name - label name + * @returns {boolean} true if label exists (including inherited) and does not have "false" value. + */ + isLabelTruthy(name) { + const label = this.getLabel(name); + + if (!label) { + return false; + } + + return label && label.value !== 'false'; + } + /** * @param {string} name - label name * @param {string} [value] - label value diff --git a/src/public/app/entities/fnote.js b/src/public/app/entities/fnote.js index 70594d647..1066a9341 100644 --- a/src/public/app/entities/fnote.js +++ b/src/public/app/entities/fnote.js @@ -595,6 +595,20 @@ class FNote { */ hasLabel(name) { return this.hasAttribute(LABEL, name); } + /** + * @param {string} name - label name + * @returns {boolean} true if label exists (including inherited) and does not have "false" value. + */ + isLabelTruthy(name) { + const label = this.getLabel(name); + + if (!label) { + return false; + } + + return label && label.value !== 'false'; + } + /** * @param {string} name - relation name * @returns {boolean} true if relation exists (excluding inherited) diff --git a/src/services/notes.js b/src/services/notes.js index 6dfa34cb0..3da2f56fc 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -23,7 +23,7 @@ const ValidationError = require("../errors/validation_error"); const noteTypesService = require("./note_types"); function getNewNotePosition(parentNote) { - if (parentNote.hasLabel('newNotesOnTop')) { + if (parentNote.isLabelTruthy('newNotesOnTop')) { const minNotePos = parentNote.getChildBranches() .reduce((min, note) => Math.min(min, note.notePosition), 0); From c44be53673391e7289b7209df0669e1986a20802 Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 5 Apr 2023 22:07:08 +0200 Subject: [PATCH 4/9] awaiting on triggered events/commands in the frontend API, fixes #3799 --- src/public/app/services/frontend_script_api.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/public/app/services/frontend_script_api.js b/src/public/app/services/frontend_script_api.js index c985d8997..98d4e8460 100644 --- a/src/public/app/services/frontend_script_api.js +++ b/src/public/app/services/frontend_script_api.js @@ -65,7 +65,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain await ws.waitForMaxKnownEntityChangeId(); await appContext.tabManager.getActiveContext().setNote(notePath); - appContext.triggerEvent('focusAndSelectTitle'); + await appContext.triggerEvent('focusAndSelectTitle'); }; /** @@ -82,7 +82,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain await appContext.tabManager.openContextWithNote(notePath, { activate }); if (activate) { - appContext.triggerEvent('focusAndSelectTitle'); + await appContext.triggerEvent('focusAndSelectTitle'); } }; @@ -100,10 +100,10 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); const {ntxId} = subContexts[subContexts.length - 1]; - appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath}); + await appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath}); if (activate) { - appContext.triggerEvent('focusAndSelectTitle'); + await appContext.triggerEvent('focusAndSelectTitle'); } }; From 8229a97ffbef2fdb4cda5ca13091e46a7d8a1a78 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 6 Apr 2023 21:20:19 +0200 Subject: [PATCH 5/9] capitalizing ribbon widget names #3806 --- src/public/app/widgets/ribbon_widgets/promoted_attributes.js | 2 +- src/public/app/widgets/ribbon_widgets/search_definition.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/ribbon_widgets/promoted_attributes.js b/src/public/app/widgets/ribbon_widgets/promoted_attributes.js index ac5286795..586780a20 100644 --- a/src/public/app/widgets/ribbon_widgets/promoted_attributes.js +++ b/src/public/app/widgets/ribbon_widgets/promoted_attributes.js @@ -60,7 +60,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { return { show: true, activate: true, - title: "Promoted attributes", + title: "Promoted Attributes", icon: "bx bx-table" }; } diff --git a/src/public/app/widgets/ribbon_widgets/search_definition.js b/src/public/app/widgets/ribbon_widgets/search_definition.js index 4ca8e17d9..baa6dfdd9 100644 --- a/src/public/app/widgets/ribbon_widgets/search_definition.js +++ b/src/public/app/widgets/ribbon_widgets/search_definition.js @@ -180,7 +180,7 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { return { show: this.isEnabled(), activate: true, - title: 'Search parameters', + title: 'Search Parameters', icon: 'bx bx-search' }; } From 32e9fd291d0907aaafd56cde6d61111d477142b7 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 6 Apr 2023 21:25:13 +0200 Subject: [PATCH 6/9] promotes attributes tab should be always visible when available, fixes #3806 --- src/public/app/layouts/desktop_layout.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index 3040a4ac3..17dcc99a7 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -128,6 +128,10 @@ export default class DesktopLayout { ) .child( new RibbonContainer() + // order of the widgets matter. Some of these want to "activate" themselves + // when visible, when this happens to multiple of them, the first one "wins". + // promoted attributes should always win. + .ribbon(new PromotedAttributesWidget()) .ribbon(new ScriptExecutorWidget()) .ribbon(new SearchDefinitionWidget()) .ribbon(new EditedNotesWidget()) @@ -135,7 +139,6 @@ export default class DesktopLayout { .ribbon(new NotePropertiesWidget()) .ribbon(new FilePropertiesWidget()) .ribbon(new ImagePropertiesWidget()) - .ribbon(new PromotedAttributesWidget()) .ribbon(new BasicPropertiesWidget()) .ribbon(new OwnedAttributeListWidget()) .ribbon(new InheritedAttributesWidget()) From 24866a3e2532a497dc6215052264946e8be447c1 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 6 Apr 2023 23:05:03 +0200 Subject: [PATCH 7/9] fix click events propagating from context menu being closed, fixes #3805 (cherry picked from commit e871edc8f347e6add552abe67d94a68793558802) --- src/public/app/menus/context_menu.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/public/app/menus/context_menu.js b/src/public/app/menus/context_menu.js index ba42cc345..627510ca7 100644 --- a/src/public/app/menus/context_menu.js +++ b/src/public/app/menus/context_menu.js @@ -142,7 +142,9 @@ class ContextMenu { // "contextmenu" event also triggers "click" event which depending on the timing can close just opened context menu // we might filter out right clicks, but then it's better if even right clicks close the context menu if (Date.now() - this.dateContextMenuOpenedMs > 300) { - this.$widget.hide(); + // seems like if we hide the menu immediately, some clicks can get propagated to the underlying component + // see https://github.com/zadam/trilium/pull/3805 for details + setTimeout(() => this.$widget.hide(), 100); } } } From 293573a0cd759f43966f892c178b76245f7d3456 Mon Sep 17 00:00:00 2001 From: zadam Date: Fri, 7 Apr 2023 21:45:27 +0200 Subject: [PATCH 8/9] don't update attribute detail while composing CJK characters, fixes #3812 --- .../attribute_widgets/attribute_detail.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index 488f3709b..80efc31ba 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -285,7 +285,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { this.$title = this.$widget.find('.attr-detail-title'); this.$inputName = this.$widget.find('.attr-input-name'); - this.$inputName.on('keyup', () => this.userEditedAttribute()); + this.$inputName.on('input', ev => { + if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812 + this.userEditedAttribute(); + } + }); this.$inputName.on('change', () => this.userEditedAttribute()); this.$inputName.on('autocomplete:closed', () => this.userEditedAttribute()); @@ -299,7 +303,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { this.$rowValue = this.$widget.find('.attr-row-value'); this.$inputValue = this.$widget.find('.attr-input-value'); - this.$inputValue.on('keyup', () => this.userEditedAttribute()); + this.$inputValue.on('input', ev => { + if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812 + this.userEditedAttribute(); + } + }); this.$inputValue.on('change', () => this.userEditedAttribute()); this.$inputValue.on('autocomplete:closed', () => this.userEditedAttribute()); this.$inputValue.on('focus', () => { @@ -328,7 +336,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation'); this.$inputInverseRelation = this.$widget.find('.attr-input-inverse-relation'); - this.$inputInverseRelation.on('keyup', () => this.userEditedAttribute()); + this.$inputInverseRelation.on('input', ev => { + if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812 + this.userEditedAttribute(); + } + }); this.$rowTargetNote = this.$widget.find('.attr-row-target-note'); this.$inputTargetNote = this.$widget.find('.attr-input-target-note'); From 839b172b92629f295b3761af2b3e28835113cadc Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 9 Apr 2023 22:45:31 +0200 Subject: [PATCH 9/9] fix duplicating subtree with internal links, closes #3813 --- src/becca/entities/battribute.js | 2 +- src/becca/entities/bnote.js | 6 +++--- src/services/notes.js | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/becca/entities/battribute.js b/src/becca/entities/battribute.js index ca14a90c0..49b9fa258 100644 --- a/src/becca/entities/battribute.js +++ b/src/becca/entities/battribute.js @@ -96,7 +96,7 @@ class BAttribute extends AbstractBeccaEntity { } if (this.type === 'relation' && !(this.value in this.becca.notes)) { - throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it target not existing note '${this.value}'.`); + throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it targets not existing note '${this.value}'.`); } } diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 960b35234..2e9febadb 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -97,7 +97,7 @@ class BNote extends AbstractBeccaEntity { * @private */ this.parents = []; /** @type {BNote[]} - * @private*/ + * @private */ this.children = []; /** @type {BAttribute[]} * @private */ @@ -107,11 +107,11 @@ class BNote extends AbstractBeccaEntity { * @private */ this.__attributeCache = null; /** @type {BAttribute[]|null} - * @private*/ + * @private */ this.inheritableAttributeCache = null; /** @type {BAttribute[]} - * @private*/ + * @private */ this.targetRelations = []; this.becca.addNote(this.noteId, this); diff --git a/src/services/notes.js b/src/services/notes.js index 3da2f56fc..d526372d2 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -841,7 +841,7 @@ function duplicateSubtree(origNoteId, newParentNoteId) { throw new Error('Duplicating root is not possible'); } - log.info(`Duplicating ${origNoteId} subtree into ${newParentNoteId}`); + log.info(`Duplicating '${origNoteId}' subtree into '${newParentNoteId}'`); const origNote = becca.notes[origNoteId]; // might be null if orig note is not in the target newParentNoteId @@ -919,7 +919,8 @@ function duplicateSubtreeInner(origNote, origBranch, newParentNoteId, noteIdMapp attr.value = noteIdMapping[attr.value]; } - attr.save(); + // the relation targets may not be created yet, the mapping is pre-generated + attr.save({skipValidation: true}); } for (const childBranch of origNote.getChildBranches()) {