mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Merge branch 'stable'
# Conflicts: # src/services/build.js
This commit is contained in:
		| @@ -96,7 +96,7 @@ class BAttribute extends AbstractBeccaEntity { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (this.type === 'relation' && !(this.value in this.becca.notes)) { |         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}'.`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ class BNote extends AbstractBeccaEntity { | |||||||
|          * @private */ |          * @private */ | ||||||
|         this.parents = []; |         this.parents = []; | ||||||
|         /** @type {BNote[]} |         /** @type {BNote[]} | ||||||
|          * @private*/ |          * @private */ | ||||||
|         this.children = []; |         this.children = []; | ||||||
|         /** @type {BAttribute[]} |         /** @type {BAttribute[]} | ||||||
|          * @private */ |          * @private */ | ||||||
| @@ -107,11 +107,11 @@ class BNote extends AbstractBeccaEntity { | |||||||
|          * @private */ |          * @private */ | ||||||
|         this.__attributeCache = null; |         this.__attributeCache = null; | ||||||
|         /** @type {BAttribute[]|null} |         /** @type {BAttribute[]|null} | ||||||
|          * @private*/ |          * @private */ | ||||||
|         this.inheritableAttributeCache = null; |         this.inheritableAttributeCache = null; | ||||||
|  |  | ||||||
|         /** @type {BAttribute[]} |         /** @type {BAttribute[]} | ||||||
|          * @private*/ |          * @private */ | ||||||
|         this.targetRelations = []; |         this.targetRelations = []; | ||||||
|  |  | ||||||
|         this.becca.addNote(this.noteId, this); |         this.becca.addNote(this.noteId, this); | ||||||
| @@ -532,6 +532,20 @@ class BNote extends AbstractBeccaEntity { | |||||||
|      */ |      */ | ||||||
|     hasLabel(name, value) { return this.hasAttribute(LABEL, name, value); } |     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} name - label name | ||||||
|      * @param {string} [value] - label value |      * @param {string} [value] - label value | ||||||
|   | |||||||
| @@ -595,6 +595,20 @@ class FNote { | |||||||
|      */ |      */ | ||||||
|     hasLabel(name) { return this.hasAttribute(LABEL, name); } |     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 |      * @param {string} name - relation name | ||||||
|      * @returns {boolean} true if relation exists (excluding inherited) |      * @returns {boolean} true if relation exists (excluding inherited) | ||||||
|   | |||||||
| @@ -128,6 +128,10 @@ export default class DesktopLayout { | |||||||
|                                     ) |                                     ) | ||||||
|                                     .child( |                                     .child( | ||||||
|                                         new RibbonContainer() |                                         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 ScriptExecutorWidget()) | ||||||
|                                             .ribbon(new SearchDefinitionWidget()) |                                             .ribbon(new SearchDefinitionWidget()) | ||||||
|                                             .ribbon(new EditedNotesWidget()) |                                             .ribbon(new EditedNotesWidget()) | ||||||
| @@ -135,7 +139,6 @@ export default class DesktopLayout { | |||||||
|                                             .ribbon(new NotePropertiesWidget()) |                                             .ribbon(new NotePropertiesWidget()) | ||||||
|                                             .ribbon(new FilePropertiesWidget()) |                                             .ribbon(new FilePropertiesWidget()) | ||||||
|                                             .ribbon(new ImagePropertiesWidget()) |                                             .ribbon(new ImagePropertiesWidget()) | ||||||
|                                             .ribbon(new PromotedAttributesWidget()) |  | ||||||
|                                             .ribbon(new BasicPropertiesWidget()) |                                             .ribbon(new BasicPropertiesWidget()) | ||||||
|                                             .ribbon(new OwnedAttributeListWidget()) |                                             .ribbon(new OwnedAttributeListWidget()) | ||||||
|                                             .ribbon(new InheritedAttributesWidget()) |                                             .ribbon(new InheritedAttributesWidget()) | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ async function processEntityChanges(entityChanges) { | |||||||
|             if (ec.entityName === 'notes') { |             if (ec.entityName === 'notes') { | ||||||
|                 processNoteChange(loadResults, ec); |                 processNoteChange(loadResults, ec); | ||||||
|             } else if (ec.entityName === 'branches') { |             } else if (ec.entityName === 'branches') { | ||||||
|                 processBranchChange(loadResults, ec); |                 await processBranchChange(loadResults, ec); | ||||||
|             } else if (ec.entityName === 'attributes') { |             } else if (ec.entityName === 'attributes') { | ||||||
|                 processAttributeChange(loadResults, ec); |                 processAttributeChange(loadResults, ec); | ||||||
|             } else if (ec.entityName === 'note_reordering') { |             } 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) { |     if (ec.isErased && ec.entityId in froca.branches) { | ||||||
|         utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); |         utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`); | ||||||
|         return; |         return; | ||||||
| @@ -139,7 +139,15 @@ function processBranchChange(loadResults, ec) { | |||||||
|     loadResults.addBranch(ec.entityId, ec.componentId); |     loadResults.addBranch(ec.entityId, ec.componentId); | ||||||
|  |  | ||||||
|     const childNote = froca.notes[ec.entity.noteId]; |     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) { |     if (branch) { | ||||||
|         branch.update(ec.entity); |         branch.update(ec.entity); | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | |||||||
|         await ws.waitForMaxKnownEntityChangeId(); |         await ws.waitForMaxKnownEntityChangeId(); | ||||||
|  |  | ||||||
|         await appContext.tabManager.getActiveContext().setNote(notePath); |         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 }); |         await appContext.tabManager.openContextWithNote(notePath, { activate }); | ||||||
|  |  | ||||||
|         if (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 subContexts = appContext.tabManager.getActiveContext().getSubContexts(); | ||||||
|         const {ntxId} = subContexts[subContexts.length - 1]; |         const {ntxId} = subContexts[subContexts.length - 1]; | ||||||
|  |  | ||||||
|         appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath}); |         await appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath}); | ||||||
|  |  | ||||||
|         if (activate) { |         if (activate) { | ||||||
|             appContext.triggerEvent('focusAndSelectTitle'); |             await appContext.triggerEvent('focusAndSelectTitle'); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -285,7 +285,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.$title = this.$widget.find('.attr-detail-title'); |         this.$title = this.$widget.find('.attr-detail-title'); | ||||||
|  |  | ||||||
|         this.$inputName = this.$widget.find('.attr-input-name'); |         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('change', () => this.userEditedAttribute()); | ||||||
|         this.$inputName.on('autocomplete:closed', () => 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.$rowValue = this.$widget.find('.attr-row-value'); | ||||||
|         this.$inputValue = this.$widget.find('.attr-input-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('change', () => this.userEditedAttribute()); | ||||||
|         this.$inputValue.on('autocomplete:closed', () => this.userEditedAttribute()); |         this.$inputValue.on('autocomplete:closed', () => this.userEditedAttribute()); | ||||||
|         this.$inputValue.on('focus', () => { |         this.$inputValue.on('focus', () => { | ||||||
| @@ -328,7 +336,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|  |  | ||||||
|         this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation'); |         this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation'); | ||||||
|         this.$inputInverseRelation = this.$widget.find('.attr-input-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.$rowTargetNote = this.$widget.find('.attr-row-target-note'); | ||||||
|         this.$inputTargetNote = this.$widget.find('.attr-input-target-note'); |         this.$inputTargetNote = this.$widget.find('.attr-input-target-note'); | ||||||
|   | |||||||
| @@ -63,7 +63,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { | |||||||
|         return { |         return { | ||||||
|             show: true, |             show: true, | ||||||
|             activate: true, |             activate: true, | ||||||
|             title: "Promoted attributes", |             title: "Promoted Attributes", | ||||||
|             icon: "bx bx-table" |             icon: "bx bx-table" | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -180,7 +180,7 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { | |||||||
|         return { |         return { | ||||||
|             show: this.isEnabled(), |             show: this.isEnabled(), | ||||||
|             activate: true, |             activate: true, | ||||||
|             title: 'Search parameters', |             title: 'Search Parameters', | ||||||
|             icon: 'bx bx-search' |             icon: 'bx bx-search' | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -39,7 +39,14 @@ export default class SharedInfoWidget extends NoteContextAwareWidget { | |||||||
|             this.$sharedText.text("This note is shared publicly on"); |             this.$sharedText.text("This note is shared publicly on"); | ||||||
|         } |         } | ||||||
|         else { |         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"); |             this.$sharedText.text("This note is shared locally on"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ const ValidationError = require("../errors/validation_error"); | |||||||
| const noteTypesService = require("./note_types"); | const noteTypesService = require("./note_types"); | ||||||
|  |  | ||||||
| function getNewNotePosition(parentNote) { | function getNewNotePosition(parentNote) { | ||||||
|     if (parentNote.hasLabel('newNotesOnTop')) { |     if (parentNote.isLabelTruthy('newNotesOnTop')) { | ||||||
|         const minNotePos = parentNote.getChildBranches() |         const minNotePos = parentNote.getChildBranches() | ||||||
|             .reduce((min, note) => Math.min(min, note.notePosition), 0); |             .reduce((min, note) => Math.min(min, note.notePosition), 0); | ||||||
|  |  | ||||||
| @@ -841,7 +841,7 @@ function duplicateSubtree(origNoteId, newParentNoteId) { | |||||||
|         throw new Error('Duplicating root is not possible'); |         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]; |     const origNote = becca.notes[origNoteId]; | ||||||
|     // might be null if orig note is not in the target newParentNoteId |     // 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.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()) { |         for (const childBranch of origNote.getChildBranches()) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user