mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 01:48:32 +02:00
added possibility to search by attached script returning note ids + some refactorings
This commit is contained in:
parent
9ca680f842
commit
fc13e1fa6a
@ -41,7 +41,7 @@ import macInit from './services/mac_init.js';
|
|||||||
import cssLoader from './services/css_loader.js';
|
import cssLoader from './services/css_loader.js';
|
||||||
|
|
||||||
// required for CKEditor image upload plugin
|
// required for CKEditor image upload plugin
|
||||||
window.glob.getCurrentNode = treeService.getCurrentNode;
|
window.glob.getActiveNode = treeService.getActiveNode;
|
||||||
window.glob.getHeaders = server.getHeaders;
|
window.glob.getHeaders = server.getHeaders;
|
||||||
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
|
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
|
||||||
// this is required by CKEditor when uploading images
|
// this is required by CKEditor when uploading images
|
||||||
@ -120,7 +120,7 @@ if (utils.isElectron()) {
|
|||||||
await treeService.activateNote(parentNoteId);
|
await treeService.activateNote(parentNoteId);
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const parentNode = treeService.getCurrentNode();
|
const parentNode = treeService.getActiveNode();
|
||||||
|
|
||||||
const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', "text", parentNode.data.isProtected);
|
const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', "text", parentNode.data.isProtected);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ async function showDialog() {
|
|||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
|
|
||||||
const currentNode = treeService.getCurrentNode();
|
const currentNode = treeService.getActiveNode();
|
||||||
|
|
||||||
branchId = currentNode.data.branchId;
|
branchId = currentNode.data.branchId;
|
||||||
const branch = await treeCache.getBranch(branchId);
|
const branch = await treeCache.getBranch(branchId);
|
||||||
|
@ -45,7 +45,7 @@ async function showDialog(defaultType) {
|
|||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
|
|
||||||
const currentNode = treeService.getCurrentNode();
|
const currentNode = treeService.getActiveNode();
|
||||||
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
|
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
|
||||||
|
|
||||||
$noteTitle.html(noteTitle);
|
$noteTitle.html(noteTitle);
|
||||||
@ -69,7 +69,7 @@ $form.submit(() => {
|
|||||||
|
|
||||||
const exportVersion = exportFormat === 'opml' ? $dialog.find("input[name='opml-version']:checked").val() : "1.0";
|
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);
|
exportBranch(currentNode.data.branchId, exportType, exportFormat, exportVersion);
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ async function showDialog() {
|
|||||||
|
|
||||||
glob.activeDialog = $dialog;
|
glob.activeDialog = $dialog;
|
||||||
|
|
||||||
const currentNode = treeService.getCurrentNode();
|
const currentNode = treeService.getActiveNode();
|
||||||
$noteTitle.text(await treeUtils.getNoteTitle(currentNode.data.noteId));
|
$noteTitle.text(await treeUtils.getNoteTitle(currentNode.data.noteId));
|
||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
}
|
}
|
||||||
|
|
||||||
$form.submit(() => {
|
$form.submit(() => {
|
||||||
const currentNode = treeService.getCurrentNode();
|
const currentNode = treeService.getActiveNode();
|
||||||
|
|
||||||
// disabling so that import is not triggered again.
|
// disabling so that import is not triggered again.
|
||||||
$importButton.attr("disabled", "disabled");
|
$importButton.attr("disabled", "disabled");
|
||||||
|
@ -71,7 +71,7 @@ async function showTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$("#note-menu-button").click(async e => {
|
$("#note-menu-button").click(async e => {
|
||||||
const node = treeService.getCurrentNode();
|
const node = treeService.getActiveNode();
|
||||||
const branch = await treeCache.getBranch(node.data.branchId);
|
const branch = await treeCache.getBranch(node.data.branchId);
|
||||||
const note = await treeCache.getNote(node.data.noteId);
|
const note = await treeCache.getNote(node.data.noteId);
|
||||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||||
|
@ -138,7 +138,7 @@ function registerEntrypoints() {
|
|||||||
|
|
||||||
// FIXME: do we really need these at this point?
|
// FIXME: do we really need these at this point?
|
||||||
utils.bindShortcut("ctrl+shift+up", () => {
|
utils.bindShortcut("ctrl+shift+up", () => {
|
||||||
const node = treeService.getCurrentNode();
|
const node = treeService.getActiveNode();
|
||||||
node.navigate($.ui.keyCode.UP, true);
|
node.navigate($.ui.keyCode.UP, true);
|
||||||
|
|
||||||
$("#note-detail-text").focus();
|
$("#note-detail-text").focus();
|
||||||
@ -147,7 +147,7 @@ function registerEntrypoints() {
|
|||||||
|
|
||||||
// FIXME: do we really need these at this point?
|
// FIXME: do we really need these at this point?
|
||||||
utils.bindShortcut("ctrl+shift+down", () => {
|
utils.bindShortcut("ctrl+shift+down", () => {
|
||||||
const node = treeService.getCurrentNode();
|
const node = treeService.getActiveNode();
|
||||||
node.navigate($.ui.keyCode.DOWN, true);
|
node.navigate($.ui.keyCode.DOWN, true);
|
||||||
|
|
||||||
$("#note-detail-text").focus();
|
$("#note-detail-text").focus();
|
||||||
|
@ -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
|
// 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
|
// try to render all those loaded notes one after each other. This only guarantees that correct note
|
||||||
// will be displayed independent of timing
|
// will be displayed independent of timing
|
||||||
const currentTreeNode = treeService.getCurrentNode();
|
const currentTreeNode = treeService.getActiveNode();
|
||||||
if (currentTreeNode && currentTreeNode.data.noteId !== loadedNote.noteId) {
|
if (currentTreeNode && currentTreeNode.data.noteId !== loadedNote.noteId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ async function loadNoteDetail(noteId) {
|
|||||||
activeNote = loadedNote;
|
activeNote = loadedNote;
|
||||||
|
|
||||||
if (utils.isDesktop()) {
|
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();
|
attributeService.refreshAttributes();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -43,7 +43,7 @@ function ensureProtectedSession(requireProtectedSession, modal) {
|
|||||||
$noteTitle.prop("readonly", true);
|
$noteTitle.prop("readonly", true);
|
||||||
|
|
||||||
if (modal) {
|
if (modal) {
|
||||||
if (treeService.getCurrentNode().data.isProtected) {
|
if (treeService.getActiveNode().data.isProtected) {
|
||||||
$noteDetailWrapper.hide();
|
$noteDetailWrapper.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import confirmDialog from "../dialogs/confirm.js";
|
|||||||
const $tree = $("#tree");
|
const $tree = $("#tree");
|
||||||
const $createTopLevelNoteButton = $("#create-top-level-note-button");
|
const $createTopLevelNoteButton = $("#create-top-level-note-button");
|
||||||
const $collapseTreeButton = $("#collapse-tree-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 $notePathList = $("#note-path-list");
|
||||||
const $notePathCount = $("#note-path-count");
|
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
|
// 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");
|
return $tree.fancytree("getActiveNode");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveNotePath() {
|
function getActiveNotePath() {
|
||||||
const node = getCurrentNode();
|
const node = getActiveNode();
|
||||||
|
|
||||||
return treeUtils.getNotePath(node);
|
return treeUtils.getNotePath(node);
|
||||||
}
|
}
|
||||||
@ -356,7 +356,7 @@ function clearSelectedNodes() {
|
|||||||
selectedNode.setSelected(false);
|
selectedNode.setSelected(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentNode = getCurrentNode();
|
const currentNode = getActiveNode();
|
||||||
|
|
||||||
if (currentNode) {
|
if (currentNode) {
|
||||||
currentNode.setSelected(true);
|
currentNode.setSelected(true);
|
||||||
@ -520,8 +520,8 @@ async function collapseTree(node = null) {
|
|||||||
node.visit(node => node.setExpanded(false));
|
node.visit(node => node.setExpanded(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToCurrentNote() {
|
function scrollToActiveNote() {
|
||||||
const node = getCurrentNode();
|
const node = getActiveNode();
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node.makeVisible({scrollIntoView: true});
|
node.makeVisible({scrollIntoView: true});
|
||||||
@ -697,7 +697,7 @@ messagingService.subscribeToSyncMessages(syncData => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
utils.bindShortcut('ctrl+o', async () => {
|
utils.bindShortcut('ctrl+o', async () => {
|
||||||
const node = getCurrentNode();
|
const node = getActiveNode();
|
||||||
const parentNoteId = node.data.parentNoteId;
|
const parentNoteId = node.data.parentNoteId;
|
||||||
const isProtected = treeUtils.getParentProtectedStatus(node);
|
const isProtected = treeUtils.getParentProtectedStatus(node);
|
||||||
|
|
||||||
@ -709,7 +709,7 @@ utils.bindShortcut('ctrl+o', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function createNoteInto() {
|
function createNoteInto() {
|
||||||
const node = getCurrentNode();
|
const node = getActiveNode();
|
||||||
|
|
||||||
createNote(node, node.data.noteId, 'into', null, node.data.isProtected, true);
|
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+p', createNoteInto);
|
||||||
|
|
||||||
utils.bindShortcut('ctrl+.', scrollToCurrentNote);
|
utils.bindShortcut('ctrl+.', scrollToActiveNote);
|
||||||
|
|
||||||
$(window).bind('hashchange', function() {
|
$(window).bind('hashchange', function() {
|
||||||
if (isNotePathInAddress()) {
|
if (isNotePathInAddress()) {
|
||||||
@ -760,18 +760,18 @@ utils.bindShortcut('alt+c', () => collapseTree()); // don't use shortened form s
|
|||||||
$collapseTreeButton.click(() => collapseTree());
|
$collapseTreeButton.click(() => collapseTree());
|
||||||
|
|
||||||
$createTopLevelNoteButton.click(createNewTopLevelNote);
|
$createTopLevelNoteButton.click(createNewTopLevelNote);
|
||||||
$scrollToCurrentNoteButton.click(scrollToCurrentNote);
|
$scrollToActiveNoteButton.click(scrollToActiveNote);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
reload,
|
reload,
|
||||||
collapseTree,
|
collapseTree,
|
||||||
scrollToCurrentNote,
|
scrollToActiveNote,
|
||||||
setBranchBackgroundBasedOnProtectedStatus,
|
setBranchBackgroundBasedOnProtectedStatus,
|
||||||
setProtected,
|
setProtected,
|
||||||
expandToNote,
|
expandToNote,
|
||||||
activateNote,
|
activateNote,
|
||||||
getFocusedNode,
|
getFocusedNode,
|
||||||
getCurrentNode,
|
getActiveNode,
|
||||||
getActiveNotePath,
|
getActiveNotePath,
|
||||||
setCurrentNotePathToHash,
|
setCurrentNotePathToHash,
|
||||||
setNoteTitle,
|
setNoteTitle,
|
||||||
|
@ -115,22 +115,7 @@ async function prepareRealBranch(parentNote) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function prepareSearchBranch(note) {
|
async function prepareSearchBranch(note) {
|
||||||
const fullNote = await noteDetailService.loadNote(note.noteId);
|
const results = await server.get('search-note/' + 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
|
|
||||||
|
|
||||||
// force to load all the notes at once instead of one by one
|
// force to load all the notes at once instead of one by one
|
||||||
await treeCache.getNotes(results.map(res => res.noteId));
|
await treeCache.getNotes(results.map(res => res.noteId));
|
||||||
@ -149,7 +134,7 @@ async function prepareSearchBranch(note) {
|
|||||||
treeCache.addBranch(branch);
|
treeCache.addBranch(branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await prepareRealBranch(fullNote);
|
return await prepareRealBranch(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getExtraClasses(note) {
|
async function getExtraClasses(note) {
|
||||||
|
@ -158,7 +158,7 @@ async function getContextMenuItems(event) {
|
|||||||
|
|
||||||
function selectContextMenuItem(event, cmd) {
|
function selectContextMenuItem(event, cmd) {
|
||||||
// context menu is always triggered on current node
|
// context menu is always triggered on current node
|
||||||
const node = treeService.getCurrentNode();
|
const node = treeService.getActiveNode();
|
||||||
|
|
||||||
if (cmd.startsWith("insertNoteAfter")) {
|
if (cmd.startsWith("insertNoteAfter")) {
|
||||||
const parentNoteId = node.data.parentNoteId;
|
const parentNoteId = node.data.parentNoteId;
|
||||||
|
2
src/public/libraries/ckeditor/ckeditor.js
vendored
2
src/public/libraries/ckeditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function validatorJavaScript(text, options) {
|
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
|
// eslint doesn't seem to validate pure JSON well
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('../../services/notes');
|
const noteService = require('../../services/notes');
|
||||||
|
const repository = require('../../services/repository');
|
||||||
const noteCacheService = require('../../services/note_cache');
|
const noteCacheService = require('../../services/note_cache');
|
||||||
|
const log = require('../../services/log');
|
||||||
|
const scriptService = require('../../services/script');
|
||||||
const searchService = require('../../services/search');
|
const searchService = require('../../services/search');
|
||||||
|
|
||||||
async function searchNotes(req) {
|
async function searchNotes(req) {
|
||||||
@ -24,7 +27,79 @@ async function saveSearchToNote(req) {
|
|||||||
return { noteId: note.noteId };
|
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 = {
|
module.exports = {
|
||||||
searchNotes,
|
searchNotes,
|
||||||
saveSearchToNote
|
saveSearchToNote,
|
||||||
|
searchFromNote
|
||||||
};
|
};
|
@ -202,6 +202,7 @@ function register(app) {
|
|||||||
|
|
||||||
apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes);
|
apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes);
|
||||||
apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote);
|
apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote);
|
||||||
|
apiRoute(GET, '/api/search-note/:noteId', searchRoute.searchFromNote);
|
||||||
|
|
||||||
route(POST, '/api/login/sync', [], loginApiRoute.loginSync, apiResultHandler);
|
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)
|
// this is for entering protected mode so user has to be already logged-in (that's the reason we don't require username)
|
||||||
|
@ -7,12 +7,14 @@ const log = require('./log');
|
|||||||
|
|
||||||
async function executeNote(note, apiParams) {
|
async function executeNote(note, apiParams) {
|
||||||
if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) {
|
if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) {
|
||||||
|
log.info(`Cannot execute note ${note.noteId}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bundle = await getScriptBundle(note);
|
const bundle = await getScriptBundle(note);
|
||||||
|
|
||||||
await executeBundle(bundle, apiParams);
|
return await executeBundle(bundle, apiParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeNoteNoException(note, apiParams) {
|
async function executeNoteNoException(note, apiParams) {
|
||||||
|
@ -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="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>
|
<a id="toggle-search-button" title="Search in notes. Shortcut CTRL+S" class="icon-action jam jam-search"></a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,17 +13,17 @@
|
|||||||
<form id="add-link-form">
|
<form id="add-link-form">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="add-link-type-div" class="radio">
|
<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"/>
|
<input type="radio" name="add-link-type" value="html"/>
|
||||||
add normal HTML link</label>
|
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"/>
|
<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"/>
|
<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>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<li><kbd>LEFT/RIGHT</kbd> - collapse/expand node</li>
|
<li><kbd>LEFT/RIGHT</kbd> - collapse/expand node</li>
|
||||||
<li><kbd>ALT+LEFT/RIGHT</kbd> - go back / forwards in the history</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+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>BACKSPACE</kbd> - jumps to parent note</li>
|
||||||
<li><kbd>ALT+C</kbd> - collapse whole note tree</li>
|
<li><kbd>ALT+C</kbd> - collapse whole note tree</li>
|
||||||
<li><kbd>ALT+-</kbd> (alt with minus sign) - collapse sub-tree</li>
|
<li><kbd>ALT+-</kbd> (alt with minus sign) - collapse sub-tree</li>
|
||||||
@ -35,9 +35,9 @@
|
|||||||
|
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<ul>
|
<ul>
|
||||||
<li><kbd>CTRL+O</kbd> - creates new note after the current note</li>
|
<li><kbd>CTRL+O</kbd> - creates new note after the active note</li>
|
||||||
<li><kbd>CTRL+P</kbd> - creates new sub-note into current 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 current note clone</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>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -54,9 +54,9 @@
|
|||||||
<li><kbd>SHIFT+UP/DOWN</kbd> - multi-select note above/below</li>
|
<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+A</kbd> - select all notes in the current level</li>
|
||||||
<li><kbd>CTRL+click</kbd> - select note</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+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>
|
<li><kbd>DEL</kbd> - delete note / sub-tree</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
@ -73,7 +73,7 @@
|
|||||||
<li><kbd>CTRL+K</kbd> - create / edit external link</li>
|
<li><kbd>CTRL+K</kbd> - create / edit external link</li>
|
||||||
<li><kbd>CTRL+L</kbd> - create internal 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>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>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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="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">
|
<div class="dropdown">
|
||||||
<a id="global-actions-button" title="Global actions" class="icon-action jam jam-cogs dropdown-toggle" data-toggle="dropdown"></a>
|
<a id="global-actions-button" title="Global actions" class="icon-action jam jam-cogs dropdown-toggle" data-toggle="dropdown"></a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user