| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 10:11:19 +02:00
										 |  |  | const protectedSessionService = require('../../protected_session'); | 
					
						
							| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Note { | 
					
						
							| 
									
										
										
										
											2020-05-17 10:11:19 +02:00
										 |  |  |     constructor(noteCache, row) { | 
					
						
							|  |  |  |         /** @param {NoteCache} */ | 
					
						
							|  |  |  |         this.noteCache = noteCache; | 
					
						
							| 
									
										
										
										
											2020-09-03 21:37:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.update(row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @param {Branch[]} */ | 
					
						
							|  |  |  |         this.parentBranches = []; | 
					
						
							|  |  |  |         /** @param {Note[]} */ | 
					
						
							|  |  |  |         this.parents = []; | 
					
						
							|  |  |  |         /** @param {Note[]} */ | 
					
						
							|  |  |  |         this.children = []; | 
					
						
							|  |  |  |         /** @param {Attribute[]} */ | 
					
						
							|  |  |  |         this.ownedAttributes = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @param {Attribute[]|null} */ | 
					
						
							|  |  |  |         this.attributeCache = null; | 
					
						
							|  |  |  |         /** @param {Attribute[]|null} */ | 
					
						
							|  |  |  |         this.inheritableAttributeCache = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @param {Attribute[]} */ | 
					
						
							|  |  |  |         this.targetRelations = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.noteCache.notes[this.noteId] = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @param {Note[]|null} */ | 
					
						
							|  |  |  |         this.ancestorCache = null; | 
					
						
							| 
									
										
										
										
											2021-01-22 22:20:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // following attributes are filled during searching from database
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @param {int} size of the content in bytes */ | 
					
						
							|  |  |  |         this.contentSize = null; | 
					
						
							|  |  |  |         /** @param {int} size of the content and note revision contents in bytes */ | 
					
						
							|  |  |  |         this.noteSize = null; | 
					
						
							|  |  |  |         /** @param {int} number of note revisions for this note */ | 
					
						
							|  |  |  |         this.revisionCount = null; | 
					
						
							| 
									
										
										
										
											2020-09-03 21:37:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update(row) { | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.noteId = row.noteId; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.title = row.title; | 
					
						
							| 
									
										
										
										
											2020-05-23 20:52:55 +02:00
										 |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.type = row.type; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.mime = row.mime; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.dateCreated = row.dateCreated; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.dateModified = row.dateModified; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.utcDateCreated = row.utcDateCreated; | 
					
						
							|  |  |  |         /** @param {string} */ | 
					
						
							|  |  |  |         this.utcDateModified = row.utcDateModified; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |         /** @param {boolean} */ | 
					
						
							|  |  |  |         this.isProtected = !!row.isProtected; | 
					
						
							|  |  |  |         /** @param {boolean} */ | 
					
						
							|  |  |  |         this.isDecrypted = !row.isProtected || !!row.isContentAvailable; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 21:37:06 +02:00
										 |  |  |         this.decrypt(); | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @param {string|null} */ | 
					
						
							|  |  |  |         this.flatTextCache = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {Attribute[]} */ | 
					
						
							|  |  |  |     get attributes() { | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |         return this.__getAttributes([]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __getAttributes(path) { | 
					
						
							|  |  |  |         if (path.includes(this.noteId)) { | 
					
						
							|  |  |  |             return []; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |         if (!this.attributeCache) { | 
					
						
							|  |  |  |             const parentAttributes = this.ownedAttributes.slice(); | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |             const newPath = [...path, this.noteId]; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (this.noteId !== 'root') { | 
					
						
							|  |  |  |                 for (const parentNote of this.parents) { | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |                     parentAttributes.push(...parentNote.__getInheritableAttributes(newPath)); | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const templateAttributes = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const ownedAttr of parentAttributes) { // parentAttributes so we process also inherited templates
 | 
					
						
							|  |  |  |                 if (ownedAttr.type === 'relation' && ownedAttr.name === 'template') { | 
					
						
							| 
									
										
										
										
											2020-05-17 10:11:19 +02:00
										 |  |  |                     const templateNote = this.noteCache.notes[ownedAttr.value]; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if (templateNote) { | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |                         templateAttributes.push(...templateNote.__getAttributes(newPath)); | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-30 22:34:18 +02:00
										 |  |  |             this.attributeCache = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const addedAttributeIds = new Set(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const attr of parentAttributes.concat(templateAttributes)) { | 
					
						
							|  |  |  |                 if (!addedAttributeIds.has(attr.attributeId)) { | 
					
						
							|  |  |  |                     addedAttributeIds.add(attr.attributeId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     this.attributeCache.push(attr); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |             this.inheritableAttributeCache = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const attr of this.attributeCache) { | 
					
						
							|  |  |  |                 if (attr.isInheritable) { | 
					
						
							|  |  |  |                     this.inheritableAttributeCache.push(attr); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.attributeCache; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {Attribute[]} */ | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |     __getInheritableAttributes(path) { | 
					
						
							|  |  |  |         if (path.includes(this.noteId)) { | 
					
						
							|  |  |  |             return []; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |         if (!this.inheritableAttributeCache) { | 
					
						
							| 
									
										
										
										
											2020-06-04 23:58:31 +02:00
										 |  |  |             this.__getAttributes(path); // will refresh also this.inheritableAttributeCache
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.inheritableAttributeCache; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hasAttribute(type, name) { | 
					
						
							| 
									
										
										
										
											2020-08-20 00:15:08 +02:00
										 |  |  |         return !!this.attributes.find(attr => attr.type === type && attr.name === name); | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:09:00 +01:00
										 |  |  |     getAttributeCaseInsensitive(type, name, value) { | 
					
						
							|  |  |  |         name = name.toLowerCase(); | 
					
						
							|  |  |  |         value = value ? value.toLowerCase() : null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.attributes.find( | 
					
						
							|  |  |  |             attr => attr.type === type | 
					
						
							|  |  |  |             && attr.name.toLowerCase() === name | 
					
						
							|  |  |  |             && (!value || attr.value.toLowerCase() === value)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 21:00:59 +01:00
										 |  |  |     hasLabel(name) { | 
					
						
							|  |  |  |         return this.hasAttribute('label', name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hasRelation(name) { | 
					
						
							|  |  |  |         return this.hasAttribute('relation', name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-25 00:25:47 +02:00
										 |  |  |     getLabelValue(name) { | 
					
						
							|  |  |  |         const label = this.attributes.find(attr => attr.type === 'label' && attr.name === name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return label ? label.value : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getRelationTarget(name) { | 
					
						
							|  |  |  |         const relation = this.attributes.find(attr => attr.type === 'relation' && attr.name === name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return relation ? relation.targetNote : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     get isArchived() { | 
					
						
							|  |  |  |         return this.hasAttribute('label', 'archived'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get hasInheritableOwnedArchivedLabel() { | 
					
						
							|  |  |  |         return !!this.ownedAttributes.find(attr => attr.type === 'label' && attr.name === 'archived' && attr.isInheritable); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-24 22:38:26 +01:00
										 |  |  |     // will sort the parents so that non-search & non-archived are first and archived at the end
 | 
					
						
							|  |  |  |     // this is done so that non-search & non-archived paths are always explored as first when looking for note path
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     resortParents() { | 
					
						
							| 
									
										
										
										
											2021-02-24 22:38:26 +01:00
										 |  |  |         this.parentBranches.sort((a, b) => | 
					
						
							|  |  |  |             a.branchId.startsWith('virt-') | 
					
						
							|  |  |  |             || a.parentNote.hasInheritableOwnedArchivedLabel ? 1 : -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.parents = this.parentBranches.map(branch => branch.parentNote); | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2020-09-07 00:05:01 +02:00
										 |  |  |      * This is used for: | 
					
						
							|  |  |  |      * - fast searching | 
					
						
							|  |  |  |      * - note similarity evaluation | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return {string} - returns flattened textual representation of note, prefixes and attributes | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     get flatText() { | 
					
						
							|  |  |  |         if (!this.flatTextCache) { | 
					
						
							| 
									
										
										
										
											2020-09-10 21:01:46 +02:00
										 |  |  |             this.flatTextCache = this.noteId + ' ' + this.type + ' ' + this.mime + ' '; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             for (const branch of this.parentBranches) { | 
					
						
							|  |  |  |                 if (branch.prefix) { | 
					
						
							| 
									
										
										
										
											2020-09-07 00:05:01 +02:00
										 |  |  |                     this.flatTextCache += branch.prefix + ' '; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-06 23:55:17 +02:00
										 |  |  |             this.flatTextCache += this.title + ' '; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             for (const attr of this.attributes) { | 
					
						
							|  |  |  |                 // it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
 | 
					
						
							| 
									
										
										
										
											2020-09-07 00:05:01 +02:00
										 |  |  |                 this.flatTextCache += (attr.type === 'label' ? '#' : '~') + attr.name; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if (attr.value) { | 
					
						
							|  |  |  |                     this.flatTextCache += '=' + attr.value; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-09-07 00:05:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 this.flatTextCache += ' '; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.flatTextCache = this.flatTextCache.toLowerCase(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.flatTextCache; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invalidateThisCache() { | 
					
						
							|  |  |  |         this.flatTextCache = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.attributeCache = null; | 
					
						
							|  |  |  |         this.inheritableAttributeCache = null; | 
					
						
							| 
									
										
										
										
											2020-05-23 23:44:55 +02:00
										 |  |  |         this.ancestorCache = null; | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invalidateSubtreeCaches() { | 
					
						
							|  |  |  |         this.invalidateThisCache(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const childNote of this.children) { | 
					
						
							|  |  |  |             childNote.invalidateSubtreeCaches(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const targetRelation of this.targetRelations) { | 
					
						
							|  |  |  |             if (targetRelation.name === 'template') { | 
					
						
							|  |  |  |                 const note = targetRelation.note; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (note) { | 
					
						
							|  |  |  |                     note.invalidateSubtreeCaches(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invalidateSubtreeFlatText() { | 
					
						
							|  |  |  |         this.flatTextCache = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const childNote of this.children) { | 
					
						
							|  |  |  |             childNote.invalidateSubtreeFlatText(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const targetRelation of this.targetRelations) { | 
					
						
							|  |  |  |             if (targetRelation.name === 'template') { | 
					
						
							|  |  |  |                 const note = targetRelation.note; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (note) { | 
					
						
							|  |  |  |                     note.invalidateSubtreeFlatText(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get isTemplate() { | 
					
						
							|  |  |  |         return !!this.targetRelations.find(rel => rel.name === 'template'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {Note[]} */ | 
					
						
							|  |  |  |     get subtreeNotesIncludingTemplated() { | 
					
						
							|  |  |  |         const arr = [[this]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const childNote of this.children) { | 
					
						
							|  |  |  |             arr.push(childNote.subtreeNotesIncludingTemplated); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const targetRelation of this.targetRelations) { | 
					
						
							|  |  |  |             if (targetRelation.name === 'template') { | 
					
						
							|  |  |  |                 const note = targetRelation.note; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (note) { | 
					
						
							|  |  |  |                     arr.push(note.subtreeNotesIncludingTemplated); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return arr.flat(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {Note[]} */ | 
					
						
							|  |  |  |     get subtreeNotes() { | 
					
						
							|  |  |  |         const arr = [[this]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const childNote of this.children) { | 
					
						
							|  |  |  |             arr.push(childNote.subtreeNotes); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return arr.flat(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 21:00:59 +01:00
										 |  |  |     /** @return {String[]} */ | 
					
						
							|  |  |  |     get subtreeNoteIds() { | 
					
						
							|  |  |  |         return this.subtreeNotes.map(note => note.noteId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 20:52:55 +02:00
										 |  |  |     get parentCount() { | 
					
						
							|  |  |  |         return this.parents.length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get childrenCount() { | 
					
						
							|  |  |  |         return this.children.length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get labelCount() { | 
					
						
							|  |  |  |         return this.attributes.filter(attr => attr.type === 'label').length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 20:42:34 +01:00
										 |  |  |     get ownedLabelCount() { | 
					
						
							|  |  |  |         return this.ownedAttributes.filter(attr => attr.type === 'label').length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 20:52:55 +02:00
										 |  |  |     get relationCount() { | 
					
						
							| 
									
										
										
										
											2021-02-19 20:42:34 +01:00
										 |  |  |         return this.attributes.filter(attr => attr.type === 'relation' && !attr.isAutoLink()).length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get relationCountIncludingLinks() { | 
					
						
							| 
									
										
										
										
											2020-05-23 20:52:55 +02:00
										 |  |  |         return this.attributes.filter(attr => attr.type === 'relation').length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 20:42:34 +01:00
										 |  |  |     get ownedRelationCount() { | 
					
						
							|  |  |  |         return this.ownedAttributes.filter(attr => attr.type === 'relation' && !attr.isAutoLink()).length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get ownedRelationCountIncludingLinks() { | 
					
						
							|  |  |  |         return this.ownedAttributes.filter(attr => attr.type === 'relation').length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get targetRelationCount() { | 
					
						
							|  |  |  |         return this.targetRelations.filter(attr => !attr.isAutoLink()).length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get targetRelationCountIncludingLinks() { | 
					
						
							|  |  |  |         return this.targetRelations.length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 20:52:55 +02:00
										 |  |  |     get attributeCount() { | 
					
						
							|  |  |  |         return this.attributes.length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 20:42:34 +01:00
										 |  |  |     get ownedAttributeCount() { | 
					
						
							|  |  |  |         return this.attributes.length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 23:44:55 +02:00
										 |  |  |     get ancestors() { | 
					
						
							|  |  |  |         if (!this.ancestorCache) { | 
					
						
							|  |  |  |             const noteIds = new Set(); | 
					
						
							|  |  |  |             this.ancestorCache = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const parent of this.parents) { | 
					
						
							|  |  |  |                 if (!noteIds.has(parent.noteId)) { | 
					
						
							|  |  |  |                     this.ancestorCache.push(parent); | 
					
						
							|  |  |  |                     noteIds.add(parent.noteId); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for (const ancestorNote of parent.ancestors) { | 
					
						
							|  |  |  |                     if (!noteIds.has(ancestorNote.noteId)) { | 
					
						
							|  |  |  |                         this.ancestorCache.push(ancestorNote); | 
					
						
							|  |  |  |                         noteIds.add(ancestorNote.noteId); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.ancestorCache; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  |     /** @return {Note[]} - returns only notes which are templated, does not include their subtrees | 
					
						
							|  |  |  |      *                     in effect returns notes which are influenced by note's non-inheritable attributes */ | 
					
						
							|  |  |  |     get templatedNotes() { | 
					
						
							|  |  |  |         const arr = [this]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const targetRelation of this.targetRelations) { | 
					
						
							|  |  |  |             if (targetRelation.name === 'template') { | 
					
						
							|  |  |  |                 const note = targetRelation.note; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (note) { | 
					
						
							|  |  |  |                     arr.push(note); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return arr; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 23:25:18 +01:00
										 |  |  |     getDistanceToAncestor(ancestorNoteId) { | 
					
						
							|  |  |  |         if (this.noteId === ancestorNoteId) { | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-15 20:31:12 +01:00
										 |  |  |         let minDistance = 999999; | 
					
						
							| 
									
										
										
										
											2021-01-26 23:25:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (const parent of this.parents) { | 
					
						
							|  |  |  |             minDistance = Math.min(minDistance, parent.getDistanceToAncestor(ancestorNoteId) + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return minDistance; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  |     decrypt() { | 
					
						
							|  |  |  |         if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) { | 
					
						
							| 
									
										
										
										
											2020-09-25 20:55:45 +02:00
										 |  |  |             this.title = protectedSessionService.decryptString(this.title); | 
					
						
							| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             this.isDecrypted = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-17 14:34:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // for logging etc
 | 
					
						
							|  |  |  |     get pojo() { | 
					
						
							|  |  |  |         const pojo = {...this}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         delete pojo.noteCache; | 
					
						
							|  |  |  |         delete pojo.ancestorCache; | 
					
						
							|  |  |  |         delete pojo.attributeCache; | 
					
						
							|  |  |  |         delete pojo.flatTextCache; | 
					
						
							| 
									
										
										
										
											2020-09-18 21:47:59 +02:00
										 |  |  |         delete pojo.children; | 
					
						
							|  |  |  |         delete pojo.parents; | 
					
						
							|  |  |  |         delete pojo.parentBranches; | 
					
						
							| 
									
										
										
										
											2020-09-17 14:34:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return pojo; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-16 23:12:29 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-17 09:48:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | module.exports = Note; |