mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
add move to dialog
This commit is contained in:
parent
5b4a2bd71c
commit
4cda661c1b
@ -83,31 +83,14 @@ CREATE TABLE IF NOT EXISTS "branches" (
|
|||||||
CREATE INDEX `IDX_branches_noteId` ON `branches` (`noteId`);
|
CREATE INDEX `IDX_branches_noteId` ON `branches` (`noteId`);
|
||||||
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
||||||
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
||||||
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
|
||||||
`noteId` TEXT NOT NULL,
|
|
||||||
`title` TEXT,
|
|
||||||
`contentLength` INT NOT NULL,
|
|
||||||
`isProtected` INT NOT NULL DEFAULT 0,
|
|
||||||
`utcDateLastEdited` TEXT NOT NULL,
|
|
||||||
`utcDateCreated` TEXT NOT NULL,
|
|
||||||
`utcDateModified` TEXT NOT NULL,
|
|
||||||
`dateLastEdited` TEXT NOT NULL,
|
|
||||||
`dateCreated` TEXT NOT NULL,
|
|
||||||
type TEXT DEFAULT '' NOT NULL,
|
|
||||||
mime TEXT DEFAULT '' NOT NULL,
|
|
||||||
hash TEXT DEFAULT '' NOT NULL);
|
|
||||||
CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||||
`content` TEXT,
|
`content` TEXT,
|
||||||
hash TEXT DEFAULT '' NOT NULL,
|
hash TEXT DEFAULT '' NOT NULL,
|
||||||
`utcDateModified` TEXT NOT NULL);
|
`utcDateModified` TEXT NOT NULL);
|
||||||
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`);
|
|
||||||
CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`);
|
|
||||||
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
|
|
||||||
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
|
|
||||||
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
|
|
||||||
CREATE TABLE IF NOT EXISTS "notes" (
|
CREATE TABLE IF NOT EXISTS "notes" (
|
||||||
`noteId` TEXT NOT NULL,
|
`noteId` TEXT NOT NULL,
|
||||||
`title` TEXT NOT NULL DEFAULT "note",
|
`title` TEXT NOT NULL DEFAULT "note",
|
||||||
|
`contentLength` INT NOT NULL,
|
||||||
`isProtected` INT NOT NULL DEFAULT 0,
|
`isProtected` INT NOT NULL DEFAULT 0,
|
||||||
`type` TEXT NOT NULL DEFAULT 'text',
|
`type` TEXT NOT NULL DEFAULT 'text',
|
||||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||||
@ -126,3 +109,22 @@ CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
|
|||||||
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
||||||
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
||||||
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
||||||
|
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||||
|
`noteId` TEXT NOT NULL,
|
||||||
|
`title` TEXT,
|
||||||
|
`contentLength` INT NOT NULL,
|
||||||
|
`isErased` INT NOT NULL DEFAULT 0,
|
||||||
|
`isProtected` INT NOT NULL DEFAULT 0,
|
||||||
|
`utcDateLastEdited` TEXT NOT NULL,
|
||||||
|
`utcDateCreated` TEXT NOT NULL,
|
||||||
|
`utcDateModified` TEXT NOT NULL,
|
||||||
|
`dateLastEdited` TEXT NOT NULL,
|
||||||
|
`dateCreated` TEXT NOT NULL,
|
||||||
|
type TEXT DEFAULT '' NOT NULL,
|
||||||
|
mime TEXT DEFAULT '' NOT NULL,
|
||||||
|
hash TEXT DEFAULT '' NOT NULL);
|
||||||
|
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`);
|
||||||
|
CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`);
|
||||||
|
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
|
||||||
|
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
|
||||||
|
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"version": "0.36.4",
|
"version": "0.36.5",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
62
src/public/javascripts/dialogs/move_to.js
Normal file
62
src/public/javascripts/dialogs/move_to.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import noteAutocompleteService from "../services/note_autocomplete.js";
|
||||||
|
import utils from "../services/utils.js";
|
||||||
|
import cloningService from "../services/cloning.js";
|
||||||
|
import treeUtils from "../services/tree_utils.js";
|
||||||
|
import toastService from "../services/toast.js";
|
||||||
|
import treeCache from "../services/tree_cache.js";
|
||||||
|
import treeChangesService from "../services/branches.js";
|
||||||
|
import treeService from "../services/tree.js";
|
||||||
|
|
||||||
|
const $dialog = $("#move-to-dialog");
|
||||||
|
const $form = $("#move-to-form");
|
||||||
|
const $noteAutoComplete = $("#move-to-note-autocomplete");
|
||||||
|
const $movePrefix = $("#move-prefix");
|
||||||
|
const $noteList = $("#move-to-note-list");
|
||||||
|
|
||||||
|
let movedNodes;
|
||||||
|
|
||||||
|
export async function showDialog(nodes) {
|
||||||
|
movedNodes = nodes;
|
||||||
|
|
||||||
|
utils.closeActiveDialog();
|
||||||
|
|
||||||
|
glob.activeDialog = $dialog;
|
||||||
|
|
||||||
|
$dialog.modal();
|
||||||
|
|
||||||
|
$noteAutoComplete.val('').trigger('focus');
|
||||||
|
|
||||||
|
$noteList.empty();
|
||||||
|
|
||||||
|
for (const node of movedNodes) {
|
||||||
|
const note = await treeCache.getNote(node.data.noteId);
|
||||||
|
|
||||||
|
$noteList.append($("<li>").text(note.title));
|
||||||
|
}
|
||||||
|
|
||||||
|
noteAutocompleteService.initNoteAutocomplete($noteAutoComplete);
|
||||||
|
noteAutocompleteService.showRecentNotes($noteAutoComplete);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function moveNotesTo(notePath) {
|
||||||
|
const targetNode = await treeService.getNodeFromPath(notePath);
|
||||||
|
|
||||||
|
await treeChangesService.moveToNode(movedNodes, targetNode);
|
||||||
|
|
||||||
|
toastService.showMessage(`Selected notes have been moved into ${targetNode.title}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form.on('submit', () => {
|
||||||
|
const notePath = $noteAutoComplete.getSelectedPath();
|
||||||
|
|
||||||
|
if (notePath) {
|
||||||
|
$dialog.modal('hide');
|
||||||
|
|
||||||
|
moveNotesTo(notePath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error("No path to move to.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
@ -18,6 +18,7 @@ const NOTE_INFO = "../dialogs/note_info.js";
|
|||||||
const ABOUT = "../dialogs/about.js";
|
const ABOUT = "../dialogs/about.js";
|
||||||
const LINK_MAP = "../dialogs/link_map.js";
|
const LINK_MAP = "../dialogs/link_map.js";
|
||||||
const CLONE_TO = "../dialogs/clone_to.js";
|
const CLONE_TO = "../dialogs/clone_to.js";
|
||||||
|
const MOVE_TO = "../dialogs/move_to.js";
|
||||||
|
|
||||||
function registerEntrypoints() {
|
function registerEntrypoints() {
|
||||||
// hot keys are active also inside inputs and content editables
|
// hot keys are active also inside inputs and content editables
|
||||||
@ -189,14 +190,22 @@ function registerEntrypoints() {
|
|||||||
|
|
||||||
utils.bindGlobalShortcut('ctrl+shift+c', () => import(CLONE_TO).then(d => {
|
utils.bindGlobalShortcut('ctrl+shift+c', () => import(CLONE_TO).then(d => {
|
||||||
const activeNode = treeService.getActiveNode();
|
const activeNode = treeService.getActiveNode();
|
||||||
console.log("activeNode", activeNode);
|
|
||||||
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
|
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
|
||||||
console.log("selectedOrActiveNodes", selectedOrActiveNodes);
|
|
||||||
|
|
||||||
const noteIds = selectedOrActiveNodes.map(node => node.data.noteId);
|
const noteIds = selectedOrActiveNodes.map(node => node.data.noteId);
|
||||||
|
|
||||||
d.showDialog(noteIds);
|
d.showDialog(noteIds);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
utils.bindGlobalShortcut('ctrl+shift+x', () => import(MOVE_TO).then(d => {
|
||||||
|
const activeNode = treeService.getActiveNode();
|
||||||
|
|
||||||
|
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
|
||||||
|
|
||||||
|
d.showDialog(selectedOrActiveNodes);
|
||||||
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -17,11 +17,12 @@ class TreeContextMenu {
|
|||||||
|
|
||||||
getNoteTypeItems(baseCmd) {
|
getNoteTypeItems(baseCmd) {
|
||||||
return [
|
return [
|
||||||
{ title: "Text", cmd: baseCmd + "_text", uiIcon: "file" },
|
{ title: "Text", cmd: baseCmd + "_text", uiIcon: "note" },
|
||||||
{ title: "Code", cmd: baseCmd + "_code", uiIcon: "terminal" },
|
{ title: "Code", cmd: baseCmd + "_code", uiIcon: "code" },
|
||||||
{ title: "Saved search", cmd: baseCmd + "_search", uiIcon: "search-folder" },
|
{ title: "Saved search", cmd: baseCmd + "_search", uiIcon: "file-find" },
|
||||||
{ title: "Relation Map", cmd: baseCmd + "_relation-map", uiIcon: "map" },
|
{ title: "Relation Map", cmd: baseCmd + "_relation-map", uiIcon: "map-alt" },
|
||||||
{ title: "Render HTML note", cmd: baseCmd + "_render", uiIcon: "play" }
|
{ title: "Render HTML note", cmd: baseCmd + "_render", uiIcon: "extension" },
|
||||||
|
{ title: "Book", cmd: baseCmd + "_book", uiIcon: "book" }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +64,13 @@ class TreeContextMenu {
|
|||||||
{ title: "Unprotect subtree", cmd: "unprotectSubtree", uiIcon: "shield", enabled: noSelectedNotes },
|
{ title: "Unprotect subtree", cmd: "unprotectSubtree", uiIcon: "shield", enabled: noSelectedNotes },
|
||||||
{ title: "----" },
|
{ title: "----" },
|
||||||
{ title: "Copy / clone <kbd>Ctrl+C</kbd>", cmd: "copy", uiIcon: "copy",
|
{ title: "Copy / clone <kbd>Ctrl+C</kbd>", cmd: "copy", uiIcon: "copy",
|
||||||
enabled: isNotRoot },
|
enabled: isNotRoot && !isHoisted },
|
||||||
{ title: "Clone to ... <kbd>Ctrl+Shift+C</kbd>", cmd: "cloneTo", uiIcon: "empty",
|
{ title: "Clone to ... <kbd>Ctrl+Shift+C</kbd>", cmd: "cloneTo", uiIcon: "empty",
|
||||||
enabled: isNotRoot },
|
enabled: isNotRoot && !isHoisted },
|
||||||
{ title: "Cut <kbd>Ctrl+X</kbd>", cmd: "cut", uiIcon: "cut",
|
{ title: "Cut <kbd>Ctrl+X</kbd>", cmd: "cut", uiIcon: "cut",
|
||||||
enabled: isNotRoot && !isHoisted && parentNotSearch },
|
enabled: isNotRoot && !isHoisted && parentNotSearch },
|
||||||
|
{ title: "Move to ... <kbd>Ctrl+Shift+X</kbd>", cmd: "moveTo", uiIcon: "empty",
|
||||||
|
enabled: isNotRoot && !isHoisted && parentNotSearch },
|
||||||
{ title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "paste",
|
{ title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "paste",
|
||||||
enabled: !clipboard.isEmpty() && notSearch && noSelectedNotes },
|
enabled: !clipboard.isEmpty() && notSearch && noSelectedNotes },
|
||||||
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "paste",
|
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "paste",
|
||||||
@ -127,11 +130,16 @@ class TreeContextMenu {
|
|||||||
const nodes = treeService.getSelectedOrActiveNodes(this.node);
|
const nodes = treeService.getSelectedOrActiveNodes(this.node);
|
||||||
const noteIds = nodes.map(node => node.data.noteId);
|
const noteIds = nodes.map(node => node.data.noteId);
|
||||||
|
|
||||||
import("../dialogs/clone_to.js").then(d => d.showDialog(noteIds))
|
import("../dialogs/clone_to.js").then(d => d.showDialog(noteIds));
|
||||||
}
|
}
|
||||||
else if (cmd === "cut") {
|
else if (cmd === "cut") {
|
||||||
clipboard.cut(treeService.getSelectedOrActiveNodes(this.node));
|
clipboard.cut(treeService.getSelectedOrActiveNodes(this.node));
|
||||||
}
|
}
|
||||||
|
else if (cmd === "moveTo") {
|
||||||
|
const nodes = treeService.getSelectedOrActiveNodes(this.node);
|
||||||
|
|
||||||
|
import("../dialogs/move_to.js").then(d => d.showDialog(nodes));
|
||||||
|
}
|
||||||
else if (cmd === "pasteAfter") {
|
else if (cmd === "pasteAfter") {
|
||||||
clipboard.pasteAfter(this.node);
|
clipboard.pasteAfter(this.node);
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ async function findBrokenReferenceIssues() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await findAndFixIssues(`
|
await findIssues(`
|
||||||
SELECT noteRevisionId, note_revisions.noteId
|
SELECT noteRevisionId, note_revisions.noteId
|
||||||
FROM note_revisions LEFT JOIN notes USING(noteId)
|
FROM note_revisions LEFT JOIN notes USING(noteId)
|
||||||
WHERE notes.noteId IS NULL`,
|
WHERE notes.noteId IS NULL`,
|
||||||
|
@ -176,6 +176,7 @@
|
|||||||
<% include dialogs/note_info.ejs %>
|
<% include dialogs/note_info.ejs %>
|
||||||
<% include dialogs/link_map.ejs %>
|
<% include dialogs/link_map.ejs %>
|
||||||
<% include dialogs/clone_to.ejs %>
|
<% include dialogs/clone_to.ejs %>
|
||||||
|
<% include dialogs/move_to.ejs %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
31
src/views/dialogs/move_to.ejs
Normal file
31
src/views/dialogs/move_to.ejs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<div id="move-to-dialog" class="modal mx-auto" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-lg" style="max-width: 1000px" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title mr-auto">Move notes to ...</h5>
|
||||||
|
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="margin-left: 0 !important;">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id="move-to-form">
|
||||||
|
<div class="modal-body">
|
||||||
|
<h5>Notes to move</h5>
|
||||||
|
|
||||||
|
<ul id="move-to-note-list" style="max-height: 200px; overflow: auto;"></ul>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="move-to-note-autocomplete">Target parent note</label>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="move-to-note-autocomplete" class="form-control" placeholder="search for note by its name">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" class="btn btn-primary">Move to selected note <kbd>enter</kbd></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
x
Reference in New Issue
Block a user