diff --git a/src/public/app/entities/attribute.js b/src/public/app/entities/attribute.js index 6fc76274d..3d5a63616 100644 --- a/src/public/app/entities/attribute.js +++ b/src/public/app/entities/attribute.js @@ -23,8 +23,8 @@ class Attribute { } /** @returns {NoteShort} */ - async getNote() { - return await this.treeCache.getNote(this.noteId); + getNote() { + return this.treeCache.notes[this.noteId]; } get jsonValue() { @@ -39,6 +39,34 @@ class Attribute { get toString() { return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name}, value=${this.value})`; } + + /** + * @return {boolean} - returns true if this attribute has the potential to influence the note in the argument. + * That can happen in multiple ways: + * 1. attribute is owned by the note + * 2. attribute is owned by the template of the note + * 3. attribute is owned by some note's ancestor and is inheritable + */ + isAffecting(affectedNote) { + const attrNote = this.getNote(); + const owningNotes = [affectedNote, ...affectedNote.getTemplateNotes()]; + + for (const owningNote of owningNotes) { + if (owningNote.noteId === attrNote.noteId) { + return true; + } + } + + if (this.isInheritable) { + for (const owningNote of owningNotes) { + if (owningNote.hasAncestor(attrNote)) { + return true; + } + } + } + + return false; + } } -export default Attribute; \ No newline at end of file +export default Attribute; diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index f68547eb7..a553acd98 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -437,6 +437,35 @@ class NoteShort { return targets; } + /** + * @returns {NoteShort[]} + */ + getTemplateNotes() { + const relations = this.getRelations('template'); + + return relations.map(rel => this.treeCache.notes[rel.value]); + } + + hasAncestor(ancestorNote) { + if (this.noteId === ancestorNote.noteId) { + return true; + } + + for (const templateNote of this.getTemplateNotes()) { + if (templateNote.hasAncestor(ancestorNote)) { + return true; + } + } + + for (const parentNote of this.getParentNotes()) { + if (parentNote.hasAncestor(ancestorNote)) {console.log(parentNote); + return true; + } + } + + return false; + } + /** * Clear note's attributes cache to force fresh reload for next attribute request. * Cache is note instance scoped. diff --git a/src/public/app/services/tree_cache.js b/src/public/app/services/tree_cache.js index 4b18b7fa8..0aaebac3e 100644 --- a/src/public/app/services/tree_cache.js +++ b/src/public/app/services/tree_cache.js @@ -54,6 +54,10 @@ class TreeCache { if (attr.type === 'relation' && attr.name === 'template' && !(attr.value in existingNotes) && !noteIds.has(attr.value)) { missingNoteIds.push(attr.value); } + + if (!(attr.noteId in existingNotes) && !noteIds.has(attr.noteId)) { + missingNoteIds.push(attr.noteId); + } } if (missingNoteIds.length > 0) { @@ -283,4 +287,4 @@ class TreeCache { const treeCache = new TreeCache(); -export default treeCache; \ No newline at end of file +export default treeCache; diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index 1fca3ae91..d979368fd 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -270,13 +270,30 @@ export default class NoteDetailWidget extends TabAwareWidget { } async entitiesReloadedEvent({loadResults}) { - // FIXME: we should test what happens when the loaded note is deleted - if (loadResults.isNoteContentReloaded(this.noteId, this.componentId) || (loadResults.isNoteReloaded(this.noteId, this.componentId) && (this.type !== await this.getWidgetType() || this.mime !== this.note.mime))) { this.handleEvent('noteTypeMimeChanged', {noteId: this.noteId}); } + else { + const attrs = loadResults.getAttributes(); + + const label = attrs.find(attr => + attr.type === 'label' + && ['readOnly', 'autoReadOnlyDisabled', 'cssClass', 'bookZoomLevel'].includes(attr.name) + && attr.isAffecting(this.note)); + + const relation = attrs.find(attr => + attr.type === 'relation' + && ['template', 'runOnNoteView', 'renderNote'].includes(attr.name) + && attr.isAffecting(this.note)); + + if (label || relation) { + // probably incorrect event + // calling this.refresh() is not enough since the event needs to be propagated to children as well + this.handleEvent('noteTypeMimeChanged', {noteId: this.noteId}); + } + } } beforeUnloadEvent() { diff --git a/src/public/app/widgets/promoted_attributes.js b/src/public/app/widgets/promoted_attributes.js index f505df915..fb2c2c0d8 100644 --- a/src/public/app/widgets/promoted_attributes.js +++ b/src/public/app/widgets/promoted_attributes.js @@ -268,13 +268,8 @@ export default class PromotedAttributesWidget extends TabAwareWidget { $attr.prop("attribute-id", result.attributeId); } - entitiesReloadedEvent({loadResults}) {console.log("loadResults", loadResults); - // relation/label definitions are very often inherited by tree or template, - // it's difficult to detect inheritance so we will - if (loadResults.getAttributes(this.componentId).find(attr => - attr.noteId === this.noteId - || ['label-definition', 'relation-definition'].includes(attr.type))) { - + entitiesReloadedEvent({loadResults}) { + if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) { this.refresh(); } }