mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
widgetizing tree WIP
This commit is contained in:
parent
d1f679ab90
commit
b12e38c231
@ -1,6 +1,5 @@
|
||||
import cloning from './services/cloning.js';
|
||||
import contextMenu from './services/tree_context_menu.js';
|
||||
import dragAndDropSetup from './services/drag_and_drop.js';
|
||||
import link from './services/link.js';
|
||||
import ws from './services/ws.js';
|
||||
import noteDetailService from './services/note_detail.js';
|
||||
|
@ -1,6 +1,5 @@
|
||||
import treeService from "./services/tree.js";
|
||||
import noteDetailService from "./services/note_detail.js";
|
||||
import dragAndDropSetup from "./services/drag_and_drop.js";
|
||||
import treeCache from "./services/tree_cache.js";
|
||||
import treeBuilder from "./services/tree_builder.js";
|
||||
import contextMenuWidget from "./services/context_menu.js";
|
||||
|
@ -68,6 +68,7 @@ async function moveToNode(branchIdsToMove, newParentNoteId) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME used for finding a next note to activate after a delete
|
||||
async function getNextNode(nodes) {
|
||||
// following code assumes that nodes contain only top-most selected nodes - getSelectedNodes has been
|
||||
// called with stopOnParent=true
|
||||
@ -84,10 +85,10 @@ async function getNextNode(nodes) {
|
||||
return treeUtils.getNotePath(next);
|
||||
}
|
||||
|
||||
async function deleteNodes(nodes) {
|
||||
nodes = await filterRootNote(nodes);
|
||||
async function deleteNodes(branchIdsToDelete) {
|
||||
branchIdsToDelete = await filterRootNote(branchIdsToDelete);
|
||||
|
||||
if (nodes.length === 0) {
|
||||
if (branchIdsToDelete.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,7 +97,15 @@ async function deleteNodes(nodes) {
|
||||
.append($('<label for="delete-clones-checkbox">')
|
||||
.text("delete also all note clones")
|
||||
.attr("title", "all clones of selected notes will be deleted and as such the whole note will be deleted."));
|
||||
const $nodeTitles = $("<ul>").append(...nodes.map(node => $("<li>").text(node.title)));
|
||||
|
||||
const $nodeTitles = $("<ul>");
|
||||
|
||||
for (const branchId of branchIdsToDelete) {
|
||||
const note = await treeCache.getBranch(branchId).getNote();
|
||||
|
||||
$nodeTitles.append($("<li>").text(note.title));
|
||||
}
|
||||
|
||||
const $confirmText = $("<div>")
|
||||
.append($("<p>").text('This will delete the following notes and their sub-notes: '))
|
||||
.append($nodeTitles)
|
||||
@ -114,31 +123,31 @@ async function deleteNodes(nodes) {
|
||||
|
||||
let counter = 0;
|
||||
|
||||
for (const node of nodes) {
|
||||
for (const branchIdToDelete of branchIdsToDelete) {
|
||||
counter++;
|
||||
|
||||
const last = counter === nodes.length;
|
||||
const last = counter === branchIdsToDelete.length;
|
||||
const query = `?taskId=${taskId}&last=${last ? 'true' : 'false'}`;
|
||||
|
||||
if (deleteClones) {
|
||||
await server.remove(`notes/${node.data.noteId}` + query);
|
||||
const branch = treeCache.getBranch(branchIdToDelete);
|
||||
|
||||
noteDetailService.noteDeleted(node.data.noteId);
|
||||
if (deleteClones) {
|
||||
await server.remove(`notes/${branch.noteId}` + query);
|
||||
|
||||
noteDetailService.noteDeleted(branch.noteId);
|
||||
}
|
||||
else {
|
||||
const {noteDeleted} = await server.remove(`branches/${node.data.branchId}` + query);
|
||||
const {noteDeleted} = await server.remove(`branches/${branchIdToDelete}` + query);
|
||||
|
||||
if (noteDeleted) {
|
||||
noteDetailService.noteDeleted(node.data.noteId);
|
||||
noteDetailService.noteDeleted(branch.noteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nextNotePath = await getNextNode(nodes);
|
||||
|
||||
const noteIds = Array.from(new Set(nodes.map(node => node.getParent().data.noteId)));
|
||||
|
||||
await treeService.reloadNotes(noteIds, nextNotePath);
|
||||
await treeService.reloadNotes(noteIds);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
import treeService from './tree.js';
|
||||
import treeChangesService from './branches.js';
|
||||
import hoistedNoteService from './hoisted_note.js';
|
||||
|
||||
const dragAndDropSetup = {
|
||||
autoExpandMS: 600,
|
||||
dragStart: (node, data) => {
|
||||
// don't allow dragging root node
|
||||
if (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise()
|
||||
|| node.getParent().data.noteType === 'search') {
|
||||
return false;
|
||||
}
|
||||
|
||||
node.setSelected(true);
|
||||
|
||||
const notes = treeService.getSelectedNodes().map(node => { return {
|
||||
noteId: node.data.noteId,
|
||||
title: node.title
|
||||
}});
|
||||
|
||||
data.dataTransfer.setData("text", JSON.stringify(notes));
|
||||
|
||||
// This function MUST be defined to enable dragging for the tree.
|
||||
// Return false to cancel dragging of node.
|
||||
return true;
|
||||
},
|
||||
dragEnter: (node, data) => true, // allow drop on any node
|
||||
dragOver: (node, data) => true,
|
||||
dragDrop: async (node, data) => {
|
||||
if ((data.hitMode === 'over' && node.data.noteType === 'search') ||
|
||||
(['after', 'before'].includes(data.hitMode)
|
||||
&& (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise() || node.getParent().data.noteType === 'search'))) {
|
||||
|
||||
const infoDialog = await import('../dialogs/info.js');
|
||||
|
||||
await infoDialog.info("Dropping notes into this location is not allowed.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const dataTransfer = data.dataTransfer;
|
||||
|
||||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
||||
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
||||
|
||||
const importService = await import('./import.js');
|
||||
|
||||
importService.uploadFiles(node.data.noteId, files, {
|
||||
safeImport: true,
|
||||
shrinkImages: true,
|
||||
textImportedAsText: true,
|
||||
codeImportedAsCode: true,
|
||||
explodeArchives: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
// This function MUST be defined to enable dropping of items on the tree.
|
||||
// data.hitMode is 'before', 'after', or 'over'.
|
||||
|
||||
const selectedNodes = treeService.getSelectedNodes();
|
||||
|
||||
if (data.hitMode === "before") {
|
||||
treeChangesService.moveBeforeNode(selectedNodes, node);
|
||||
} else if (data.hitMode === "after") {
|
||||
treeChangesService.moveAfterNode(selectedNodes, node);
|
||||
} else if (data.hitMode === "over") {
|
||||
treeChangesService.moveToNode(selectedNodes, node);
|
||||
} else {
|
||||
throw new Error("Unknown hitMode=" + data.hitMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default dragAndDropSetup;
|
@ -1,5 +1,3 @@
|
||||
import contextMenuWidget from './context_menu.js';
|
||||
import dragAndDropSetup from './drag_and_drop.js';
|
||||
import ws from './ws.js';
|
||||
import noteDetailService from './note_detail.js';
|
||||
import protectedSessionHolder from './protected_session_holder.js';
|
||||
@ -9,10 +7,8 @@ import server from './server.js';
|
||||
import treeCache from './tree_cache.js';
|
||||
import toastService from "./toast.js";
|
||||
import treeBuilder from "./tree_builder.js";
|
||||
import treeKeyBindingService from "./tree_keybindings.js";
|
||||
import hoistedNoteService from '../services/hoisted_note.js';
|
||||
import optionsService from "../services/options.js";
|
||||
import TreeContextMenu from "./tree_context_menu.js";
|
||||
import bundle from "./bundle.js";
|
||||
import keyboardActionService from "./keyboard_actions.js";
|
||||
|
||||
|
@ -133,7 +133,7 @@ class TreeContextMenu {
|
||||
protectedSessionService.protectSubtree(this.node.data.noteId, false);
|
||||
}
|
||||
else if (cmd === "copy") {
|
||||
clipboard.copy(this.treeWidget.getSelectedOrActiveNodes(this.node));
|
||||
clipboard.copy(this.getSelectedOrActiveBranchIds());
|
||||
}
|
||||
else if (cmd === "cloneTo") {
|
||||
const nodes = this.treeWidget.getSelectedOrActiveNodes(this.node);
|
||||
@ -142,7 +142,7 @@ class TreeContextMenu {
|
||||
import("../dialogs/clone_to.js").then(d => d.showDialog(noteIds));
|
||||
}
|
||||
else if (cmd === "cut") {
|
||||
clipboard.cut(this.treeWidget.getSelectedOrActiveNodes(this.node));
|
||||
clipboard.cut(this.getSelectedOrActiveBranchIds());
|
||||
}
|
||||
else if (cmd === "moveTo") {
|
||||
const nodes = this.treeWidget.getSelectedOrActiveNodes(this.node);
|
||||
@ -150,13 +150,13 @@ class TreeContextMenu {
|
||||
import("../dialogs/move_to.js").then(d => d.showDialog(nodes));
|
||||
}
|
||||
else if (cmd === "pasteAfter") {
|
||||
clipboard.pasteAfter(this.treeWidget, this.node);
|
||||
clipboard.pasteAfter(this.node.data.branchId);
|
||||
}
|
||||
else if (cmd === "pasteInto") {
|
||||
clipboard.pasteInto(this.node);
|
||||
clipboard.pasteInto(this.node.data.noteId);
|
||||
}
|
||||
else if (cmd === "delete") {
|
||||
treeChangesService.deleteNodes(this.treeWidget.getSelectedOrActiveNodes(this.node));
|
||||
treeChangesService.deleteNodes(this.getSelectedOrActiveBranchIds());
|
||||
}
|
||||
else if (cmd === "export") {
|
||||
const exportDialog = await import('../dialogs/export.js');
|
||||
@ -193,6 +193,12 @@ class TreeContextMenu {
|
||||
ws.logError("Unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedOrActiveBranchIds() {
|
||||
const nodes = this.treeWidget.getSelectedOrActiveNodes(this.node);
|
||||
|
||||
return nodes.map(node => node.data.branchId);
|
||||
}
|
||||
}
|
||||
|
||||
export default TreeContextMenu;
|
@ -6,161 +6,186 @@ import clipboard from "./clipboard.js";
|
||||
import utils from "./utils.js";
|
||||
import keyboardActionService from "./keyboard_actions.js";
|
||||
|
||||
const fixedKeyBindings = {
|
||||
// code below shouldn't be necessary normally, however there's some problem with interaction with context menu plugin
|
||||
// after opening context menu, standard shortcuts don't work, but they are detected here
|
||||
// so we essentially takeover the standard handling with our implementation.
|
||||
"left": node => {
|
||||
node.navigate($.ui.keyCode.LEFT, true).then(treeService.clearSelectedNodes);
|
||||
/**
|
||||
* @param {NoteTreeWidget} treeWidget
|
||||
*/
|
||||
function getFixedKeyBindings(treeWidget) {
|
||||
return {
|
||||
// code below shouldn't be necessary normally, however there's some problem with interaction with context menu plugin
|
||||
// after opening context menu, standard shortcuts don't work, but they are detected here
|
||||
// so we essentially takeover the standard handling with our implementation.
|
||||
"left": node => {
|
||||
node.navigate($.ui.keyCode.LEFT, true).then(treeWidget.clearSelectedNodes);
|
||||
|
||||
return false;
|
||||
},
|
||||
"right": node => {
|
||||
node.navigate($.ui.keyCode.RIGHT, true).then(treeService.clearSelectedNodes);
|
||||
return false;
|
||||
},
|
||||
"right": node => {
|
||||
node.navigate($.ui.keyCode.RIGHT, true).then(treeWidget.clearSelectedNodes);
|
||||
|
||||
return false;
|
||||
},
|
||||
"up": node => {
|
||||
node.navigate($.ui.keyCode.UP, true).then(treeService.clearSelectedNodes);
|
||||
return false;
|
||||
},
|
||||
"up": node => {
|
||||
node.navigate($.ui.keyCode.UP, true).then(treeWidget.clearSelectedNodes);
|
||||
|
||||
return false;
|
||||
},
|
||||
"down": node => {
|
||||
node.navigate($.ui.keyCode.DOWN, true).then(treeService.clearSelectedNodes);
|
||||
return false;
|
||||
},
|
||||
"down": node => {
|
||||
node.navigate($.ui.keyCode.DOWN, true).then(treeWidget.clearSelectedNodes);
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const templates = {
|
||||
"DeleteNotes": node => {
|
||||
treeChangesService.deleteNodes(treeService.getSelectedOrActiveNodes(node));
|
||||
},
|
||||
"MoveNoteUp": node => {
|
||||
const beforeNode = node.getPrevSibling();
|
||||
|
||||
if (beforeNode !== null) {
|
||||
treeChangesService.moveBeforeNode([node], beforeNode);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"MoveNoteDown": node => {
|
||||
const afterNode = node.getNextSibling();
|
||||
if (afterNode !== null) {
|
||||
treeChangesService.moveAfterNode([node], afterNode);
|
||||
}
|
||||
/**
|
||||
* @param {NoteTreeWidget} treeWidget
|
||||
* @param {FancytreeNode} node
|
||||
*/
|
||||
function getSelectedOrActiveBranchIds(treeWidget, node) {
|
||||
const nodes = treeWidget.getSelectedOrActiveNodes(node);
|
||||
|
||||
return false;
|
||||
},
|
||||
"MoveNoteUpInHierarchy": node => {
|
||||
treeChangesService.moveNodeUpInHierarchy(node);
|
||||
return nodes.map(node => node.data.branchId);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"MoveNoteDownInHierarchy": node => {
|
||||
const toNode = node.getPrevSibling();
|
||||
/**
|
||||
* @param {NoteTreeWidget} treeWidget
|
||||
*/
|
||||
function getTemplates(treeWidget) {
|
||||
return {
|
||||
"DeleteNotes": node => {
|
||||
treeChangesService.deleteNodes(getSelectedOrActiveBranchIds(treeWidget, node));
|
||||
},
|
||||
"MoveNoteUp": node => {
|
||||
const beforeNode = node.getPrevSibling();
|
||||
|
||||
if (toNode !== null) {
|
||||
treeChangesService.moveToNode([node], toNode);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"AddNoteAboveToSelection": () => {
|
||||
const node = treeService.getFocusedNode();
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
const prevSibling = node.getPrevSibling();
|
||||
|
||||
if (prevSibling) {
|
||||
prevSibling.setActive(true, {noEvents: true});
|
||||
|
||||
if (prevSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
if (beforeNode !== null) {
|
||||
treeChangesService.moveBeforeNode([node], beforeNode);
|
||||
}
|
||||
|
||||
prevSibling.setSelected(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"AddNoteBelowToSelection": () => {
|
||||
const node = treeService.getFocusedNode();
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
const nextSibling = node.getNextSibling();
|
||||
|
||||
if (nextSibling) {
|
||||
nextSibling.setActive(true, {noEvents: true});
|
||||
|
||||
if (nextSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
return false;
|
||||
},
|
||||
"MoveNoteDown": node => {
|
||||
const afterNode = node.getNextSibling();
|
||||
if (afterNode !== null) {
|
||||
treeChangesService.moveAfterNode([node], afterNode);
|
||||
}
|
||||
|
||||
nextSibling.setSelected(true);
|
||||
return false;
|
||||
},
|
||||
"MoveNoteUpInHierarchy": node => {
|
||||
treeChangesService.moveNodeUpInHierarchy(node);
|
||||
|
||||
return false;
|
||||
},
|
||||
"MoveNoteDownInHierarchy": node => {
|
||||
const toNode = node.getPrevSibling();
|
||||
|
||||
if (toNode !== null) {
|
||||
treeChangesService.moveToNode([node], toNode);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"AddNoteAboveToSelection": () => {
|
||||
const node = treeService.getFocusedNode();
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
const prevSibling = node.getPrevSibling();
|
||||
|
||||
if (prevSibling) {
|
||||
prevSibling.setActive(true, {noEvents: true});
|
||||
|
||||
if (prevSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
}
|
||||
|
||||
prevSibling.setSelected(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"AddNoteBelowToSelection": () => {
|
||||
const node = treeWidget.getFocusedNode();
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
const nextSibling = node.getNextSibling();
|
||||
|
||||
if (nextSibling) {
|
||||
nextSibling.setActive(true, {noEvents: true});
|
||||
|
||||
if (nextSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
}
|
||||
|
||||
nextSibling.setSelected(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"CollapseSubtree": node => {
|
||||
treeWidget.collapseTree(node);
|
||||
},
|
||||
"SortChildNotes": node => {
|
||||
treeService.sortAlphabetically(node.data.noteId);
|
||||
|
||||
return false;
|
||||
},
|
||||
"SelectAllNotesInParent": node => {
|
||||
for (const child of node.getParent().getChildren()) {
|
||||
child.setSelected(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"CopyNotesToClipboard": node => {
|
||||
clipboard.copy(getSelectedOrActiveBranchIds(treeWidget, node));
|
||||
|
||||
return false;
|
||||
},
|
||||
"CutNotesToClipboard": node => {
|
||||
clipboard.cut(getSelectedOrActiveBranchIds(treeWidget, node));
|
||||
|
||||
return false;
|
||||
},
|
||||
"PasteNotesFromClipboard": node => {
|
||||
clipboard.pasteInto(node.data.noteId);
|
||||
|
||||
return false;
|
||||
},
|
||||
"EditNoteTitle": node => {
|
||||
noteDetailService.focusOnTitle();
|
||||
|
||||
return false;
|
||||
},
|
||||
"ActivateParentNote": async node => {
|
||||
if (!await hoistedNoteService.isRootNode(node)) {
|
||||
node.getParent().setActive().then(treeWidget.clearSelectedNodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"CollapseSubtree": node => {
|
||||
treeService.collapseTree(node);
|
||||
},
|
||||
"SortChildNotes": node => {
|
||||
treeService.sortAlphabetically(node.data.noteId);
|
||||
/**
|
||||
* @param {NoteTreeWidget} treeWidget
|
||||
*/
|
||||
async function getKeyboardBindings(treeWidget) {
|
||||
const bindings = Object.assign({}, getFixedKeyBindings(treeWidget));
|
||||
|
||||
return false;
|
||||
},
|
||||
"SelectAllNotesInParent": node => {
|
||||
for (const child of node.getParent().getChildren()) {
|
||||
child.setSelected(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
"CopyNotesToClipboard": node => {
|
||||
clipboard.copy(treeService.getSelectedOrActiveNodes(node));
|
||||
|
||||
return false;
|
||||
},
|
||||
"CutNotesToClipboard": node => {
|
||||
clipboard.cut(treeService.getSelectedOrActiveNodes(node));
|
||||
|
||||
return false;
|
||||
},
|
||||
"PasteNotesFromClipboard": node => {
|
||||
clipboard.pasteInto(node);
|
||||
|
||||
return false;
|
||||
},
|
||||
"EditNoteTitle": node => {
|
||||
noteDetailService.focusOnTitle();
|
||||
|
||||
return false;
|
||||
},
|
||||
"ActivateParentNote": async node => {
|
||||
if (!await hoistedNoteService.isRootNode(node)) {
|
||||
node.getParent().setActive().then(treeService.clearSelectedNodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function getKeyboardBindings() {
|
||||
const bindings = Object.assign({}, fixedKeyBindings);
|
||||
const templates = getTemplates(treeWidget);
|
||||
|
||||
for (const actionName in templates) {
|
||||
const action = await keyboardActionService.getAction(actionName);
|
||||
|
@ -8,10 +8,10 @@ import noteDetailService from "../services/note_detail.js";
|
||||
import utils from "../services/utils.js";
|
||||
import contextMenuWidget from "../services/context_menu.js";
|
||||
import treeKeyBindingService from "../services/tree_keybindings.js";
|
||||
import dragAndDropSetup from "../services/drag_and_drop.js";
|
||||
import treeCache from "../services/tree_cache.js";
|
||||
import treeBuilder from "../services/tree_builder.js";
|
||||
import TreeContextMenu from "../services/tree_context_menu.js";
|
||||
import treeChangesService from "../services/branches.js";
|
||||
|
||||
const TPL = `
|
||||
<style>
|
||||
@ -110,9 +110,77 @@ export default class NoteTreeWidget extends BasicWidget {
|
||||
collapse: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, false),
|
||||
init: (event, data) => treeService.treeInitialized(),
|
||||
hotkeys: {
|
||||
keydown: await treeKeyBindingService.getKeyboardBindings()
|
||||
keydown: await treeKeyBindingService.getKeyboardBindings(this)
|
||||
},
|
||||
dnd5: {
|
||||
autoExpandMS: 600,
|
||||
dragStart: (node, data) => {
|
||||
// don't allow dragging root node
|
||||
if (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise()
|
||||
|| node.getParent().data.noteType === 'search') {
|
||||
return false;
|
||||
}
|
||||
|
||||
node.setSelected(true);
|
||||
|
||||
const notes = this.getSelectedNodes().map(node => { return {
|
||||
noteId: node.data.noteId,
|
||||
title: node.title
|
||||
}});
|
||||
|
||||
data.dataTransfer.setData("text", JSON.stringify(notes));
|
||||
|
||||
// This function MUST be defined to enable dragging for the tree.
|
||||
// Return false to cancel dragging of node.
|
||||
return true;
|
||||
},
|
||||
dragEnter: (node, data) => true, // allow drop on any node
|
||||
dragOver: (node, data) => true,
|
||||
dragDrop: async (node, data) => {
|
||||
if ((data.hitMode === 'over' && node.data.noteType === 'search') ||
|
||||
(['after', 'before'].includes(data.hitMode)
|
||||
&& (node.data.noteId === hoistedNoteService.getHoistedNoteNoPromise() || node.getParent().data.noteType === 'search'))) {
|
||||
|
||||
const infoDialog = await import('../dialogs/info.js');
|
||||
|
||||
await infoDialog.info("Dropping notes into this location is not allowed.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const dataTransfer = data.dataTransfer;
|
||||
|
||||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
||||
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
||||
|
||||
const importService = await import('./import.js');
|
||||
|
||||
importService.uploadFiles(node.data.noteId, files, {
|
||||
safeImport: true,
|
||||
shrinkImages: true,
|
||||
textImportedAsText: true,
|
||||
codeImportedAsCode: true,
|
||||
explodeArchives: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
// This function MUST be defined to enable dropping of items on the tree.
|
||||
// data.hitMode is 'before', 'after', or 'over'.
|
||||
|
||||
const selectedBranchIds = this.getSelectedNodes().map(node => node.data.branchId);
|
||||
|
||||
if (data.hitMode === "before") {
|
||||
treeChangesService.moveBeforeNode(selectedBranchIds, node.data.branchId);
|
||||
} else if (data.hitMode === "after") {
|
||||
treeChangesService.moveAfterNode(selectedBranchIds, node.data.branchId);
|
||||
} else if (data.hitMode === "over") {
|
||||
treeChangesService.moveToNode(selectedBranchIds, node.data.noteId);
|
||||
} else {
|
||||
throw new Error("Unknown hitMode=" + data.hitMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
dnd5: dragAndDropSetup,
|
||||
lazyLoad: function(event, data) {
|
||||
const noteId = data.node.data.noteId;
|
||||
|
||||
@ -195,6 +263,21 @@ export default class NoteTreeWidget extends BasicWidget {
|
||||
node.visit(node => node.setExpanded(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* focused & not active node can happen during multiselection where the node is selected but not activated
|
||||
* (its content is not displayed in the detail)
|
||||
* @return {FancytreeNode|null}
|
||||
*/
|
||||
getFocusedNode() {
|
||||
return this.tree.getFocusNode();
|
||||
}
|
||||
|
||||
clearSelectedNodes() {
|
||||
for (const selectedNode of this.getSelectedNodes()) {
|
||||
selectedNode.setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
createTopLevelNoteListener() { treeService.createNewTopLevelNote(); }
|
||||
|
||||
collapseTreeListener() { this.collapseTree(); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user