This note's representation is used in note tree and is kept in TreeCache.
@@ -45,7 +45,7 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
@@ -1014,7 +953,7 @@
Source:
@@ -1072,7 +1011,7 @@
Source:
@@ -1220,7 +1159,7 @@
Source:
@@ -1420,7 +1359,7 @@
Source:
@@ -1598,7 +1537,7 @@
Source:
@@ -1704,7 +1643,7 @@
Source:
@@ -1806,7 +1745,7 @@
Source:
@@ -1908,7 +1847,7 @@
Source:
@@ -2010,7 +1949,7 @@
Source:
@@ -2161,7 +2100,7 @@
Source:
@@ -2328,7 +2267,7 @@
Source:
@@ -2495,7 +2434,7 @@
Source:
@@ -2650,7 +2589,7 @@
Source:
@@ -2708,6 +2647,1516 @@
+ getOwnedAttribute(type, name) → {Attribute }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ type
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute type (label, relation, etc.)
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
+
+
+
+
+
+
+ Type
+
+
+
+Attribute
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedAttributes(typeopt , nameopt ) → {Array.<Attribute >}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ type
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ (optional) attribute type to filter
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ (optional) attribute name to filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ all note's attributes, including inherited ones
+
+
+
+
+
+
+ Type
+
+
+
+Array.<Attribute >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedAttributeValue(type, name) → {string}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ type
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute type (label, relation, etc.)
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ attribute value of given type and name or null if no such attribute exists.
+
+
+
+
+
+
+ Type
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedLabel(name) → {Attribute }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ label name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ label if it exists, null otherwise
+
+
+
+
+
+
+ Type
+
+
+
+Attribute
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedLabels(nameopt ) → {Array.<Attribute >}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ label name to filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ all note's labels (attributes with type label), including inherited ones
+
+
+
+
+
+
+ Type
+
+
+
+Array.<Attribute >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedLabelValue(name) → {string}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ label name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ label value if label exists, null otherwise
+
+
+
+
+
+
+ Type
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedRelation(name) → {Attribute }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ relation name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ relation if it exists, null otherwise
+
+
+
+
+
+
+ Type
+
+
+
+Attribute
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedRelations(nameopt ) → {Array.<Attribute >}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+ Attributes
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ relation name to filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ all note's relations (attributes with type relation), including inherited ones
+
+
+
+
+
+
+ Type
+
+
+
+Array.<Attribute >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ getOwnedRelationValue(name) → {string}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ relation name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ relation value if relation exists, null otherwise
+
+
+
+
+
+
+ Type
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
getParentNoteIds() → {Array.<string>}
@@ -2756,7 +4205,7 @@
Source:
@@ -2858,7 +4307,7 @@
Source:
@@ -3009,7 +4458,7 @@
Source:
@@ -3176,7 +4625,7 @@
Source:
@@ -3343,7 +4792,7 @@
Source:
@@ -3498,7 +4947,7 @@
Source:
@@ -3668,7 +5117,7 @@
Source:
@@ -3819,7 +5268,7 @@
Source:
@@ -3877,7 +5326,7 @@
- (async) getTargetRelations() → {Promise.<Array.<Attribute >>}
+ getTargetRelations() → {Array.<Attribute >}
@@ -3929,7 +5378,7 @@
Source:
@@ -3965,7 +5414,7 @@
-Promise.<Array.<Attribute >>
+Array.<Attribute >
@@ -4103,7 +5552,7 @@
Source:
@@ -4209,7 +5658,7 @@
Source:
@@ -4360,7 +5809,7 @@
Source:
@@ -4418,6 +5867,494 @@
+ hasOwnedAttribute(type, name) → {boolean}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ type
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute type (label, relation, etc.)
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ attribute name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if note has an attribute with given type and name (including inherited)
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hasOwnedLabel(name) → {boolean}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ label name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if label exists (excluding inherited)
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hasOwnedRelation(name) → {boolean}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ relation name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if relation exists (excluding inherited)
+
+
+
+
+
+
+ Type
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(async) hasRelation(name) → {Promise.<boolean>}
@@ -4515,7 +6452,7 @@
Source:
@@ -4573,7 +6510,7 @@
- invalidate__attributeCache()
+ invalidateAttributeCache()
@@ -4626,7 +6563,7 @@ Cache is note instance scoped.
Source:
@@ -4710,7 +6647,7 @@ Cache is note instance scoped.
Source:
@@ -4774,7 +6711,7 @@ Cache is note instance scoped.
- Classes
+ Classes
diff --git a/docs/frontend_api/entities_attribute.js.html b/docs/frontend_api/entities_attribute.js.html
index 01956a8e7..5b9095b62 100644
--- a/docs/frontend_api/entities_attribute.js.html
+++ b/docs/frontend_api/entities_attribute.js.html
@@ -29,6 +29,11 @@
class Attribute {
constructor(treeCache, row) {
this.treeCache = treeCache;
+
+ this.update(row);
+ }
+
+ update(row) {
/** @param {string} attributeId */
this.attributeId = row.attributeId;
/** @param {string} noteId */
@@ -43,12 +48,6 @@
this.position = row.position;
/** @param {boolean} isInheritable */
this.isInheritable = row.isInheritable;
- /** @param {boolean} isDeleted */
- this.isDeleted = row.isDeleted;
- /** @param {string} utcDateCreated */
- this.utcDateCreated = row.utcDateCreated;
- /** @param {string} utcDateModified */
- this.utcDateModified = row.utcDateModified;
}
/** @returns {NoteShort} */
@@ -57,7 +56,7 @@
}
get toString() {
- return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
+ return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name}, value=${this.value})`;
}
}
@@ -71,7 +70,7 @@ export default Attribute;
- Classes
+ Classes
diff --git a/docs/frontend_api/entities_branch.js.html b/docs/frontend_api/entities_branch.js.html
index d8208013d..1b5bf3a49 100644
--- a/docs/frontend_api/entities_branch.js.html
+++ b/docs/frontend_api/entities_branch.js.html
@@ -30,6 +30,11 @@
class Branch {
constructor(treeCache, row) {
this.treeCache = treeCache;
+
+ this.update(row);
+ }
+
+ update(row) {
/** @param {string} primary key */
this.branchId = row.branchId;
/** @param {string} */
@@ -49,6 +54,11 @@ class Branch {
return this.treeCache.getNote(this.noteId);
}
+ /** @returns {NoteShort} */
+ async getParentNote() {
+ return this.treeCache.getNote(this.parentNoteId);
+ }
+
/** @returns {boolean} true if it's top level, meaning its parent is root note */
isTopLevel() {
return this.parentNoteId === 'root';
@@ -69,7 +79,7 @@ export default Branch;
- Classes
+ Classes
diff --git a/docs/frontend_api/entities_note_complement.js.html b/docs/frontend_api/entities_note_complement.js.html
new file mode 100644
index 000000000..03e78d1b5
--- /dev/null
+++ b/docs/frontend_api/entities_note_complement.js.html
@@ -0,0 +1,76 @@
+
+
+
+
+ JSDoc: Source: entities/note_complement.js
+
+
+
+
+
+
+
+
+
+
+
+
+
Source: entities/note_complement.js
+
+
+
+
+
+
+
+
+ /**
+ * Complements the NoteShort with the main note content and other extra attributes
+ */
+class NoteComplement {
+ constructor(row) {
+ /** @param {string} */
+ this.noteId = row.noteId;
+
+ /** @param {string} */
+ this.content = row.content;
+
+ /** @param {string} */
+ this.dateCreated = row.dateCreated;
+
+ /** @param {string} */
+ this.dateModified = row.dateModified;
+
+ /** @param {string} */
+ this.utcDateCreated = row.utcDateCreated;
+
+ /** @param {string} */
+ this.utcDateModified = row.utcDateModified;
+ }
+}
+
+export default NoteComplement;
+
+
+
+
+
+
+
+
+
+ Classes
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/frontend_api/entities_note_short.js.html b/docs/frontend_api/entities_note_short.js.html
index ebb24d8b2..16c7fd55d 100644
--- a/docs/frontend_api/entities_note_short.js.html
+++ b/docs/frontend_api/entities_note_short.js.html
@@ -41,10 +41,31 @@ class NoteShort {
/**
* @param {TreeCache} treeCache
* @param {Object.<string, Object>} row
- * @param {Branch[]} branches - all relevant branches, i.e. where this note is either child or parent
*/
- constructor(treeCache, row, branches) {
+ constructor(treeCache, row) {
this.treeCache = treeCache;
+
+ /** @type {string[]} */
+ this.attributes = [];
+
+ /** @type {string[]} */
+ this.targetRelations = [];
+
+ /** @type {string[]} */
+ this.parents = [];
+ /** @type {string[]} */
+ this.children = [];
+
+ /** @type {Object.<string, string>} */
+ this.parentToBranch = {};
+
+ /** @type {Object.<string, string>} */
+ this.childToBranch = {};
+
+ this.update(row);
+ }
+
+ update(row) {
/** @param {string} */
this.noteId = row.noteId;
/** @param {string} */
@@ -59,37 +80,6 @@ class NoteShort {
this.mime = row.mime;
/** @param {boolean} */
this.isDeleted = row.isDeleted;
- /** @param {boolean} */
- this.archived = row.archived;
- /** @param {string} */
- this.cssClass = row.cssClass;
- /** @param {string} */
- this.iconClass = row.iconClass;
-
- /** @type {string[]} */
- this.parents = [];
- /** @type {string[]} */
- this.children = [];
-
- /** @type {Object.<string, string>} */
- this.parentToBranch = {};
-
- /** @type {Object.<string, string>} */
- this.childToBranch = {};
-
- for (const branch of branches) {
- if (this.noteId === branch.noteId) {
- this.parents.push(branch.parentNoteId);
- this.parentToBranch[branch.parentNoteId] = branch.branchId;
- }
- else if (this.noteId === branch.parentNoteId) {
- this.children.push(branch.noteId);
- this.childToBranch[branch.noteId] = branch.branchId;
- }
- else {
- throw new Error(`Unknown branch ${branch.branchId} for note ${this.noteId}`);
- }
- }
}
addParent(parentNoteId, branchId) {
@@ -181,31 +171,76 @@ class NoteShort {
return await this.treeCache.getNotes(this.children);
}
+ /**
+ * @param {string} [type] - (optional) attribute type to filter
+ * @param {string} [name] - (optional) attribute name to filter
+ * @returns {Attribute[]} all note's attributes, including inherited ones
+ */
+ getOwnedAttributes(type, name) {
+ const attrs = this.attributes
+ .map(attributeId => this.treeCache.attributes[attributeId])
+ .filter(attr => !!attr);
+
+ return this.__filterAttrs(attrs, type, name)
+ }
+
/**
* @param {string} [type] - (optional) attribute type to filter
* @param {string} [name] - (optional) attribute name to filter
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
*/
async getAttributes(type, name) {
- if (!this.__attributeCache) {
- this.__attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
- .map(attrRow => new Attribute(this.treeCache, attrRow));
+ const ownedAttributes = this.getOwnedAttributes();
+
+ const attrArrs = [
+ ownedAttributes
+ ];
+
+ for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) {
+ const templateNote = await this.treeCache.getNote(templateAttr.value);
+
+ if (templateNote) {
+ attrArrs.push(await templateNote.getAttributes());
+ }
}
+ if (this.noteId !== 'root') {
+ for (const parentNote of await this.getParentNotes()) {
+ attrArrs.push(await parentNote.getInheritableAttributes());
+ }
+ }
+
+ const attributes = attrArrs.flat();
+
+ return this.__filterAttrs(attributes, type, name);
+ }
+
+ __filterAttrs(attributes, type, name) {
if (type && name) {
- return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
- }
- else if (type) {
- return this.__attributeCache.filter(attr => attr.type === type);
- }
- else if (name) {
- return this.__attributeCache.filter(attr => attr.name === name);
- }
- else {
- return this.__attributeCache.slice();
+ return attributes.filter(attr => attr.type === type && attr.name === name);
+ } else if (type) {
+ return attributes.filter(attr => attr.type === type);
+ } else if (name) {
+ return attributes.filter(attr => attr.name === name);
+ } else {
+ return attributes;
}
}
+ async getInheritableAttributes() {
+ const attrs = await this.getAttributes();
+
+ return attrs.filter(attr => attr.isInheritable);
+ }
+
+ /**
+ * @param {string} [name] - label name to filter
+ * @returns {Attribute[]} all note's labels (attributes with type label), including inherited ones
+ */
+ getOwnedLabels(name) {
+ return this.getOwnedAttributes(LABEL, name);
+ }
+
/**
* @param {string} [name] - label name to filter
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
@@ -222,6 +257,14 @@ class NoteShort {
return await this.getAttributes(LABEL_DEFINITION, name);
}
+ /**
+ * @param {string} [name] - relation name to filter
+ * @returns {Attribute[]} all note's relations (attributes with type relation), including inherited ones
+ */
+ getOwnedRelations(name) {
+ return this.getOwnedAttributes(RELATION, name);
+ }
+
/**
* @param {string} [name] - relation name to filter
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
@@ -247,15 +290,46 @@ class NoteShort {
return !!await this.getAttribute(type, name);
}
+ /**
+ * @param {string} type - attribute type (label, relation, etc.)
+ * @param {string} name - attribute name
+ * @returns {boolean} true if note has an attribute with given type and name (including inherited)
+ */
+ hasOwnedAttribute(type, name) {
+ return !!this.getOwnedAttribute(type, name);
+ }
+
+ /**
+ * @param {string} type - attribute type (label, relation, etc.)
+ * @param {string} name - attribute name
+ * @returns {Attribute} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
+ */
+ getOwnedAttribute(type, name) {
+ const attributes = this.getOwnedAttributes(type, name);
+
+ return attributes.length > 0 ? attributes[0] : 0;
+ }
+
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
*/
async getAttribute(type, name) {
- const attributes = await this.getAttributes();
+ const attributes = await this.getAttributes(type, name);
- return attributes.find(attr => attr.type === type && attr.name === name);
+ return attributes.length > 0 ? attributes[0] : 0;
+ }
+
+ /**
+ * @param {string} type - attribute type (label, relation, etc.)
+ * @param {string} name - attribute name
+ * @returns {string} attribute value of given type and name or null if no such attribute exists.
+ */
+ getOwnedAttributeValue(type, name) {
+ const attr = this.getOwnedAttribute(type, name);
+
+ return attr ? attr.value : null;
}
/**
@@ -269,36 +343,72 @@ class NoteShort {
return attr ? attr.value : null;
}
+ /**
+ * @param {string} name - label name
+ * @returns {boolean} true if label exists (excluding inherited)
+ */
+ hasOwnedLabel(name) { return this.hasOwnedAttribute(LABEL, name); }
+
/**
* @param {string} name - label name
* @returns {Promise<boolean>} true if label exists (including inherited)
*/
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {boolean} true if relation exists (excluding inherited)
+ */
+ hasOwnedRelation(name) { return this.hasOwnedAttribute(RELATION, name); }
+
/**
* @param {string} name - relation name
* @returns {Promise<boolean>} true if relation exists (including inherited)
*/
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
+ /**
+ * @param {string} name - label name
+ * @returns {Attribute} label if it exists, null otherwise
+ */
+ getOwnedLabel(name) { return this.getOwnedAttribute(LABEL, name); }
+
/**
* @param {string} name - label name
* @returns {Promise<Attribute>} label if it exists, null otherwise
*/
async getLabel(name) { return await this.getAttribute(LABEL, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {Attribute} relation if it exists, null otherwise
+ */
+ getOwnedRelation(name) { return this.getOwnedAttribute(RELATION, name); }
+
/**
* @param {string} name - relation name
* @returns {Promise<Attribute>} relation if it exists, null otherwise
*/
async getRelation(name) { return await this.getAttribute(RELATION, name); }
+ /**
+ * @param {string} name - label name
+ * @returns {string} label value if label exists, null otherwise
+ */
+ getOwnedLabelValue(name) { return this.getOwnedAttributeValue(LABEL, name); }
+
/**
* @param {string} name - label name
* @returns {Promise<string>} label value if label exists, null otherwise
*/
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {string} relation value if relation exists, null otherwise
+ */
+ getOwnedRelationValue(name) { return this.getOwnedAttributeValue(RELATION, name); }
+
/**
* @param {string} name - relation name
* @returns {Promise<string>} relation value if relation exists, null otherwise
@@ -334,18 +444,18 @@ class NoteShort {
* Clear note's attributes cache to force fresh reload for next attribute request.
* Cache is note instance scoped.
*/
- invalidate__attributeCache() {
+ invalidateAttributeCache() {
this.__attributeCache = null;
}
/**
* Get relations which target this note
*
- * @returns {Promise<Attribute[]>}
+ * @returns {Attribute[]}
*/
- async getTargetRelations() {
- return (await server.get('notes/' + this.noteId + '/target-relations'))
- .map(attrRow => new Attribute(this.treeCache, attrRow));
+ getTargetRelations() {
+ return this.targetRelations
+ .map(attributeId => this.treeCache.attributes[attributeId]);
}
get toString() {
@@ -355,8 +465,6 @@ class NoteShort {
get dto() {
const dto = Object.assign({}, this);
delete dto.treeCache;
- delete dto.archived;
- delete dto.__attributeCache;
return dto;
}
@@ -372,7 +480,7 @@ export default NoteShort;
- Classes
+ Classes
diff --git a/docs/frontend_api/global.html b/docs/frontend_api/global.html
index 7f4006e31..b4c13d6c8 100644
--- a/docs/frontend_api/global.html
+++ b/docs/frontend_api/global.html
@@ -333,7 +333,7 @@
- Classes
+ Classes
diff --git a/docs/frontend_api/index.html b/docs/frontend_api/index.html
index 310dca343..cb160592e 100644
--- a/docs/frontend_api/index.html
+++ b/docs/frontend_api/index.html
@@ -50,7 +50,7 @@
- Classes
+ Classes
diff --git a/docs/frontend_api/services_frontend_script_api.js.html b/docs/frontend_api/services_frontend_script_api.js.html
index 3b73eabad..f9289fa31 100644
--- a/docs/frontend_api/services_frontend_script_api.js.html
+++ b/docs/frontend_api/services_frontend_script_api.js.html
@@ -32,13 +32,13 @@ import utils from './utils.js';
import toastService from './toast.js';
import linkService from './link.js';
import treeCache from './tree_cache.js';
-import noteDetailService from './note_detail.js';
import noteTooltipService from './note_tooltip.js';
import protectedSessionService from './protected_session.js';
import dateNotesService from './date_notes.js';
import StandardWidget from '../widgets/standard_widget.js';
import ws from "./ws.js";
import hoistedNoteService from "./hoisted_note.js";
+import appContext from "./app_context.js";
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@@ -77,7 +77,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
*/
this.activateNote = async (notePath, noteLoadedListener) => {
await treeService.activateNote(notePath, async () => {
- await treeService.scrollToActiveNote();
+ await appContext.getMainNoteTree().scrollToActiveNoteListener();
if (noteLoadedListener) {
noteLoadedListener();
@@ -94,7 +94,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
this.activateNewNote = async notePath => {
await ws.waitForMaxKnownSyncId();
- await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
+ await treeService.activateNote(notePath, () => appContext.trigger('focusAndSelectTitle'));
};
/**
@@ -172,9 +172,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
currentNoteId: currentNote.noteId,
originEntityName: "notes", // currently there's no other entity on frontend which can trigger event
originEntityId: originEntity ? originEntity.noteId : null
- }, {
- 'trilium-source-id': "script"
- });
+ }, "script");
if (ret.success) {
// wait until all the changes done in the script has been synced to frontend before continuing
@@ -299,22 +297,6 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
*/
this.refreshTree = treeService.reload;
- /**
- * Refresh active tab
- *
- * @method
- * @returns {Promise<void>}
- */
- this.refreshActiveTab = noteDetailService.reload;
-
- /**
- * Refresh current tab
- *
- * @method
- * @returns {Promise<void>}
- */
- this.refreshAllTabs = noteDetailService.reloadAllTabs;
-
/**
* Create note link (jQuery object) for given note.
*
@@ -327,30 +309,30 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
/**
* Adds given text to the editor cursor
*
- * @param {string} text
+ * @param {string} text - this must be clear text, HTML is not supported.
* @method
*/
- this.addTextToActiveTabEditor = linkService.addTextToEditor;
+ this.addTextToActiveTabEditor = text => appContext.trigger('addTextToActiveEditor', {text});
/**
* @method
- * @returns {NoteFull} active note (loaded into right pane)
+ * @returns {NoteShort} active note (loaded into right pane)
*/
- this.getActiveTabNote = noteDetailService.getActiveTabNote;
+ this.getActiveTabNote = appContext.getActiveTabNote;
/**
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
*
* @method
- * @returns {Editor|null} CKEditor instance or null (e.g. if active note is not a text note)
+ * @param callback - method receiving "textEditor" instance
*/
- this.getActiveTabTextEditor = noteDetailService.getActiveEditor;
+ this.getActiveTabTextEditor = callback => appContext.trigger('executeInActiveEditor', {callback});
/**
* @method
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
*/
- this.getActiveTabNotePath = noteDetailService.getActiveTabNotePath;
+ this.getActiveTabNotePath = appContext.getActiveTabNotePath;
/**
* This method checks whether user navigated away from the note from which the scripts has been started.
@@ -365,12 +347,6 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
return tabContext.note && this.originEntity.noteId === tabContext.note.noteId;
};
- /**
- * @method
- * @param {function} func - callback called on note change as user is typing (not necessarily tied to save event)
- */
- this.onNoteChange = noteDetailService.onNoteChange;
-
/**
* @method
* @param {object} $el - jquery object on which to setup the tooltip
@@ -455,7 +431,7 @@ export default FrontendScriptApi;
- Classes
+ Classes
diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js
deleted file mode 100644
index 9ddb3cace..000000000
--- a/src/public/javascripts/services/note_detail.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import appContext from "./app_context.js";
-
-function getActiveEditor() {
- const activeTabContext = appContext.getActiveTabContext();
-
- if (activeTabContext && activeTabContext.note && activeTabContext.note.type === 'text') {
- return activeTabContext.getComponent().getEditor();
- }
- else {
- return null;
- }
-}
-
-export default {
- getActiveEditor
-};
\ No newline at end of file
diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js
index 1c807833c..add1f54f8 100644
--- a/src/public/javascripts/services/tab_context.js
+++ b/src/public/javascripts/services/tab_context.js
@@ -47,6 +47,8 @@ class TabContext extends Component {
this.notePath = notePath;
this.noteId = treeService.getNoteIdFromNotePath(notePath);
+ this.autoBookDisabled = false;
+
//this.cleanup(); // esp. on windows autocomplete is not getting closed automatically
setTimeout(async () => {
diff --git a/src/public/javascripts/widgets/component.js b/src/public/javascripts/widgets/component.js
index d19354767..66db2fb55 100644
--- a/src/public/javascripts/widgets/component.js
+++ b/src/public/javascripts/widgets/component.js
@@ -19,10 +19,18 @@ export default class Component {
let propagateToChildren = true;
+ const start = Date.now();
+
if (typeof fun === 'function') {
propagateToChildren = await fun.call(this, data) !== false;
}
+ const end = Date.now();
+
+ if (end - start > 10) {
+ console.log(`Event ${name} in component ${this.componentId} took ${end-start}ms`);
+ }
+
if (propagateToChildren) {
const promise = this.triggerChildren(name, data, sync);
diff --git a/src/public/javascripts/widgets/note_detail.js b/src/public/javascripts/widgets/note_detail.js
index 37c103439..8caa6a602 100644
--- a/src/public/javascripts/widgets/note_detail.js
+++ b/src/public/javascripts/widgets/note_detail.js
@@ -143,7 +143,7 @@ export default class NoteDetailWidget extends TabAwareWidget {
typeWidget.eventReceived('setTabContext', {tabContext: this.tabContext});
}
- async getWidgetType(disableAutoBook) {
+ async getWidgetType() {
const note = this.tabContext.note;
if (!note) {
@@ -152,7 +152,7 @@ export default class NoteDetailWidget extends TabAwareWidget {
let type = note.type;
- if (type === 'text' && !disableAutoBook
+ if (type === 'text' && !this.tabContext.autoBookDisabled
&& note.hasChildren()
&& utils.isDesktop()) {
@@ -224,4 +224,8 @@ export default class NoteDetailWidget extends TabAwareWidget {
beforeUnloadListener() {
this.spacedUpdate.updateNowIfNecessary();
}
+
+ autoBookDisabledListener() {
+ this.refresh();
+ }
}
\ No newline at end of file
diff --git a/src/public/javascripts/widgets/type_widgets/book.js b/src/public/javascripts/widgets/type_widgets/book.js
index b9d071cbd..619b6e227 100644
--- a/src/public/javascripts/widgets/type_widgets/book.js
+++ b/src/public/javascripts/widgets/type_widgets/book.js
@@ -200,7 +200,9 @@ export default class BookTypeWidget extends TypeWidget {
if (this.isAutoBook()) {
const $addTextLink = $('here ').on('click', () => {
- // FIXME
+ this.tabContext.autoBookDisabled = true;
+
+ this.trigger('autoBookDisabled');
});
this.$content.append($('
')