mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +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)) { | ||||
|             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 */ | ||||
|         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); | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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()) | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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'); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -63,7 +63,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { | ||||
|         return { | ||||
|             show: true, | ||||
|             activate: true, | ||||
|             title: "Promoted attributes", | ||||
|             title: "Promoted Attributes", | ||||
|             icon: "bx bx-table" | ||||
|         }; | ||||
|     } | ||||
|   | ||||
| @@ -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' | ||||
|         }; | ||||
|     } | ||||
|   | ||||
| @@ -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"); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
| @@ -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()) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user