mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	split up autocomplete related functionality
This commit is contained in:
		| @@ -3,6 +3,7 @@ import cloningService from '../services/cloning.js'; | ||||
| import linkService from '../services/link.js'; | ||||
| import noteDetailService from '../services/note_detail.js'; | ||||
| import treeUtils from '../services/tree_utils.js'; | ||||
| import autocompleteService from '../services/autocomplete.js'; | ||||
|  | ||||
| const $dialog = $("#add-link-dialog"); | ||||
| const $form = $("#add-link-form"); | ||||
| @@ -46,13 +47,13 @@ async function showDialog() { | ||||
|     $linkTitle.val(''); | ||||
|  | ||||
|     function setDefaultLinkTitle(noteId) { | ||||
|         const noteTitle = treeService.getNoteTitle(noteId); | ||||
|         const noteTitle = treeUtils.getNoteTitle(noteId); | ||||
|  | ||||
|         $linkTitle.val(noteTitle); | ||||
|     } | ||||
|  | ||||
|     $autoComplete.autocomplete({ | ||||
|         source: await treeService.getAutocompleteItems(), | ||||
|         source: await autocompleteService.getAutocompleteItems(), | ||||
|         minLength: 0, | ||||
|         change: () => { | ||||
|             const val = $autoComplete.val(); | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import treeService from '../services/tree.js'; | ||||
| import server from '../services/server.js'; | ||||
| import treeCache from "../services/tree_cache.js"; | ||||
| import treeUtils from "../services/tree_utils.js"; | ||||
|  | ||||
| const $dialog = $("#edit-tree-prefix-dialog"); | ||||
| const $form = $("#edit-tree-prefix-form"); | ||||
| @@ -24,7 +25,7 @@ async function showDialog() { | ||||
|  | ||||
|     $treePrefixInput.val(branch.prefix).focus(); | ||||
|  | ||||
|     const noteTitle = treeService.getNoteTitle(currentNode.data.noteId); | ||||
|     const noteTitle = treeUtils.getNoteTitle(currentNode.data.noteId); | ||||
|  | ||||
|     $noteTitle.html(noteTitle); | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import treeService from '../services/tree.js'; | ||||
| import linkService from '../services/link.js'; | ||||
| import utils from '../services/utils.js'; | ||||
| import autocompleteService from '../services/autocomplete.js'; | ||||
|  | ||||
| const $dialog = $("#jump-to-note-dialog"); | ||||
| const $autoComplete = $("#jump-to-note-autocomplete"); | ||||
| @@ -17,7 +18,7 @@ async function showDialog() { | ||||
|     }); | ||||
|  | ||||
|     await $autoComplete.autocomplete({ | ||||
|         source: await utils.stopWatch("building autocomplete", treeService.getAutocompleteItems), | ||||
|         source: await utils.stopWatch("building autocomplete", autocompleteService.getAutocompleteItems), | ||||
|         minLength: 0 | ||||
|     }); | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import treeService from '../services/tree.js'; | ||||
| import messagingService from '../services/messaging.js'; | ||||
| import server from '../services/server.js'; | ||||
| import utils from "../services/utils.js"; | ||||
| import treeUtils from "../services/tree_utils.js"; | ||||
|  | ||||
| const $dialog = $("#recent-notes-dialog"); | ||||
| const $searchInput = $('#recent-notes-search-input'); | ||||
| @@ -46,7 +47,7 @@ async function showDialog() { | ||||
|         let noteTitle; | ||||
|  | ||||
|         try { | ||||
|             noteTitle = await treeService.getNotePathTitle(notePath); | ||||
|             noteTitle = await treeUtils.getNotePathTitle(notePath); | ||||
|         } | ||||
|         catch (e) { | ||||
|             noteTitle = "[error - can't find note title]"; | ||||
|   | ||||
							
								
								
									
										100
									
								
								src/public/javascripts/services/autocomplete.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/public/javascripts/services/autocomplete.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| import treeCache from "./tree_cache.js"; | ||||
| import treeUtils from "./tree_utils.js"; | ||||
|  | ||||
| async function getAutocompleteItems(parentNoteId, notePath, titlePath) { | ||||
|     if (!parentNoteId) { | ||||
|         parentNoteId = 'root'; | ||||
|     } | ||||
|  | ||||
|     const parentNote = await treeCache.getNote(parentNoteId); | ||||
|     const childNotes = await parentNote.getChildNotes(); | ||||
|  | ||||
|     if (!childNotes.length) { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     if (!notePath) { | ||||
|         notePath = ''; | ||||
|     } | ||||
|  | ||||
|     if (!titlePath) { | ||||
|         titlePath = ''; | ||||
|     } | ||||
|  | ||||
|     // https://github.com/zadam/trilium/issues/46 | ||||
|     // unfortunately not easy to implement because we don't have an easy access to note's isProtected property | ||||
|  | ||||
|     const autocompleteItems = []; | ||||
|  | ||||
|     for (const childNote of childNotes) { | ||||
|         if (childNote.hideInAutocomplete) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         const childNotePath = (notePath ? (notePath + '/') : '') + childNote.noteId; | ||||
|         const childTitlePath = (titlePath ? (titlePath + ' / ') : '') + await treeUtils.getNoteTitle(childNote.noteId, parentNoteId); | ||||
|  | ||||
|         autocompleteItems.push({ | ||||
|             value: childTitlePath + ' (' + childNotePath + ')', | ||||
|             label: childTitlePath | ||||
|         }); | ||||
|  | ||||
|         const childItems = await getAutocompleteItems(childNote.noteId, childNotePath, childTitlePath); | ||||
|  | ||||
|         for (const childItem of childItems) { | ||||
|             autocompleteItems.push(childItem); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return autocompleteItems; | ||||
| } | ||||
|  | ||||
| // Overrides the default autocomplete filter function to search for matched on atleast 1 word in each of the input term's words | ||||
| $.ui.autocomplete.filter = (array, terms) => { | ||||
|     if (!terms) { | ||||
|         return array; | ||||
|     } | ||||
|  | ||||
|     const startDate = new Date(); | ||||
|  | ||||
|     const results = []; | ||||
|     const tokens = terms.toLowerCase().split(" "); | ||||
|  | ||||
|     for (const item of array) { | ||||
|         const lcLabel = item.label.toLowerCase(); | ||||
|  | ||||
|         const found = tokens.every(token => lcLabel.indexOf(token) !== -1); | ||||
|         if (!found) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // this is not completely correct and might cause minor problems with note with names containing this " / " | ||||
|         const lastSegmentIndex = lcLabel.lastIndexOf(" / "); | ||||
|  | ||||
|         if (lastSegmentIndex !== -1) { | ||||
|             const lastSegment = lcLabel.substr(lastSegmentIndex + 3); | ||||
|  | ||||
|             // at least some token needs to be in the last segment (leaf note), otherwise this | ||||
|             // particular note is not that interesting (query is satisfied by parent note) | ||||
|             const foundInLastSegment = tokens.some(token => lastSegment.indexOf(token) !== -1); | ||||
|  | ||||
|             if (!foundInLastSegment) { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         results.push(item); | ||||
|  | ||||
|         if (results.length > 100) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     console.log("Search took " + (new Date().getTime() - startDate.getTime()) + "ms"); | ||||
|  | ||||
|     return results; | ||||
| }; | ||||
|  | ||||
| export default { | ||||
|     getAutocompleteItems | ||||
| }; | ||||
| @@ -13,33 +13,19 @@ jQuery.hotkeys.options.filterInputAcceptingElements = false; | ||||
| jQuery.hotkeys.options.filterContentEditable = false; | ||||
| jQuery.hotkeys.options.filterTextInputs = false; | ||||
|  | ||||
| $(document).bind('keydown', 'alt+m', e => { | ||||
|     $(".hide-toggle").toggleClass("suppressed"); | ||||
|  | ||||
|     e.preventDefault(); | ||||
| }); | ||||
| utils.bindShortcut('alt+m', e => $(".hide-toggle").toggleClass("suppressed")); | ||||
|  | ||||
| // hide (toggle) everything except for the note content for distraction free writing | ||||
| $(document).bind('keydown', 'alt+t', e => { | ||||
| utils.bindShortcut('alt+t', e => { | ||||
|     const date = new Date(); | ||||
|     const dateString = utils.formatDateTime(date); | ||||
|  | ||||
|     linkService.addTextToEditor(dateString); | ||||
|  | ||||
|     e.preventDefault(); | ||||
| }); | ||||
|  | ||||
| $(document).bind('keydown', 'f5', () => { | ||||
|     utils.reloadApp(); | ||||
| utils.bindShortcut('f5', utils.reloadApp); | ||||
|  | ||||
|     return false; | ||||
| }); | ||||
|  | ||||
| $(document).bind('keydown', 'ctrl+r', () => { | ||||
|     utils.reloadApp(); | ||||
|  | ||||
|     return false; | ||||
| }); | ||||
| utils.bindShortcut('ctrl+r', utils.reloadApp); | ||||
|  | ||||
| $(document).bind('keydown', 'ctrl+shift+i', () => { | ||||
|     if (utils.isElectron()) { | ||||
| @@ -62,22 +48,18 @@ $(document).bind('keydown', 'ctrl+f', () => { | ||||
|     } | ||||
| }); | ||||
|  | ||||
| $(document).bind('keydown', "ctrl+shift+up", () => { | ||||
| utils.bindShortcut("ctrl+shift+up", () => { | ||||
|     const node = treeService.getCurrentNode(); | ||||
|     node.navigate($.ui.keyCode.UP, true); | ||||
|  | ||||
|     $("#note-detail").focus(); | ||||
|  | ||||
|     return false; | ||||
| }); | ||||
|  | ||||
| $(document).bind('keydown', "ctrl+shift+down", () => { | ||||
| utils.bindShortcut("ctrl+shift+down", () => { | ||||
|     const node = treeService.getCurrentNode(); | ||||
|     node.navigate($.ui.keyCode.DOWN, true); | ||||
|  | ||||
|     $("#note-detail").focus(); | ||||
|  | ||||
|     return false; | ||||
| }); | ||||
|  | ||||
| $(document).bind('keydown', 'ctrl+-', () => { | ||||
| @@ -110,52 +92,6 @@ $(window).on('beforeunload', () => { | ||||
|     noteDetailService.saveNoteIfChanged(); | ||||
| }); | ||||
|  | ||||
| // Overrides the default autocomplete filter function to search for matched on atleast 1 word in each of the input term's words | ||||
| $.ui.autocomplete.filter = (array, terms) => { | ||||
|     if (!terms) { | ||||
|         return array; | ||||
|     } | ||||
|  | ||||
|     const startDate = new Date(); | ||||
|  | ||||
|     const results = []; | ||||
|     const tokens = terms.toLowerCase().split(" "); | ||||
|  | ||||
|     for (const item of array) { | ||||
|         const lcLabel = item.label.toLowerCase(); | ||||
|  | ||||
|         const found = tokens.every(token => lcLabel.indexOf(token) !== -1); | ||||
|         if (!found) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // this is not completely correct and might cause minor problems with note with names containing this " / " | ||||
|         const lastSegmentIndex = lcLabel.lastIndexOf(" / "); | ||||
|  | ||||
|         if (lastSegmentIndex !== -1) { | ||||
|             const lastSegment = lcLabel.substr(lastSegmentIndex + 3); | ||||
|  | ||||
|             // at least some token needs to be in the last segment (leaf note), otherwise this | ||||
|             // particular note is not that interesting (query is satisfied by parent note) | ||||
|             const foundInLastSegment = tokens.some(token => lastSegment.indexOf(token) !== -1); | ||||
|  | ||||
|             if (!foundInLastSegment) { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         results.push(item); | ||||
|  | ||||
|         if (results.length > 100) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     console.log("Search took " + (new Date().getTime() - startDate.getTime()) + "ms"); | ||||
|  | ||||
|     return results; | ||||
| }; | ||||
|  | ||||
| $(document).tooltip({ | ||||
|     items: "#note-detail a", | ||||
|     content: function(callback) { | ||||
|   | ||||
| @@ -27,7 +27,7 @@ function createNoteLink(notePath, noteTitle) { | ||||
|     if (!noteTitle) { | ||||
|         const noteId = treeUtils.getNoteIdFromNotePath(notePath); | ||||
|  | ||||
|         noteTitle = treeService.getNoteTitle(noteId); | ||||
|         noteTitle = treeUtils.getNoteTitle(noteId); | ||||
|     } | ||||
|  | ||||
|     const noteLink = $("<a>", { | ||||
|   | ||||
| @@ -23,22 +23,6 @@ const $scrollToCurrentNoteButton = $("#scroll-to-current-note-button"); | ||||
|  | ||||
| let startNotePath = null; | ||||
|  | ||||
| async function getNoteTitle(noteId, parentNoteId = null) { | ||||
|     utils.assertArguments(noteId); | ||||
|  | ||||
|     let {title} = await treeCache.getNote(noteId); | ||||
|  | ||||
|     if (parentNoteId !== null) { | ||||
|         const branch = await treeCache.getBranchByChildParent(noteId, parentNoteId); | ||||
|  | ||||
|         if (branch && branch.prefix) { | ||||
|             title = branch.prefix + ' - ' + title; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return title; | ||||
| } | ||||
|  | ||||
| // note that if you want to access data like noteId or isProtected, you need to go into "data" property | ||||
| function getCurrentNode() { | ||||
|     return $tree.fancytree("getActiveNode"); | ||||
| @@ -78,7 +62,7 @@ async function setPrefix(branchId, prefix) { | ||||
| } | ||||
|  | ||||
| async function setNodeTitleWithPrefix(node) { | ||||
|     const noteTitle = await getNoteTitle(node.data.noteId); | ||||
|     const noteTitle = await treeUtils.getNoteTitle(node.data.noteId); | ||||
|     const branch = await treeCache.getBranch(node.data.branchId); | ||||
|  | ||||
|     const prefix = branch.prefix; | ||||
| @@ -300,7 +284,7 @@ async function showParentList(noteId, node) { | ||||
|             const parentNotePath = await getSomeNotePath(parentNote); | ||||
|             // this is to avoid having root notes leading '/' | ||||
|             const notePath = parentNotePath ? (parentNotePath + '/' + noteId) : noteId; | ||||
|             const title = await getNotePathTitle(notePath); | ||||
|             const title = await treeUtils.getNotePathTitle(notePath); | ||||
|  | ||||
|             let item; | ||||
|  | ||||
| @@ -316,22 +300,6 @@ async function showParentList(noteId, node) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| async function getNotePathTitle(notePath) { | ||||
|     utils.assertArguments(notePath); | ||||
|  | ||||
|     const titlePath = []; | ||||
|  | ||||
|     let parentNoteId = 'root'; | ||||
|  | ||||
|     for (const noteId of notePath.split('/')) { | ||||
|         titlePath.push(await getNoteTitle(noteId, parentNoteId)); | ||||
|  | ||||
|         parentNoteId = noteId; | ||||
|     } | ||||
|  | ||||
|     return titlePath.join(' / '); | ||||
| } | ||||
|  | ||||
| async function getSomeNotePath(note) { | ||||
|     utils.assertArguments(note); | ||||
|  | ||||
| @@ -695,54 +663,6 @@ function setProtected(noteId, isProtected) { | ||||
|     setBranchBackgroundBasedOnProtectedStatus(noteId); | ||||
| } | ||||
|  | ||||
| async function getAutocompleteItems(parentNoteId, notePath, titlePath) { | ||||
|     if (!parentNoteId) { | ||||
|         parentNoteId = 'root'; | ||||
|     } | ||||
|  | ||||
|     const parentNote = await treeCache.getNote(parentNoteId); | ||||
|     const childNotes = await parentNote.getChildNotes(); | ||||
|  | ||||
|     if (!childNotes.length) { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     if (!notePath) { | ||||
|         notePath = ''; | ||||
|     } | ||||
|  | ||||
|     if (!titlePath) { | ||||
|         titlePath = ''; | ||||
|     } | ||||
|  | ||||
|     // https://github.com/zadam/trilium/issues/46 | ||||
|     // unfortunately not easy to implement because we don't have an easy access to note's isProtected property | ||||
|  | ||||
|     const autocompleteItems = []; | ||||
|  | ||||
|     for (const childNote of childNotes) { | ||||
|         if (childNote.hideInAutocomplete) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         const childNotePath = (notePath ? (notePath + '/') : '') + childNote.noteId; | ||||
|         const childTitlePath = (titlePath ? (titlePath + ' / ') : '') + await getNoteTitle(childNote.noteId, parentNoteId); | ||||
|  | ||||
|         autocompleteItems.push({ | ||||
|             value: childTitlePath + ' (' + childNotePath + ')', | ||||
|             label: childTitlePath | ||||
|         }); | ||||
|  | ||||
|         const childItems = await getAutocompleteItems(childNote.noteId, childNotePath, childTitlePath); | ||||
|  | ||||
|         for (const childItem of childItems) { | ||||
|             autocompleteItems.push(childItem); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return autocompleteItems; | ||||
| } | ||||
|  | ||||
| async function setNoteTitle(noteId, title) { | ||||
|     utils.assertArguments(noteId); | ||||
|  | ||||
| @@ -886,18 +806,15 @@ export default { | ||||
|     scrollToCurrentNote, | ||||
|     setBranchBackgroundBasedOnProtectedStatus, | ||||
|     setProtected, | ||||
|     getCurrentNode, | ||||
|     expandToNote, | ||||
|     activateNode, | ||||
|     getCurrentNode, | ||||
|     getCurrentNotePath, | ||||
|     getNoteTitle, | ||||
|     setCurrentNotePathToHash, | ||||
|     getAutocompleteItems, | ||||
|     setNoteTitle, | ||||
|     setPrefix, | ||||
|     createNewTopLevelNote, | ||||
|     createNote, | ||||
|     setPrefix, | ||||
|     getNotePathTitle, | ||||
|     removeParentChildRelation, | ||||
|     setParentChildRelation, | ||||
|     getSelectedNodes, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import utils from './utils.js'; | ||||
| import treeCache from "./tree_cache.js"; | ||||
|  | ||||
| const $tree = $("#tree"); | ||||
|  | ||||
| @@ -30,9 +31,43 @@ function getNotePath(node) { | ||||
|     return path.reverse().join("/"); | ||||
| } | ||||
|  | ||||
| async function getNoteTitle(noteId, parentNoteId = null) { | ||||
|     utils.assertArguments(noteId); | ||||
|  | ||||
|     let {title} = await treeCache.getNote(noteId); | ||||
|  | ||||
|     if (parentNoteId !== null) { | ||||
|         const branch = await treeCache.getBranchByChildParent(noteId, parentNoteId); | ||||
|  | ||||
|         if (branch && branch.prefix) { | ||||
|             title = branch.prefix + ' - ' + title; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return title; | ||||
| } | ||||
|  | ||||
| async function getNotePathTitle(notePath) { | ||||
|     utils.assertArguments(notePath); | ||||
|  | ||||
|     const titlePath = []; | ||||
|  | ||||
|     let parentNoteId = 'root'; | ||||
|  | ||||
|     for (const noteId of notePath.split('/')) { | ||||
|         titlePath.push(await getNoteTitle(noteId, parentNoteId)); | ||||
|  | ||||
|         parentNoteId = noteId; | ||||
|     } | ||||
|  | ||||
|     return titlePath.join(' / '); | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     getParentProtectedStatus, | ||||
|     getNodeByKey, | ||||
|     getNotePath, | ||||
|     getNoteIdFromNotePath, | ||||
|     getNoteTitle, | ||||
|     getNotePathTitle, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user