mirror of
https://github.com/zadam/trilium.git
synced 2024-09-22 00:26:01 +08:00
split up autocomplete related functionality
This commit is contained in:
parent
35998058ce
commit
68bba623b6
|
@ -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,
|
||||
};
|
Loading…
Reference in a new issue