multi-select in note tree and clipboard operations on the selection

This commit is contained in:
azivner 2018-01-01 17:59:59 -05:00
parent 99b163a042
commit 274bb32696
2 changed files with 104 additions and 38 deletions

View File

@ -3,53 +3,68 @@
const contextMenu = (function() { const contextMenu = (function() {
const treeEl = $("#tree"); const treeEl = $("#tree");
let clipboardId = null; let clipboardIds = [];
let clipboardMode = null; let clipboardMode = null;
function pasteAfter(node) { function pasteAfter(node) {
if (clipboardMode === 'cut') { if (clipboardMode === 'cut') {
const subjectNode = treeUtils.getNodeByKey(clipboardId); for (const nodeKey of clipboardIds) {
const subjectNode = treeUtils.getNodeByKey(nodeKey);
treeChanges.moveAfterNode(subjectNode, node); treeChanges.moveAfterNode(subjectNode, node);
}
clipboardIds = [];
clipboardMode = null;
} }
else if (clipboardMode === 'copy') { else if (clipboardMode === 'copy') {
treeChanges.cloneNoteAfter(clipboardId, node.data.note_tree_id); for (const noteId of clipboardIds) {
treeChanges.cloneNoteAfter(noteId, node.data.note_tree_id);
}
// copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places
} }
else if (clipboardId === null) { else if (clipboardIds.length === 0) {
// just do nothing // just do nothing
} }
else { else {
throwError("Unrecognized clipboard mode=" + clipboardMode); throwError("Unrecognized clipboard mode=" + clipboardMode);
} }
clipboardId = null;
clipboardMode = null;
} }
function pasteInto(node) { function pasteInto(node) {
if (clipboardMode === 'cut') { if (clipboardMode === 'cut') {
const subjectNode = treeUtils.getNodeByKey(clipboardId); for (const nodeKey of clipboardIds) {
const subjectNode = treeUtils.getNodeByKey(nodeKey);
treeChanges.moveToNode(subjectNode, node); treeChanges.moveToNode(subjectNode, node);
}
clipboardIds = [];
clipboardMode = null;
} }
else if (clipboardMode === 'copy') { else if (clipboardMode === 'copy') {
treeChanges.cloneNoteTo(clipboardId, node.data.note_id); for (const noteId of clipboardIds) {
treeChanges.cloneNoteTo(noteId, node.data.note_id);
}
// copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places
}
else if (clipboardIds.length === 0) {
// just do nothing
} }
else { else {
throwError("Unrecognized clipboard mode=" + mode); throwError("Unrecognized clipboard mode=" + mode);
} }
clipboardId = null;
clipboardMode = null;
} }
function copy(node) { function copy(nodes) {
clipboardId = node.data.note_id; clipboardIds = nodes.map(node => node.data.note_id);
clipboardMode = 'copy'; clipboardMode = 'copy';
} }
function cut(node) { function cut(nodes) {
clipboardId = node.key; clipboardIds = nodes.map(node => node.key);
clipboardMode = 'cut'; clipboardMode = 'cut';
} }
@ -77,8 +92,8 @@ const contextMenu = (function() {
beforeOpen: (event, ui) => { beforeOpen: (event, ui) => {
const node = $.ui.fancytree.getNode(ui.target); const node = $.ui.fancytree.getNode(ui.target);
// Modify menu entries depending on node status // Modify menu entries depending on node status
treeEl.contextmenu("enableEntry", "pasteAfter", clipboardId !== null); treeEl.contextmenu("enableEntry", "pasteAfter", clipboardIds.length > 0);
treeEl.contextmenu("enableEntry", "pasteInto", clipboardId !== null); treeEl.contextmenu("enableEntry", "pasteInto", clipboardIds.length > 0);
// Activate node on right-click // Activate node on right-click
node.setActive(); node.setActive();
@ -109,10 +124,10 @@ const contextMenu = (function() {
protected_session.protectSubTree(node.data.note_id, false); protected_session.protectSubTree(node.data.note_id, false);
} }
else if (ui.cmd === "copy") { else if (ui.cmd === "copy") {
copy(node); copy(noteTree.getSelectedNodes());
} }
else if (ui.cmd === "cut") { else if (ui.cmd === "cut") {
cut(node); cut(noteTree.getSelectedNodes());
} }
else if (ui.cmd === "pasteAfter") { else if (ui.cmd === "pasteAfter") {
pasteAfter(node); pasteAfter(node);

View File

@ -382,6 +382,18 @@ const noteTree = (function() {
recentNotes.addRecentNote(currentNoteTreeId, currentNotePath); recentNotes.addRecentNote(currentNoteTreeId, currentNotePath);
} }
function getSelectedNodes() {
return getTree().getSelectedNodes();
}
function clearSelectedNodes() {
for (const selectedNode of getSelectedNodes()) {
selectedNode.setSelected(false);
}
getCurrentNode().setSelected(true);
}
function initFancyTree(noteTree) { function initFancyTree(noteTree) {
assertArguments(noteTree); assertArguments(noteTree);
@ -389,53 +401,75 @@ const noteTree = (function() {
"del": node => { "del": node => {
treeChanges.deleteNode(node); treeChanges.deleteNode(node);
}, },
"shift+up": node => { "ctrl+up": node => {
const beforeNode = node.getPrevSibling(); const beforeNode = node.getPrevSibling();
if (beforeNode !== null) { if (beforeNode !== null) {
treeChanges.moveBeforeNode(node, beforeNode); treeChanges.moveBeforeNode(node, beforeNode);
} }
}, },
"shift+down": node => { "ctrl+down": node => {
let afterNode = node.getNextSibling(); let afterNode = node.getNextSibling();
if (afterNode !== null) { if (afterNode !== null) {
treeChanges.moveAfterNode(node, afterNode); treeChanges.moveAfterNode(node, afterNode);
} }
}, },
"shift+left": node => { "ctrl+left": node => {
treeChanges.moveNodeUpInHierarchy(node); treeChanges.moveNodeUpInHierarchy(node);
}, },
"shift+right": node => { "ctrl+right": node => {
let toNode = node.getPrevSibling(); let toNode = node.getPrevSibling();
if (toNode !== null) { if (toNode !== null) {
treeChanges.moveToNode(node, toNode); treeChanges.moveToNode(node, toNode);
} }
}, },
"shift+up": node => {
node.navigate($.ui.keyCode.UP, true).then(() => {
const currentNode = getCurrentNode();
if (currentNode.isSelected()) {
node.setSelected(false);
}
currentNode.setSelected(true);
});
},
"shift+down": node => {
node.navigate($.ui.keyCode.DOWN, true).then(() => {
const currentNode = getCurrentNode();
if (currentNode.isSelected()) {
node.setSelected(false);
}
currentNode.setSelected(true);
});
},
"f2": node => { "f2": node => {
editTreePrefix.showDialog(node); editTreePrefix.showDialog(node);
}, },
"alt+-": node => { "alt+-": node => {
collapseTree(node); collapseTree(node);
}, },
"ctrl+c": node => { "ctrl+c": () => {
contextMenu.copy(node); contextMenu.copy(getSelectedNodes());
showMessage("Note copied into clipboard."); showMessage("Note(s) copied into clipboard.");
return false; return false;
}, },
"ctrl+x": node => { "ctrl+x": () => {
contextMenu.cut(node); contextMenu.cut(getSelectedNodes());
showMessage("Note cut into clipboard."); showMessage("Note(s) cut into clipboard.");
return false; return false;
}, },
"ctrl+v": node => { "ctrl+v": node => {
contextMenu.pasteInto(node); contextMenu.pasteInto(node);
showMessage("Note pasted from clipboard into current note."); showMessage("Note(s) pasted from clipboard into current note.");
return false; return false;
}, },
@ -449,22 +483,22 @@ const noteTree = (function() {
// after opening context menu, standard shortcuts don't work, but they are detected here // after opening context menu, standard shortcuts don't work, but they are detected here
// so we essentially takeover the standard handling with our implementation. // so we essentially takeover the standard handling with our implementation.
"left": node => { "left": node => {
node.navigate($.ui.keyCode.LEFT, true); node.navigate($.ui.keyCode.LEFT, true).then(() => clearSelectedNodes());
return false; return false;
}, },
"right": node => { "right": node => {
node.navigate($.ui.keyCode.RIGHT, true); node.navigate($.ui.keyCode.RIGHT, true).then(() => clearSelectedNodes());
return false; return false;
}, },
"up": node => { "up": node => {
node.navigate($.ui.keyCode.UP, true); node.navigate($.ui.keyCode.UP, true).then(() => clearSelectedNodes());
return false; return false;
}, },
"down": node => { "down": node => {
node.navigate($.ui.keyCode.DOWN, true); node.navigate($.ui.keyCode.DOWN, true).then(() => clearSelectedNodes());
return false; return false;
} }
@ -476,6 +510,22 @@ const noteTree = (function() {
extensions: ["hotkeys", "filter", "dnd", "clones"], extensions: ["hotkeys", "filter", "dnd", "clones"],
source: noteTree, source: noteTree,
scrollParent: $("#tree"), scrollParent: $("#tree"),
click: (event, data) => {
const targetType = data.targetType;
const node = data.node;
if (targetType === 'title' || targetType === 'icon') {
node.setActive();
if (!event.ctrlKey) {
clearSelectedNodes();
}
node.setSelected(true);
return false;
}
},
activate: (event, data) => { activate: (event, data) => {
const node = data.node.data; const node = data.node.data;
@ -769,6 +819,7 @@ const noteTree = (function() {
setPrefix, setPrefix,
getNotePathTitle, getNotePathTitle,
removeParentChildRelation, removeParentChildRelation,
setParentChildRelation setParentChildRelation,
getSelectedNodes
}; };
})(); })();