added possibility to search by attached script returning note ids + some refactorings

This commit is contained in:
zadam 2019-03-20 22:28:54 +01:00
parent 9ca680f842
commit fc13e1fa6a
21 changed files with 125 additions and 62 deletions

View File

@ -41,7 +41,7 @@ import macInit from './services/mac_init.js';
import cssLoader from './services/css_loader.js';
// required for CKEditor image upload plugin
window.glob.getCurrentNode = treeService.getCurrentNode;
window.glob.getActiveNode = treeService.getActiveNode;
window.glob.getHeaders = server.getHeaders;
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
// this is required by CKEditor when uploading images
@ -120,7 +120,7 @@ if (utils.isElectron()) {
await treeService.activateNote(parentNoteId);
setTimeout(async () => {
const parentNode = treeService.getCurrentNode();
const parentNode = treeService.getActiveNode();
const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', "text", parentNode.data.isProtected);

View File

@ -16,7 +16,7 @@ async function showDialog() {
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const currentNode = treeService.getActiveNode();
branchId = currentNode.data.branchId;
const branch = await treeCache.getBranch(branchId);

View File

@ -45,7 +45,7 @@ async function showDialog(defaultType) {
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const currentNode = treeService.getActiveNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
@ -69,7 +69,7 @@ $form.submit(() => {
const exportVersion = exportFormat === 'opml' ? $dialog.find("input[name='opml-version']:checked").val() : "1.0";
const currentNode = treeService.getCurrentNode();
const currentNode = treeService.getActiveNode();
exportBranch(currentNode.data.branchId, exportType, exportFormat, exportVersion);

View File

@ -35,14 +35,14 @@ async function showDialog() {
glob.activeDialog = $dialog;
const currentNode = treeService.getCurrentNode();
const currentNode = treeService.getActiveNode();
$noteTitle.text(await treeUtils.getNoteTitle(currentNode.data.noteId));
$dialog.modal();
}
$form.submit(() => {
const currentNode = treeService.getCurrentNode();
const currentNode = treeService.getActiveNode();
// disabling so that import is not triggered again.
$importButton.attr("disabled", "disabled");

View File

@ -71,7 +71,7 @@ async function showTree() {
}
$("#note-menu-button").click(async e => {
const node = treeService.getCurrentNode();
const node = treeService.getActiveNode();
const branch = await treeCache.getBranch(node.data.branchId);
const note = await treeCache.getNote(node.data.noteId);
const parentNote = await treeCache.getNote(branch.parentNoteId);

View File

@ -138,7 +138,7 @@ function registerEntrypoints() {
// FIXME: do we really need these at this point?
utils.bindShortcut("ctrl+shift+up", () => {
const node = treeService.getCurrentNode();
const node = treeService.getActiveNode();
node.navigate($.ui.keyCode.UP, true);
$("#note-detail-text").focus();
@ -147,7 +147,7 @@ function registerEntrypoints() {
// FIXME: do we really need these at this point?
utils.bindShortcut("ctrl+shift+down", () => {
const node = treeService.getCurrentNode();
const node = treeService.getActiveNode();
node.navigate($.ui.keyCode.DOWN, true);
$("#note-detail-text").focus();

View File

@ -187,7 +187,7 @@ async function loadNoteDetail(noteId) {
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
// try to render all those loaded notes one after each other. This only guarantees that correct note
// will be displayed independent of timing
const currentTreeNode = treeService.getCurrentNode();
const currentTreeNode = treeService.getActiveNode();
if (currentTreeNode && currentTreeNode.data.noteId !== loadedNote.noteId) {
return;
}
@ -196,7 +196,7 @@ async function loadNoteDetail(noteId) {
activeNote = loadedNote;
if (utils.isDesktop()) {
// needs to happen after loading the note itself because it references current noteId
// needs to happen after loading the note itself because it references active noteId
attributeService.refreshAttributes();
}
else {

View File

@ -43,7 +43,7 @@ function ensureProtectedSession(requireProtectedSession, modal) {
$noteTitle.prop("readonly", true);
if (modal) {
if (treeService.getCurrentNode().data.isProtected) {
if (treeService.getActiveNode().data.isProtected) {
$noteDetailWrapper.hide();
}

View File

@ -20,7 +20,7 @@ import confirmDialog from "../dialogs/confirm.js";
const $tree = $("#tree");
const $createTopLevelNoteButton = $("#create-top-level-note-button");
const $collapseTreeButton = $("#collapse-tree-button");
const $scrollToCurrentNoteButton = $("#scroll-to-current-note-button");
const $scrollToActiveNoteButton = $("#scroll-to-active-note-button");
const $notePathList = $("#note-path-list");
const $notePathCount = $("#note-path-count");
@ -35,12 +35,12 @@ function getFocusedNode() {
}
// note that if you want to access data like noteId or isProtected, you need to go into "data" property
function getCurrentNode() {
function getActiveNode() {
return $tree.fancytree("getActiveNode");
}
function getActiveNotePath() {
const node = getCurrentNode();
const node = getActiveNode();
return treeUtils.getNotePath(node);
}
@ -356,7 +356,7 @@ function clearSelectedNodes() {
selectedNode.setSelected(false);
}
const currentNode = getCurrentNode();
const currentNode = getActiveNode();
if (currentNode) {
currentNode.setSelected(true);
@ -520,8 +520,8 @@ async function collapseTree(node = null) {
node.visit(node => node.setExpanded(false));
}
function scrollToCurrentNote() {
const node = getCurrentNode();
function scrollToActiveNote() {
const node = getActiveNode();
if (node) {
node.makeVisible({scrollIntoView: true});
@ -697,7 +697,7 @@ messagingService.subscribeToSyncMessages(syncData => {
});
utils.bindShortcut('ctrl+o', async () => {
const node = getCurrentNode();
const node = getActiveNode();
const parentNoteId = node.data.parentNoteId;
const isProtected = treeUtils.getParentProtectedStatus(node);
@ -709,7 +709,7 @@ utils.bindShortcut('ctrl+o', async () => {
});
function createNoteInto() {
const node = getCurrentNode();
const node = getActiveNode();
createNote(node, node.data.noteId, 'into', null, node.data.isProtected, true);
}
@ -742,7 +742,7 @@ window.glob.createNoteInto = createNoteInto;
utils.bindShortcut('ctrl+p', createNoteInto);
utils.bindShortcut('ctrl+.', scrollToCurrentNote);
utils.bindShortcut('ctrl+.', scrollToActiveNote);
$(window).bind('hashchange', function() {
if (isNotePathInAddress()) {
@ -760,18 +760,18 @@ utils.bindShortcut('alt+c', () => collapseTree()); // don't use shortened form s
$collapseTreeButton.click(() => collapseTree());
$createTopLevelNoteButton.click(createNewTopLevelNote);
$scrollToCurrentNoteButton.click(scrollToCurrentNote);
$scrollToActiveNoteButton.click(scrollToActiveNote);
export default {
reload,
collapseTree,
scrollToCurrentNote,
scrollToActiveNote,
setBranchBackgroundBasedOnProtectedStatus,
setProtected,
expandToNote,
activateNote,
getFocusedNode,
getCurrentNode,
getActiveNode,
getActiveNotePath,
setCurrentNotePathToHash,
setNoteTitle,

View File

@ -115,22 +115,7 @@ async function prepareRealBranch(parentNote) {
}
async function prepareSearchBranch(note) {
const fullNote = await noteDetailService.loadNote(note.noteId);
console.log("ZZZ", fullNote.noteContent.content);
if (!fullNote.noteContent.content || !fullNote.noteContent.content.trim()) {
return [];
}
const json = JSON.parse(fullNote.noteContent.content);
if (!json.searchString || !json.searchString.trim()) {
return [];
}
const results = (await server.get('search/' + encodeURIComponent(json.searchString)))
.filter(res => res.noteId !== note.noteId); // this is necessary because title of the search note is often the same as the search text which would match and create circle
const results = await server.get('search-note/' + note.noteId);
// force to load all the notes at once instead of one by one
await treeCache.getNotes(results.map(res => res.noteId));
@ -149,7 +134,7 @@ async function prepareSearchBranch(note) {
treeCache.addBranch(branch);
}
return await prepareRealBranch(fullNote);
return await prepareRealBranch(note);
}
async function getExtraClasses(note) {

View File

@ -158,7 +158,7 @@ async function getContextMenuItems(event) {
function selectContextMenuItem(event, cmd) {
// context menu is always triggered on current node
const node = treeService.getCurrentNode();
const node = treeService.getActiveNode();
if (cmd.startsWith("insertNoteAfter")) {
const parentNoteId = node.data.parentNoteId;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@
}
async function validatorJavaScript(text, options) {
if (glob.getCurrentNote().mime === 'application/json') {
if (glob.getActiveNote().mime === 'application/json') {
// eslint doesn't seem to validate pure JSON well
return [];
}

View File

@ -1,7 +1,10 @@
"use strict";
const noteService = require('../../services/notes');
const repository = require('../../services/repository');
const noteCacheService = require('../../services/note_cache');
const log = require('../../services/log');
const scriptService = require('../../services/script');
const searchService = require('../../services/search');
async function searchNotes(req) {
@ -24,7 +27,79 @@ async function saveSearchToNote(req) {
return { noteId: note.noteId };
}
async function searchFromNote(req) {
const note = await repository.getNote(req.params.noteId);
if (!note) {
return [404, `Note ${req.params.noteId} has not been found.`];
}
if (note.type !== 'search') {
return [400, '`Note ${req.params.noteId} is not search note.`']
}
const json = await note.getJsonContent();
if (!json || !json.searchString) {
return [];
}
let noteIds;
if (json.searchString.startsWith('=')) {
const relationName = json.searchString.substr(1).trim();
noteIds = await searchFromRelation(note, relationName);
}
else {
noteIds = searchService.searchForNoteIds(json.searchString);
}
// we won't return search note's own noteId
noteIds = noteIds.filter(noteId => noteId !== note.noteId);
return noteIds.map(noteCacheService.getNotePath).filter(res => !!res);
}
async function searchFromRelation(note, relationName) {
const scriptNote = await note.getRelationTarget(relationName);
if (!scriptNote) {
log.info(`Search note's relation ${relationName} has not been found.`);
return [];
}
if (!scriptNote.isJavaScript() || scriptNote.getScriptEnv() !== 'backend') {
log.info(`Note ${scriptNote.noteId} is not executable.`);
return [];
}
if (!note.isContentAvailable) {
log.info(`Note ${scriptNote.noteId} is not available outside of protected session.`);
return [];
}
const result = await scriptService.executeNote(scriptNote, { originEntity: note });
if (!Array.isArray(result)) {
log.info(`Result from ${scriptNote.noteId} is not an array.`);
return [];
}
if (result.length === 0) {
return [];
}
// we expect either array of noteIds (strings) or notes, in that case we extract noteIds ourselves
return typeof result[0] === 'string' ? result : result.map(item => item.noteId);
}
module.exports = {
searchNotes,
saveSearchToNote
saveSearchToNote,
searchFromNote
};

View File

@ -202,6 +202,7 @@ function register(app) {
apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes);
apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote);
apiRoute(GET, '/api/search-note/:noteId', searchRoute.searchFromNote);
route(POST, '/api/login/sync', [], loginApiRoute.loginSync, apiResultHandler);
// this is for entering protected mode so user has to be already logged-in (that's the reason we don't require username)

View File

@ -7,12 +7,14 @@ const log = require('./log');
async function executeNote(note, apiParams) {
if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) {
log.info(`Cannot execute note ${note.noteId}`);
return;
}
const bundle = await getScriptBundle(note);
await executeBundle(bundle, apiParams);
return await executeBundle(bundle, apiParams);
}
async function executeNoteNoException(note, apiParams) {

View File

@ -94,7 +94,7 @@
<a id="collapse-tree-button" title="Collapse note tree. Shortcut ALT+C" class="icon-action jam jam-layers"></a>
<a id="scroll-to-current-note-button" title="Scroll to current note. Shortcut CTRL+." class="icon-action jam jam-download"></a>
<a id="scroll-to-active-note-button" title="Scroll to active note. Shortcut CTRL+." class="icon-action jam jam-download"></a>
<a id="toggle-search-button" title="Search in notes. Shortcut CTRL+S" class="icon-action jam jam-search"></a>
</div>

View File

@ -13,17 +13,17 @@
<form id="add-link-form">
<div class="modal-body">
<div id="add-link-type-div" class="radio">
<label title="Add HTML link to the selected note at cursor in current note">
<label title="Add HTML link to the selected note at cursor in active note">
<input type="radio" name="add-link-type" value="html"/>
add normal HTML link</label>
<label title="Add selected note as a child of current note">
<label title="Add selected note as a child of active note">
<input type="radio" name="add-link-type" value="selected-to-current"/>
add selected note to current note</label>
add selected note to active note</label>
<label title="Add current note as a child of the selected note">
<label title="Add active note as a child of the selected note">
<input type="radio" name="add-link-type" value="current-to-selected"/>
add current note to selected note</label>
add active note to selected note</label>
</div>
<div class="form-group">

View File

@ -20,7 +20,7 @@
<li><kbd>LEFT/RIGHT</kbd> - collapse/expand node</li>
<li><kbd>ALT+LEFT/RIGHT</kbd> - go back / forwards in the history</li>
<li><kbd>CTRL+J</kbd> - show <a class="external" href="https://github.com/zadam/trilium/wiki/Note-navigation#jump-to-note">"Jump to" dialog</a></li>
<li><kbd>CTRL+.</kbd> - scroll to current note</li>
<li><kbd>CTRL+.</kbd> - scroll to active note</li>
<li><kbd>BACKSPACE</kbd> - jumps to parent note</li>
<li><kbd>ALT+C</kbd> - collapse whole note tree</li>
<li><kbd>ALT+-</kbd> (alt with minus sign) - collapse sub-tree</li>
@ -35,9 +35,9 @@
<p class="card-text">
<ul>
<li><kbd>CTRL+O</kbd> - creates new note after the current note</li>
<li><kbd>CTRL+P</kbd> - creates new sub-note into current note</li>
<li><kbd>F2</kbd> - edit <a class="external" href="https://github.com/zadam/trilium/wiki/Tree concepts#prefix">prefix</a> of current note clone</li>
<li><kbd>CTRL+O</kbd> - creates new note after the active note</li>
<li><kbd>CTRL+P</kbd> - creates new sub-note into active note</li>
<li><kbd>F2</kbd> - edit <a class="external" href="https://github.com/zadam/trilium/wiki/Tree concepts#prefix">prefix</a> of active note clone</li>
</ul>
</p>
</div>
@ -54,9 +54,9 @@
<li><kbd>SHIFT+UP/DOWN</kbd> - multi-select note above/below</li>
<li><kbd>CTRL+A</kbd> - select all notes in the current level</li>
<li><kbd>CTRL+click</kbd> - select note</li>
<li><kbd>CTRL+C</kbd> - copies current note (or current selection) into clipboard (used for <a class="external" href="https://github.com/zadam/trilium/wiki/Cloning notes">cloning</a>)</li>
<li><kbd>CTRL+C</kbd> - copies active note (or current selection) into clipboard (used for <a class="external" href="https://github.com/zadam/trilium/wiki/Cloning notes">cloning</a>)</li>
<li><kbd>CTRL+X</kbd> - cuts current (or current selection) note into clipboard (used for moving notes)</li>
<li><kbd>CTRL+V</kbd> - pastes note(s) as sub-note into current note (which is either move or clone depending on whether it was copied or cut into clipboard)</li>
<li><kbd>CTRL+V</kbd> - pastes note(s) as sub-note into active note (which is either move or clone depending on whether it was copied or cut into clipboard)</li>
<li><kbd>DEL</kbd> - delete note / sub-tree</li>
</ul>
</p>
@ -73,7 +73,7 @@
<li><kbd>CTRL+K</kbd> - create / edit external link</li>
<li><kbd>CTRL+L</kbd> - create internal link</li>
<li><kbd>ALT+T</kbd> - inserts current date and time at caret position</li>
<li><kbd>CTRL+.</kbd> - jump away to the tree pane and scroll to current note</li>
<li><kbd>CTRL+.</kbd> - jump away to the tree pane and scroll to active note</li>
</ul>
</p>
</div>

View File

@ -15,7 +15,7 @@
<a id="collapse-tree-button" title="Collapse note tree. Shortcut ALT+C" class="icon-action jam jam-layers"></a>
<a id="scroll-to-current-note-button" title="Scroll to current note. Shortcut CTRL+." class="icon-action jam jam-download"></a>
<a id="scroll-to-active-note-button" title="Scroll to active note. Shortcut CTRL+." class="icon-action jam jam-download"></a>
<div class="dropdown">
<a id="global-actions-button" title="Global actions" class="icon-action jam jam-cogs dropdown-toggle" data-toggle="dropdown"></a>