mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
simplification of tree cache
This commit is contained in:
parent
22d48b0586
commit
ed9ecf2a57
@ -4,8 +4,8 @@ import NoteShort from './note_short.js';
|
||||
* Represents full note, specifically including note's content.
|
||||
*/
|
||||
class NoteFull extends NoteShort {
|
||||
constructor(treeCache, row) {
|
||||
super(treeCache, row);
|
||||
constructor(treeCache, row, noteShort) {
|
||||
super(treeCache, row, []);
|
||||
|
||||
/** @param {string} */
|
||||
this.content = row.content;
|
||||
@ -21,6 +21,12 @@ class NoteFull extends NoteShort {
|
||||
|
||||
/** @param {string} */
|
||||
this.utcDateModified = row.utcDateModified;
|
||||
|
||||
/* ugly */
|
||||
this.parents = noteShort.parents;
|
||||
this.parentToBranch = noteShort.parentToBranch;
|
||||
this.children = noteShort.children;
|
||||
this.childToBranch = noteShort.childToBranch;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import server from '../services/server.js';
|
||||
import Attribute from './attribute.js';
|
||||
import branches from "../services/branches.js";
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
@ -13,7 +14,12 @@ const RELATION_DEFINITION = 'relation-definition';
|
||||
* This note's representation is used in note tree and is kept in TreeCache.
|
||||
*/
|
||||
class NoteShort {
|
||||
constructor(treeCache, row) {
|
||||
/**
|
||||
* @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) {
|
||||
this.treeCache = treeCache;
|
||||
/** @param {string} */
|
||||
this.noteId = row.noteId;
|
||||
@ -29,6 +35,55 @@ class NoteShort {
|
||||
this.archived = row.archived;
|
||||
/** @param {string} */
|
||||
this.cssClass = row.cssClass;
|
||||
|
||||
/** @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) {
|
||||
if (!this.parents.includes(parentNoteId)) {
|
||||
this.parents.push(parentNoteId);
|
||||
}
|
||||
|
||||
this.parentToBranch[parentNoteId] = branchId;
|
||||
}
|
||||
|
||||
addChild(childNoteId, branchId) {
|
||||
if (!this.children.includes(childNoteId)) {
|
||||
this.children.push(childNoteId);
|
||||
}
|
||||
|
||||
this.childToBranch[childNoteId] = branchId;
|
||||
|
||||
const branchIdPos = {};
|
||||
|
||||
for (const branchId of Object.values(this.childToBranch)) {
|
||||
branchIdPos[branchId] = this.treeCache.branches[branchId].notePosition;
|
||||
}
|
||||
|
||||
this.children.sort((a, b) => branchIdPos[this.childToBranch[a]] < branchIdPos[this.childToBranch[b]] ? -1 : 1);
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@ -58,48 +113,41 @@ class NoteShort {
|
||||
|
||||
/** @returns {Promise<Branch[]>} */
|
||||
async getBranches() {
|
||||
const branchIds = this.treeCache.parents[this.noteId].map(
|
||||
parentNoteId => this.treeCache.getBranchIdByChildParent(this.noteId, parentNoteId));
|
||||
const branchIds = Object.values(this.parentToBranch);
|
||||
|
||||
return this.treeCache.getBranches(branchIds);
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
hasChildren() {
|
||||
return this.treeCache.children[this.noteId]
|
||||
&& this.treeCache.children[this.noteId].length > 0;
|
||||
return this.children.length > 0;
|
||||
}
|
||||
|
||||
/** @returns {Promise<Branch[]>} */
|
||||
async getChildBranches() {
|
||||
if (!this.treeCache.children[this.noteId]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const branchIds = this.treeCache.children[this.noteId].map(
|
||||
childNoteId => this.treeCache.getBranchIdByChildParent(childNoteId, this.noteId));
|
||||
const branchIds = Object.values(this.childToBranch);
|
||||
|
||||
return await this.treeCache.getBranches(branchIds);
|
||||
}
|
||||
|
||||
/** @returns {string[]} */
|
||||
getParentNoteIds() {
|
||||
return this.treeCache.parents[this.noteId] || [];
|
||||
return this.parents;
|
||||
}
|
||||
|
||||
/** @returns {Promise<NoteShort[]>} */
|
||||
async getParentNotes() {
|
||||
return await this.treeCache.getNotes(this.getParentNoteIds());
|
||||
return await this.treeCache.getNotes(this.parents);
|
||||
}
|
||||
|
||||
/** @returns {string[]} */
|
||||
getChildNoteIds() {
|
||||
return this.treeCache.children[this.noteId] || [];
|
||||
return this.children;
|
||||
}
|
||||
|
||||
/** @returns {Promise<NoteShort[]>} */
|
||||
async getChildNotes() {
|
||||
return await this.treeCache.getNotes(this.getChildNoteIds());
|
||||
return await this.treeCache.getNotes(this.children);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,7 +214,7 @@ async function changeNode(func, node, beforeNoteId = null, afterNoteId = null) {
|
||||
|
||||
node.data.parentNoteId = thisNewParentNode.data.noteId;
|
||||
|
||||
await treeCache.moveNote(childNoteId, thisOldParentNode.data.noteId, thisNewParentNode.data.noteId, beforeNoteId, afterNoteId);
|
||||
await treeCache.reloadNotes([childNoteId]);
|
||||
|
||||
await treeService.checkFolderStatus(thisOldParentNode);
|
||||
await treeService.checkFolderStatus(thisNewParentNode);
|
||||
|
@ -12,9 +12,7 @@ async function cloneNoteTo(childNoteId, parentNoteId, prefix) {
|
||||
return;
|
||||
}
|
||||
|
||||
treeCache.addBranchRelationship(resp.branchId, childNoteId, parentNoteId);
|
||||
|
||||
await treeService.reloadNotes([parentNoteId]);
|
||||
await treeService.reloadNotes([childNoteId, parentNoteId]);
|
||||
}
|
||||
|
||||
// beware that first arg is noteId and second is branchId!
|
||||
@ -28,9 +26,7 @@ async function cloneNoteAfter(noteId, afterBranchId) {
|
||||
|
||||
const afterBranch = await treeCache.getBranch(afterBranchId);
|
||||
|
||||
treeCache.addBranchRelationship(resp.branchId, noteId, afterBranch.parentNoteId);
|
||||
|
||||
await treeService.reloadNotes([afterBranch.parentNoteId]);
|
||||
await treeService.reloadNotes([noteId, afterBranch.parentNoteId]);
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@ -10,7 +10,7 @@ async function getTodayNote() {
|
||||
async function getDateNote(date) {
|
||||
const note = await server.get('date-notes/date/' + date);
|
||||
|
||||
await treeCache.reloadParents(note.noteId);
|
||||
await treeCache.reloadNotes([note.noteId]);
|
||||
|
||||
return await treeCache.getNote(note.noteId);
|
||||
}
|
||||
@ -19,7 +19,7 @@ async function getDateNote(date) {
|
||||
async function getMonthNote(month) {
|
||||
const note = await server.get('date-notes/month/' + month);
|
||||
|
||||
await treeCache.reloadParents(note.noteId);
|
||||
await treeCache.reloadNotes([note.noteId]);
|
||||
|
||||
return await treeCache.getNote(note.noteId);
|
||||
}
|
||||
@ -28,7 +28,7 @@ async function getMonthNote(month) {
|
||||
async function getYearNote(year) {
|
||||
const note = await server.get('date-notes/year/' + year);
|
||||
|
||||
await treeCache.reloadParents(note.noteId);
|
||||
await treeCache.reloadNotes([note.noteId]);
|
||||
|
||||
return await treeCache.getNote(note.noteId);
|
||||
}
|
||||
|
@ -215,13 +215,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
* @param {string} noteId
|
||||
* @method
|
||||
*/
|
||||
this.reloadNotesAndTheirChildren = async noteId => await treeCache.reloadNotesAndTheirChildren(noteId);
|
||||
|
||||
/**
|
||||
* @param {string} noteId
|
||||
* @method
|
||||
*/
|
||||
this.reloadParents = async noteId => await treeCache.reloadParents(noteId);
|
||||
this.reloadNotes = async noteId => await treeCache.reloadNotes(noteId);
|
||||
|
||||
/**
|
||||
* Instance name identifies particular Trilium instance. It can be useful for scripts
|
||||
|
@ -250,7 +250,9 @@ async function loadNoteDetail(origNotePath, options = {}) {
|
||||
async function loadNote(noteId) {
|
||||
const row = await server.get('notes/' + noteId);
|
||||
|
||||
return new NoteFull(treeCache, row);
|
||||
const noteShort = await treeCache.getNote(noteId);
|
||||
|
||||
return new NoteFull(treeCache, row, noteShort);
|
||||
}
|
||||
|
||||
async function filterTabs(noteId) {
|
||||
|
@ -670,10 +670,8 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
|
||||
|
||||
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusAndSelectTitle);
|
||||
|
||||
const noteEntity = new NoteShort(treeCache, note);
|
||||
const branchEntity = new Branch(treeCache, branch);
|
||||
|
||||
treeCache.add(noteEntity, branchEntity);
|
||||
const noteEntity = await treeCache.getNote(note.noteId);
|
||||
const branchEntity = await treeCache.getBranch(branch.branchId);
|
||||
|
||||
let newNode = {
|
||||
title: newNoteName,
|
||||
@ -836,7 +834,7 @@ async function reloadNotes(noteIds) {
|
||||
|
||||
console.debug("Reloading notes", noteIds);
|
||||
|
||||
await treeCache.reloadNotesAndTheirChildren(noteIds);
|
||||
await treeCache.reloadNotes(noteIds);
|
||||
|
||||
const activeNotePath = noteDetailService.getActiveTabNotePath();
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import utils from "./utils.js";
|
||||
import Branch from "../entities/branch.js";
|
||||
import NoteShort from "../entities/note_short.js";
|
||||
import toastService from "./toast.js";
|
||||
import ws from "./ws.js";
|
||||
import server from "./server.js";
|
||||
|
||||
@ -14,14 +13,6 @@ class TreeCache {
|
||||
}
|
||||
|
||||
init() {
|
||||
/** @type {Object.<string, string>} */
|
||||
this.parents = {};
|
||||
/** @type {Object.<string, string>} */
|
||||
this.children = {};
|
||||
|
||||
/** @type {Object.<string, string>} */
|
||||
this.childParentToBranch = {};
|
||||
|
||||
/** @type {Object.<string, NoteShort>} */
|
||||
this.notes = {};
|
||||
|
||||
@ -36,58 +27,88 @@ class TreeCache {
|
||||
}
|
||||
|
||||
addResp(noteRows, branchRows) {
|
||||
for (const noteRow of noteRows) {
|
||||
const note = new NoteShort(this, noteRow);
|
||||
|
||||
this.notes[note.noteId] = note;
|
||||
}
|
||||
const branchesByNotes = {};
|
||||
|
||||
for (const branchRow of branchRows) {
|
||||
const branch = new Branch(this, branchRow);
|
||||
|
||||
this.addBranch(branch);
|
||||
|
||||
branchesByNotes[branch.noteId] = branchesByNotes[branch.noteId] || [];
|
||||
branchesByNotes[branch.noteId].push(branch);
|
||||
|
||||
branchesByNotes[branch.parentNoteId] = branchesByNotes[branch.parentNoteId] || [];
|
||||
branchesByNotes[branch.parentNoteId].push(branch);
|
||||
}
|
||||
|
||||
for (const noteRow of noteRows) {
|
||||
const {noteId} = noteRow;
|
||||
|
||||
const oldNote = this.notes[noteId];
|
||||
|
||||
if (oldNote) {
|
||||
for (const childNoteId of oldNote.children) {
|
||||
const childNote = this.notes[childNoteId];
|
||||
|
||||
if (childNote) {
|
||||
childNote.parents = childNote.parents.filter(p => p !== noteId);
|
||||
|
||||
const branchId = childNote.parentToBranch[noteId];
|
||||
|
||||
if (branchId in this.branches) {
|
||||
delete this.branches[branchId];
|
||||
}
|
||||
|
||||
delete childNote.parentToBranch[noteId];
|
||||
}
|
||||
}
|
||||
|
||||
for (const parentNoteId of oldNote.parents) {
|
||||
const parentNote = this.notes[parentNoteId];
|
||||
|
||||
if (parentNote) {
|
||||
parentNote.children = parentNote.children.filter(p => p !== noteId);
|
||||
|
||||
const branchId = parentNote.childToBranch[noteId];
|
||||
|
||||
if (branchId in this.branches) {
|
||||
delete this.branches[branchId];
|
||||
}
|
||||
|
||||
delete parentNote.childToBranch[noteId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const note = new NoteShort(this, noteRow, branchesByNotes[noteId]);
|
||||
|
||||
this.notes[note.noteId] = note;
|
||||
|
||||
for (const childNoteId of note.children) {
|
||||
const childNote = this.notes[childNoteId];
|
||||
|
||||
if (childNote) {
|
||||
childNote.addParent(noteId, note.childToBranch[childNoteId]);
|
||||
}
|
||||
}
|
||||
|
||||
for (const parentNoteId of note.parents) {
|
||||
const parentNote = this.notes[parentNoteId];
|
||||
|
||||
if (parentNote) {
|
||||
parentNote.addChild(noteId, note.parentToBranch[parentNoteId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload notes and their children.
|
||||
*/
|
||||
async reloadNotesAndTheirChildren(noteIds) {
|
||||
async reloadNotes(noteIds) {
|
||||
// first load the data before clearing the cache
|
||||
const resp = await server.post('tree/load', { noteIds });
|
||||
|
||||
for (const noteId of noteIds) {
|
||||
for (const childNoteId of this.children[noteId] || []) {
|
||||
this.parents[childNoteId] = this.parents[childNoteId].filter(p => p !== noteId);
|
||||
|
||||
const branchId = this.getBranchIdByChildParent(childNoteId, noteId);
|
||||
|
||||
delete this.branches[branchId];
|
||||
delete this.childParentToBranch[childNoteId + '-' + noteId];
|
||||
}
|
||||
|
||||
this.children[noteId] = [];
|
||||
|
||||
delete this.notes[noteId];
|
||||
}
|
||||
|
||||
this.addResp(resp.notes, resp.branches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads parents of given noteId - useful when new note is created to make sure note is loaded
|
||||
* in a correct order.
|
||||
*/
|
||||
async reloadParents(noteId) {
|
||||
// to be able to find parents we need first to make sure it is actually loaded
|
||||
await this.getNote(noteId);
|
||||
|
||||
await this.reloadNotesAndTheirChildren(this.parents[noteId] || []);
|
||||
|
||||
// this is done to load the new parents for the noteId
|
||||
await this.reloadNotesAndTheirChildren([noteId]);
|
||||
}
|
||||
|
||||
/** @return {Promise<NoteShort[]>} */
|
||||
async getNotes(noteIds, silentNotFoundError = false) {
|
||||
const missingNoteIds = noteIds.filter(noteId => this.notes[noteId] === undefined);
|
||||
@ -128,34 +149,6 @@ class TreeCache {
|
||||
|
||||
addBranch(branch) {
|
||||
this.branches[branch.branchId] = branch;
|
||||
|
||||
this.addBranchRelationship(branch.branchId, branch.noteId, branch.parentNoteId);
|
||||
}
|
||||
|
||||
addBranchRelationship(branchId, childNoteId, parentNoteId) {
|
||||
if (parentNoteId === 'none') { // applies only to root element
|
||||
return;
|
||||
}
|
||||
|
||||
this.childParentToBranch[childNoteId + '-' + parentNoteId] = branchId;
|
||||
|
||||
this.parents[childNoteId] = this.parents[childNoteId] || [];
|
||||
|
||||
if (!this.parents[childNoteId].includes(parentNoteId)) {
|
||||
this.parents[childNoteId].push(parentNoteId);
|
||||
}
|
||||
|
||||
this.children[parentNoteId] = this.children[parentNoteId] || [];
|
||||
|
||||
if (!this.children[parentNoteId].includes(childNoteId)) {
|
||||
this.children[parentNoteId].push(childNoteId);
|
||||
}
|
||||
}
|
||||
|
||||
add(note, branch) {
|
||||
this.notes[note.noteId] = note;
|
||||
|
||||
this.addBranch(branch);
|
||||
}
|
||||
|
||||
async getBranches(branchIds) {
|
||||
@ -181,60 +174,6 @@ class TreeCache {
|
||||
async getBranch(branchId) {
|
||||
return (await this.getBranches([branchId]))[0];
|
||||
}
|
||||
|
||||
/** @return Branch */
|
||||
async getBranchByChildParent(childNoteId, parentNoteId) {
|
||||
const branchId = this.getBranchIdByChildParent(childNoteId, parentNoteId);
|
||||
|
||||
return await this.getBranch(branchId);
|
||||
}
|
||||
|
||||
getBranchIdByChildParent(childNoteId, parentNoteId) {
|
||||
const key = childNoteId + '-' + parentNoteId;
|
||||
const branchId = this.childParentToBranch[key];
|
||||
|
||||
if (!branchId) {
|
||||
toastService.throwError("Cannot find branch for child-parent=" + key);
|
||||
}
|
||||
|
||||
return branchId;
|
||||
}
|
||||
|
||||
/* Move note from one parent to another. */
|
||||
async moveNote(childNoteId, oldParentNoteId, newParentNoteId, beforeNoteId, afterNoteId) {
|
||||
utils.assertArguments(childNoteId, oldParentNoteId, newParentNoteId);
|
||||
|
||||
if (oldParentNoteId === newParentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const branchId = this.childParentToBranch[childNoteId + '-' + oldParentNoteId];
|
||||
const branch = await this.getBranch(branchId);
|
||||
branch.parentNoteId = newParentNoteId;
|
||||
|
||||
this.childParentToBranch[childNoteId + '-' + newParentNoteId] = branchId;
|
||||
delete this.childParentToBranch[childNoteId + '-' + oldParentNoteId]; // this is correct because we know that oldParentId isn't same as newParentId
|
||||
|
||||
// remove old associations
|
||||
this.parents[childNoteId] = this.parents[childNoteId].filter(p => p !== oldParentNoteId);
|
||||
this.children[oldParentNoteId] = this.children[oldParentNoteId].filter(ch => ch !== childNoteId);
|
||||
|
||||
// add new associations
|
||||
this.parents[childNoteId].push(newParentNoteId);
|
||||
|
||||
const children = this.children[newParentNoteId] = this.children[newParentNoteId] || []; // this might be first child
|
||||
|
||||
// we try to put the note into precise order which might be used again by lazy-loaded nodes
|
||||
if (beforeNoteId && children.includes(beforeNoteId)) {
|
||||
children.splice(children.indexOf(beforeNoteId), 0, childNoteId);
|
||||
}
|
||||
else if (afterNoteId && children.includes(afterNoteId)) {
|
||||
children.splice(children.indexOf(afterNoteId) + 1, 0, childNoteId);
|
||||
}
|
||||
else {
|
||||
children.push(childNoteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const treeCache = new TreeCache();
|
||||
|
@ -59,10 +59,14 @@ async function getNoteTitle(noteId, parentNoteId = null) {
|
||||
let {title} = note;
|
||||
|
||||
if (parentNoteId !== null) {
|
||||
const branch = await treeCache.getBranchByChildParent(noteId, parentNoteId);
|
||||
const branchId = note.parentToBranch[parentNoteId];
|
||||
|
||||
if (branch && branch.prefix) {
|
||||
title = branch.prefix + ' - ' + title;
|
||||
if (branchId) {
|
||||
const branch = await treeCache.getBranch(branchId);
|
||||
|
||||
if (branch && branch.prefix) {
|
||||
title = branch.prefix + ' - ' + title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user