mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	note cache refactoring WIP
This commit is contained in:
		| @@ -75,7 +75,7 @@ function updateTitleFormGroupVisibility() { | |||||||
| } | } | ||||||
|  |  | ||||||
| $form.on('submit', () => { | $form.on('submit', () => { | ||||||
|     const notePath = $autoComplete.getSelectedPath(); |     const notePath = $autoComplete.getSelectedNotePath(); | ||||||
|  |  | ||||||
|     if (notePath) { |     if (notePath) { | ||||||
|         $dialog.modal('hide'); |         $dialog.modal('hide'); | ||||||
|   | |||||||
| @@ -269,7 +269,7 @@ function initKoPlugins() { | |||||||
|         init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { |         init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { | ||||||
|             noteAutocompleteService.initNoteAutocomplete($(element)); |             noteAutocompleteService.initNoteAutocomplete($(element)); | ||||||
|  |  | ||||||
|             $(element).setSelectedPath(bindingContext.$data.selectedPath); |             $(element).setSelectedNotePath(bindingContext.$data.selectedPath); | ||||||
|  |  | ||||||
|             $(element).on('autocomplete:selected', function (event, suggestion, dataset) { |             $(element).on('autocomplete:selected', function (event, suggestion, dataset) { | ||||||
|                 bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : ''; |                 bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : ''; | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ async function cloneNotesTo(notePath) { | |||||||
| } | } | ||||||
|  |  | ||||||
| $form.on('submit', () => { | $form.on('submit', () => { | ||||||
|     const notePath = $noteAutoComplete.getSelectedPath(); |     const notePath = $noteAutoComplete.getSelectedNotePath(); | ||||||
|  |  | ||||||
|     if (notePath) { |     if (notePath) { | ||||||
|         $dialog.modal('hide'); |         $dialog.modal('hide'); | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ async function includeNote(notePath) { | |||||||
| } | } | ||||||
|  |  | ||||||
| $form.on('submit', () => { | $form.on('submit', () => { | ||||||
|     const notePath = $autoComplete.getSelectedPath(); |     const notePath = $autoComplete.getSelectedNotePath(); | ||||||
|  |  | ||||||
|     if (notePath) { |     if (notePath) { | ||||||
|         $dialog.modal('hide'); |         $dialog.modal('hide'); | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ async function moveNotesTo(parentNoteId) { | |||||||
| } | } | ||||||
|  |  | ||||||
| $form.on('submit', () => { | $form.on('submit', () => { | ||||||
|     const notePath = $noteAutoComplete.getSelectedPath(); |     const notePath = $noteAutoComplete.getSelectedNotePath(); | ||||||
|  |  | ||||||
|     if (notePath) { |     if (notePath) { | ||||||
|         $dialog.modal('hide'); |         $dialog.modal('hide'); | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import appContext from "./app_context.js"; | |||||||
| import utils from './utils.js'; | import utils from './utils.js'; | ||||||
|  |  | ||||||
| // this key needs to have this value so it's hit by the tooltip | // this key needs to have this value so it's hit by the tooltip | ||||||
| const SELECTED_PATH_KEY = "data-note-path"; | const SELECTED_NOTE_PATH_KEY = "data-note-path"; | ||||||
|  |  | ||||||
| async function autocompleteSource(term, cb) { | async function autocompleteSource(term, cb) { | ||||||
|     const result = await server.get('autocomplete' |     const result = await server.get('autocomplete' | ||||||
| @@ -12,8 +12,8 @@ async function autocompleteSource(term, cb) { | |||||||
|  |  | ||||||
|     if (result.length === 0) { |     if (result.length === 0) { | ||||||
|         result.push({ |         result.push({ | ||||||
|             pathTitle: "No results", |             notePathTitle: "No results", | ||||||
|             path: "" |             notePath: "" | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -25,7 +25,7 @@ function clearText($el) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $el.setSelectedPath(""); |     $el.setSelectedNotePath(""); | ||||||
|     $el.autocomplete("val", "").trigger('change'); |     $el.autocomplete("val", "").trigger('change'); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -34,7 +34,7 @@ function showRecentNotes($el) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $el.setSelectedPath(""); |     $el.setSelectedNotePath(""); | ||||||
|     $el.autocomplete("val", ""); |     $el.autocomplete("val", ""); | ||||||
|     $el.trigger('focus'); |     $el.trigger('focus'); | ||||||
| } | } | ||||||
| @@ -91,10 +91,10 @@ function initNoteAutocomplete($el, options) { | |||||||
|     }, [ |     }, [ | ||||||
|         { |         { | ||||||
|             source: autocompleteSource, |             source: autocompleteSource, | ||||||
|             displayKey: 'pathTitle', |             displayKey: 'notePathTitle', | ||||||
|             templates: { |             templates: { | ||||||
|                 suggestion: function(suggestion) { |                 suggestion: function(suggestion) { | ||||||
|                     return suggestion.highlightedTitle; |                     return suggestion.highlightedNotePathTitle; | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             // we can't cache identical searches because notes can be created / renamed, new recent notes can be added |             // we can't cache identical searches because notes can be created / renamed, new recent notes can be added | ||||||
| @@ -102,7 +102,7 @@ function initNoteAutocomplete($el, options) { | |||||||
|         } |         } | ||||||
|     ]); |     ]); | ||||||
|  |  | ||||||
|     $el.on('autocomplete:selected', (event, suggestion) => $el.setSelectedPath(suggestion.path)); |     $el.on('autocomplete:selected', (event, suggestion) => $el.setSelectedNotePath(suggestion.notePath)); | ||||||
|     $el.on('autocomplete:closed', () => { |     $el.on('autocomplete:closed', () => { | ||||||
|         if (!$el.val().trim()) { |         if (!$el.val().trim()) { | ||||||
|             clearText($el); |             clearText($el); | ||||||
| @@ -113,24 +113,24 @@ function initNoteAutocomplete($el, options) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function init() { | function init() { | ||||||
|     $.fn.getSelectedPath = function () { |     $.fn.getSelectedNotePath = function () { | ||||||
|         if (!$(this).val().trim()) { |         if (!$(this).val().trim()) { | ||||||
|             return ""; |             return ""; | ||||||
|         } else { |         } else { | ||||||
|             return $(this).attr(SELECTED_PATH_KEY); |             return $(this).attr(SELECTED_NOTE_PATH_KEY); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     $.fn.setSelectedPath = function (path) { |     $.fn.setSelectedNotePath = function (notePath) { | ||||||
|         path = path || ""; |         notePath = notePath || ""; | ||||||
|  |  | ||||||
|         $(this).attr(SELECTED_PATH_KEY, path); |         $(this).attr(SELECTED_NOTE_PATH_KEY, notePath); | ||||||
|  |  | ||||||
|         $(this) |         $(this) | ||||||
|             .closest(".input-group") |             .closest(".input-group") | ||||||
|             .find(".go-to-selected-note-button") |             .find(".go-to-selected-note-button") | ||||||
|             .toggleClass("disabled", !path.trim()) |             .toggleClass("disabled", !notePath.trim()) | ||||||
|             .attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed |             .attr(SELECTED_NOTE_PATH_KEY, notePath); // we also set attr here so tooltip can be displayed | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -200,7 +200,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget { | |||||||
|                 this.promotedAttributeChanged(event); |                 this.promotedAttributeChanged(event); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             $input.setSelectedPath(valueAttr.value); |             $input.setSelectedNotePath(valueAttr.value); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             ws.logError("Unknown attribute type=" + valueAttr.type); |             ws.logError("Unknown attribute type=" + valueAttr.type); | ||||||
| @@ -250,7 +250,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget { | |||||||
|             value = $attr.is(':checked') ? "true" : "false"; |             value = $attr.is(':checked') ? "true" : "false"; | ||||||
|         } |         } | ||||||
|         else if ($attr.prop("attribute-type") === "relation") { |         else if ($attr.prop("attribute-type") === "relation") { | ||||||
|             const selectedPath = $attr.getSelectedPath(); |             const selectedPath = $attr.getSelectedNotePath(); | ||||||
|  |  | ||||||
|             value = selectedPath ? treeService.getNoteIdFromNotePath(selectedPath) : ""; |             value = selectedPath ? treeService.getNoteIdFromNotePath(selectedPath) : ""; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ async function getAutocomplete(req) { | |||||||
|         results = await getRecentNotes(activeNoteId); |         results = await getRecentNotes(activeNoteId); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         results = await noteCacheService.findNotesWithFulltext(query); |         results = await noteCacheService.findNotesForAutocomplete(query); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const msTaken = Date.now() - timestampStarted; |     const msTaken = Date.now() - timestampStarted; | ||||||
| @@ -57,10 +57,9 @@ async function getRecentNotes(activeNoteId) { | |||||||
|         const title = noteCacheService.getNoteTitleForPath(rn.notePath.split('/')); |         const title = noteCacheService.getNoteTitleForPath(rn.notePath.split('/')); | ||||||
|  |  | ||||||
|         return { |         return { | ||||||
|             path: rn.notePath, |             notePath: rn.notePath, | ||||||
|             pathTitle: title, |             notePathTitle: title, | ||||||
|             highlightedTitle: title, |             highlightedNotePathTitle: utils.escapeHtml(title) | ||||||
|             noteTitle: noteCacheService.getNoteTitleFromPath(rn.notePath) |  | ||||||
|         }; |         }; | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -371,6 +371,8 @@ async function load() { | |||||||
|     branches = await getMappedRows(`SELECT branchId, noteId, parentNoteId, prefix FROM branches WHERE isDeleted = 0`, |     branches = await getMappedRows(`SELECT branchId, noteId, parentNoteId, prefix FROM branches WHERE isDeleted = 0`, | ||||||
|         row => new Branch(row)); |         row => new Branch(row)); | ||||||
|  |  | ||||||
|  |     attributeIndex = []; | ||||||
|  |  | ||||||
|     attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`, |     attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`, | ||||||
|         row => new Attribute(row)); |         row => new Attribute(row)); | ||||||
|  |  | ||||||
| @@ -378,17 +380,7 @@ async function load() { | |||||||
|     loadedPromiseResolve(); |     loadedPromiseResolve(); | ||||||
| } | } | ||||||
|  |  | ||||||
| const expression = { | class AndExp { | ||||||
|     operator: 'and', |  | ||||||
|     operands: [ |  | ||||||
|         { |  | ||||||
|             operator: 'exists', |  | ||||||
|             fieldName: 'hokus' |  | ||||||
|         } |  | ||||||
|     ] |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class AndOp { |  | ||||||
|     constructor(subExpressions) { |     constructor(subExpressions) { | ||||||
|         this.subExpressions = subExpressions; |         this.subExpressions = subExpressions; | ||||||
|     } |     } | ||||||
| @@ -402,7 +394,7 @@ class AndOp { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class OrOp { | class OrExp { | ||||||
|     constructor(subExpressions) { |     constructor(subExpressions) { | ||||||
|         this.subExpressions = subExpressions; |         this.subExpressions = subExpressions; | ||||||
|     } |     } | ||||||
| @@ -441,7 +433,7 @@ class NoteSet { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class ExistsOp { | class ExistsExp { | ||||||
|     constructor(attributeType, attributeName) { |     constructor(attributeType, attributeName) { | ||||||
|         this.attributeType = attributeType; |         this.attributeType = attributeType; | ||||||
|         this.attributeName = attributeName; |         this.attributeName = attributeName; | ||||||
| @@ -469,7 +461,7 @@ class ExistsOp { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class EqualsOp { | class EqualsExp { | ||||||
|     constructor(attributeType, attributeName, attributeValue) { |     constructor(attributeType, attributeName, attributeValue) { | ||||||
|         this.attributeType = attributeType; |         this.attributeType = attributeType; | ||||||
|         this.attributeName = attributeName; |         this.attributeName = attributeName; | ||||||
| @@ -498,7 +490,7 @@ class EqualsOp { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class NoteContentFulltextOp { | class NoteContentFulltextExp { | ||||||
|     constructor(tokens) { |     constructor(tokens) { | ||||||
|         this.tokens = tokens; |         this.tokens = tokens; | ||||||
|     } |     } | ||||||
| @@ -525,7 +517,7 @@ class NoteContentFulltextOp { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class NoteCacheFulltextOp { | class NoteCacheFulltextExp { | ||||||
|     constructor(tokens) { |     constructor(tokens) { | ||||||
|         this.tokens = tokens; |         this.tokens = tokens; | ||||||
|     } |     } | ||||||
| @@ -569,7 +561,7 @@ class NoteCacheFulltextOp { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if (foundTokens.length > 0) { |                 if (foundTokens.length > 0) { | ||||||
|                     const remainingTokens = tokens.filter(token => !foundTokens.includes(token)); |                     const remainingTokens = this.tokens.filter(token => !foundTokens.includes(token)); | ||||||
|  |  | ||||||
|                     this.searchDownThePath(parentNote, remainingTokens, [note.noteId], resultNoteSet, searchContext); |                     this.searchDownThePath(parentNote, remainingTokens, [note.noteId], resultNoteSet, searchContext); | ||||||
|                 } |                 } | ||||||
| @@ -651,6 +643,21 @@ class NoteCacheFulltextOp { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class SearchResult { | ||||||
|  |     constructor(notePathArray) { | ||||||
|  |         this.notePathArray = notePathArray; | ||||||
|  |         this.notePathTitle = getNoteTitleForPath(notePathArray); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get notePath() { | ||||||
|  |         return this.notePathArray.join('/'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get noteId() { | ||||||
|  |         return this.notePathArray[this.notePathArray.length - 1]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| async function findNotesWithExpression(expression) { | async function findNotesWithExpression(expression) { | ||||||
|  |  | ||||||
|     const hoistedNote = notes[hoistedNoteService.getHoistedNoteId()]; |     const hoistedNote = notes[hoistedNoteService.getHoistedNoteId()]; | ||||||
| @@ -664,10 +671,27 @@ async function findNotesWithExpression(expression) { | |||||||
|         noteIdToNotePath: {} |         noteIdToNotePath: {} | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     expression.execute(allNoteSet, searchContext); |     const noteSet = await expression.execute(allNoteSet, searchContext); | ||||||
|  |  | ||||||
|  |     let searchResults = noteSet.notes | ||||||
|  |         .map(note => searchContext.noteIdToNotePath[note.noteId] || getSomePath(note)) | ||||||
|  |         .filter(notePathArray => notePathArray.includes(hoistedNoteService.getHoistedNoteId())) | ||||||
|  |         .map(notePathArray => new SearchResult(notePathArray)); | ||||||
|  |  | ||||||
|  |     // sort results by depth of the note. This is based on the assumption that more important results | ||||||
|  |     // are closer to the note root. | ||||||
|  |     searchResults.sort((a, b) => { | ||||||
|  |         if (a.notePathArray.length === b.notePathArray.length) { | ||||||
|  |             return a.notePathTitle < b.notePathTitle ? -1 : 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return a.notePathArray.length < b.notePathArray.length ? -1 : 1; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     return searchResults; | ||||||
| } | } | ||||||
|  |  | ||||||
| async function findNotesWithFulltext(query, searchInContent) { | async function findNotesForAutocomplete(query) { | ||||||
|     if (!query.trim().length) { |     if (!query.trim().length) { | ||||||
|         return []; |         return []; | ||||||
|     } |     } | ||||||
| @@ -678,74 +702,54 @@ async function findNotesWithFulltext(query, searchInContent) { | |||||||
|         .split(/[ -]/) |         .split(/[ -]/) | ||||||
|         .filter(token => token !== '/'); // '/' is used as separator |         .filter(token => token !== '/'); // '/' is used as separator | ||||||
|  |  | ||||||
|     const cacheResults = findInNoteCache(tokens); |     const expression = new NoteCacheFulltextExp(tokens); | ||||||
|  |  | ||||||
|     const contentResults = searchInContent ? await findInNoteContent(tokens) : []; |     let searchResults = await findNotesWithExpression(expression); | ||||||
|  |  | ||||||
|     let results = cacheResults.concat(contentResults); |     searchResults = searchResults.slice(0, 200); | ||||||
|  |  | ||||||
|     if (hoistedNoteService.getHoistedNoteId() !== 'root') { |     highlightSearchResults(searchResults, tokens); | ||||||
|         results = results.filter(res => res.pathArray.includes(hoistedNoteService.getHoistedNoteId())); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // sort results by depth of the note. This is based on the assumption that more important results |  | ||||||
|     // are closer to the note root. |  | ||||||
|     results.sort((a, b) => { |  | ||||||
|         if (a.pathArray.length === b.pathArray.length) { |  | ||||||
|             return a.title < b.title ? -1 : 1; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return a.pathArray.length < b.pathArray.length ? -1 : 1; |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     const apiResults = results.slice(0, 200).map(res => { |  | ||||||
|         const notePath = res.pathArray.join('/'); |  | ||||||
|  |  | ||||||
|  |     return searchResults.map(result => { | ||||||
|         return { |         return { | ||||||
|             noteId: res.noteId, |             notePath: result.notePath, | ||||||
|             branchId: res.branchId, |             notePathTitle: result.notePathTitle, | ||||||
|             path: notePath, |             highlightedNotePathTitle: result.highlightedNotePathTitle | ||||||
|             pathTitle: res.titleArray.join(' / '), |         } | ||||||
|             noteTitle: getNoteTitleFromPath(notePath) |  | ||||||
|         }; |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     highlightResults(apiResults, tokens); |  | ||||||
|  |  | ||||||
|     return apiResults; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function highlightResults(results, allTokens) { | function highlightSearchResults(searchResults, tokens) { | ||||||
|     // we remove < signs because they can cause trouble in matching and overwriting existing highlighted chunks |     // we remove < signs because they can cause trouble in matching and overwriting existing highlighted chunks | ||||||
|     // which would make the resulting HTML string invalid. |     // which would make the resulting HTML string invalid. | ||||||
|     // { and } are used for marking <b> and </b> tag (to avoid matches on single 'b' character) |     // { and } are used for marking <b> and </b> tag (to avoid matches on single 'b' character) | ||||||
|     allTokens = allTokens.map(token => token.replace('/[<\{\}]/g', '')); |     tokens = tokens.map(token => token.replace('/[<\{\}]/g', '')); | ||||||
|  |  | ||||||
|     // sort by the longest so we first highlight longest matches |     // sort by the longest so we first highlight longest matches | ||||||
|     allTokens.sort((a, b) => a.length > b.length ? -1 : 1); |     tokens.sort((a, b) => a.length > b.length ? -1 : 1); | ||||||
|  |  | ||||||
|     for (const result of results) { |     for (const result of searchResults) { | ||||||
|         const note = notes[result.noteId]; |         const note = notes[result.noteId]; | ||||||
|  |  | ||||||
|  |         result.highlightedNotePathTitle = result.notePathTitle; | ||||||
|  |  | ||||||
|         for (const attr of note.attributes) { |         for (const attr of note.attributes) { | ||||||
|             if (allTokens.find(token => attr.name.includes(token) || attr.value.includes(token))) { |             if (tokens.find(token => attr.name.includes(token) || attr.value.includes(token))) { | ||||||
|                 result.pathTitle += ` <small>${formatAttribute(attr)}</small>`; |                 result.highlightedNotePathTitle += ` <small>${formatAttribute(attr)}</small>`; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         result.highlightedTitle = result.pathTitle; |     for (const token of tokens) { | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (const token of allTokens) { |  | ||||||
|         const tokenRegex = new RegExp("(" + utils.escapeRegExp(token) + ")", "gi"); |         const tokenRegex = new RegExp("(" + utils.escapeRegExp(token) + ")", "gi"); | ||||||
|  |  | ||||||
|         for (const result of results) { |         for (const result of searchResults) { | ||||||
|             result.highlightedTitle = result.highlightedTitle.replace(tokenRegex, "{$1}"); |             result.highlightedNotePathTitle = result.highlightedNotePathTitle.replace(tokenRegex, "{$1}"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (const result of results) { |     for (const result of searchResults) { | ||||||
|         result.highlightedTitle = result.highlightedTitle |         result.highlightedNotePathTitle = result.highlightedNotePathTitle | ||||||
|             .replace(/{/g, "<b>") |             .replace(/{/g, "<b>") | ||||||
|             .replace(/}/g, "</b>"); |             .replace(/}/g, "</b>"); | ||||||
|     } |     } | ||||||
| @@ -839,17 +843,6 @@ function isInAncestor(noteId, ancestorNoteId) { | |||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| function getNoteTitleFromPath(notePath) { |  | ||||||
|     const pathArr = notePath.split("/"); |  | ||||||
|  |  | ||||||
|     if (pathArr.length === 1) { |  | ||||||
|         return getNoteTitle(pathArr[0], 'root'); |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         return getNoteTitle(pathArr[pathArr.length - 1], pathArr[pathArr.length - 2]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getNoteTitle(childNoteId, parentNoteId) { | function getNoteTitle(childNoteId, parentNoteId) { | ||||||
|     const childNote = notes[childNoteId]; |     const childNote = notes[childNoteId]; | ||||||
|     const parentNote = notes[parentNoteId]; |     const parentNote = notes[parentNoteId]; | ||||||
| @@ -868,17 +861,17 @@ function getNoteTitle(childNoteId, parentNoteId) { | |||||||
|     return ((branch && branch.prefix) ? `${branch.prefix} - ` : '') + title; |     return ((branch && branch.prefix) ? `${branch.prefix} - ` : '') + title; | ||||||
| } | } | ||||||
|  |  | ||||||
| function getNoteTitleArrayForPath(path) { | function getNoteTitleArrayForPath(notePathArray) { | ||||||
|     const titles = []; |     const titles = []; | ||||||
|  |  | ||||||
|     if (path[0] === hoistedNoteService.getHoistedNoteId() && path.length === 1) { |     if (notePathArray[0] === hoistedNoteService.getHoistedNoteId() && notePathArray.length === 1) { | ||||||
|         return [ getNoteTitle(hoistedNoteService.getHoistedNoteId()) ]; |         return [ getNoteTitle(hoistedNoteService.getHoistedNoteId()) ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let parentNoteId = 'root'; |     let parentNoteId = 'root'; | ||||||
|     let hoistedNotePassed = false; |     let hoistedNotePassed = false; | ||||||
|  |  | ||||||
|     for (const noteId of path) { |     for (const noteId of notePathArray) { | ||||||
|         // start collecting path segment titles only after hoisted note |         // start collecting path segment titles only after hoisted note | ||||||
|         if (hoistedNotePassed) { |         if (hoistedNotePassed) { | ||||||
|             const title = getNoteTitle(noteId, parentNoteId); |             const title = getNoteTitle(noteId, parentNoteId); | ||||||
| @@ -896,8 +889,8 @@ function getNoteTitleArrayForPath(path) { | |||||||
|     return titles; |     return titles; | ||||||
| } | } | ||||||
|  |  | ||||||
| function getNoteTitleForPath(path) { | function getNoteTitleForPath(notePathArray) { | ||||||
|     const titles = getNoteTitleArrayForPath(path); |     const titles = getNoteTitleArrayForPath(notePathArray); | ||||||
|  |  | ||||||
|     return titles.join(' / '); |     return titles.join(' / '); | ||||||
| } | } | ||||||
| @@ -1153,10 +1146,9 @@ sqlInit.dbReady.then(() => utils.stopWatch("Note cache load", load)); | |||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     loadedPromise, |     loadedPromise, | ||||||
|     findNotesWithFulltext, |     findNotesForAutocomplete, | ||||||
|     getNotePath, |     getNotePath, | ||||||
|     getNoteTitleForPath, |     getNoteTitleForPath, | ||||||
|     getNoteTitleFromPath, |  | ||||||
|     isAvailable, |     isAvailable, | ||||||
|     isArchived, |     isArchived, | ||||||
|     isInAncestor, |     isInAncestor, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user