diff --git a/src/public/javascripts/services/keyboard_actions.js b/src/public/javascripts/services/keyboard_actions.js index ed21a04f4..618393483 100644 --- a/src/public/javascripts/services/keyboard_actions.js +++ b/src/public/javascripts/services/keyboard_actions.js @@ -123,5 +123,6 @@ export default { triggerAction, getAction, updateDisplayedShortcuts, - setupActionsForElement + setupActionsForElement, + getActionsForScope }; \ No newline at end of file diff --git a/src/public/javascripts/services/tree_keybindings.js b/src/public/javascripts/services/tree_keybindings.js deleted file mode 100644 index 820e79be3..000000000 --- a/src/public/javascripts/services/tree_keybindings.js +++ /dev/null @@ -1,207 +0,0 @@ -import treeChangesService from "./branches.js"; -import treeService from "./tree.js"; -import hoistedNoteService from "./hoisted_note.js"; -import clipboard from "./clipboard.js"; -import utils from "./utils.js"; -import keyboardActionService from "./keyboard_actions.js"; -import appContext from "./app_context.js"; - -/** - * @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(treeWidget.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(treeWidget.clearSelectedNodes); - - return false; - } - }; -} - -/** - * @param {NoteTreeWidget} treeWidget - * @param {FancytreeNode} node - */ -function getSelectedOrActiveBranchIds(treeWidget, node) { - const nodes = treeWidget.getSelectedOrActiveNodes(node); - - return nodes.map(node => node.data.branchId); -} - -/** - * @param {NoteTreeWidget} treeWidget - */ -function getTemplates(treeWidget) { - return { - "deleteNotes": node => { - const branchIds = getSelectedOrActiveBranchIds(treeWidget, node); - - treeChangesService.deleteNotes(treeWidget, branchIds); - }, - "moveNoteUp": node => { - const beforeNode = node.getPrevSibling(); - - if (beforeNode !== null) { - treeChangesService.moveBeforeBranch([node.data.branchId], beforeNode.data.branchId); - } - - return false; - }, - "moveNoteDown": node => { - const afterNode = node.getNextSibling(); - if (afterNode !== null) { - treeChangesService.moveAfterBranch([node.data.branchId], afterNode.data.branchId); - } - - return false; - }, - "moveNoteUpInHierarchy": node => { - treeChangesService.moveNodeUpInHierarchy(node); - - return false; - }, - "moveNoteDownInHierarchy": node => { - const toNode = node.getPrevSibling(); - - if (toNode !== null) { - treeChangesService.moveToParentNote([node.data.branchId], toNode.data.noteId); - } - - return false; - }, - "addNoteAboveToSelection": () => { - const node = treeWidget.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 => { - appContext.triggerEvent('focusOnTitle'); - - return false; - }, - "activateParentNote": node => { - if (!hoistedNoteService.isRootNode(node)) { - node.getParent().setActive().then(treeWidget.clearSelectedNodes); - } - } - }; -} - -/** - * @param {NoteTreeWidget} treeWidget - */ -async function getKeyboardBindings(treeWidget) { - const bindings = Object.assign({}, getFixedKeyBindings(treeWidget)); - - const templates = getTemplates(treeWidget); - - for (const actionName in templates) { - const action = await keyboardActionService.getAction(actionName); - - for (const shortcut of action.effectiveShortcuts || []) { - const normalizedShortcut = utils.normalizeShortcut(shortcut); - - bindings[normalizedShortcut] = templates[actionName]; - } - } - - return bindings; -} - -export default { - getKeyboardBindings -}; \ No newline at end of file diff --git a/src/public/javascripts/widgets/note_detail.js b/src/public/javascripts/widgets/note_detail.js index 60d465419..34ea6a271 100644 --- a/src/public/javascripts/widgets/note_detail.js +++ b/src/public/javascripts/widgets/note_detail.js @@ -91,7 +91,7 @@ export default class NoteDetailWidget extends TabAwareWidget { return this.tabContext && this.tabContext.isActive(); } - async refresh() {console.log("REFRESH DETAIL"); + async refresh() { if (!this.isEnabled()) { this.toggle(false); return; diff --git a/src/public/javascripts/widgets/note_title.js b/src/public/javascripts/widgets/note_title.js index e0dc5e4e3..e85c49185 100644 --- a/src/public/javascripts/widgets/note_title.js +++ b/src/public/javascripts/widgets/note_title.js @@ -72,7 +72,7 @@ export default class NoteTitleWidget extends TabAwareWidget { } } - focusAndSelectTitleEvent() { + focusAndSelectTitleCommand() { if (this.tabContext && this.tabContext.isActive()) { this.$noteTitle .trigger('focus') diff --git a/src/public/javascripts/widgets/note_tree.js b/src/public/javascripts/widgets/note_tree.js index 771c0ca3e..5a6823bf3 100644 --- a/src/public/javascripts/widgets/note_tree.js +++ b/src/public/javascripts/widgets/note_tree.js @@ -2,7 +2,6 @@ import hoistedNoteService from "../services/hoisted_note.js"; import treeService from "../services/tree.js"; import utils from "../services/utils.js"; import contextMenuWidget from "../services/context_menu.js"; -import treeKeyBindingService from "../services/tree_keybindings.js"; import treeCache from "../services/tree_cache.js"; import treeBuilder from "../services/tree_builder.js"; import TreeContextMenu from "../services/tree_context_menu.js"; @@ -13,6 +12,8 @@ import server from "../services/server.js"; import noteCreateService from "../services/note_create.js"; import toastService from "../services/toast.js"; import appContext from "../services/app_context.js"; +import keyboardActionsService from "../services/keyboard_actions.js"; +import clipboard from "../services/clipboard.js"; const TPL = `
@@ -29,7 +30,7 @@ const TPL = `
`; -export default class NoteTreeWidget extends TabAwareWidget { +export default class Notethis extends TabAwareWidget { constructor(appContext, parent) { super(appContext, parent); @@ -112,7 +113,7 @@ export default class NoteTreeWidget extends TabAwareWidget { expand: (event, data) => this.setExpandedToServer(data.node.data.branchId, true), collapse: (event, data) => this.setExpandedToServer(data.node.data.branchId, false), hotkeys: { - keydown: await treeKeyBindingService.getKeyboardBindings(this) + keydown: await this.getHotKeys() }, dnd5: { autoExpandMS: 600, @@ -406,9 +407,9 @@ export default class NoteTreeWidget extends TabAwareWidget { await this.tree.reload(notes); } - createTopLevelNoteEvent() { noteCreateService.createNewTopLevelNote(); } + createTopLevelNoteCommand() { noteCreateService.createNewTopLevelNote(); } - collapseTreeEvent() { this.collapseTree(); } + collapseTreeCommand() { this.collapseTree(); } isEnabled() { return this.tabContext && this.tabContext.isActive(); @@ -547,7 +548,7 @@ export default class NoteTreeWidget extends TabAwareWidget { } } - async createNoteAfterEvent() { + async createNoteAfterCommand() { const node = this.getActiveNode(); const parentNoteId = node.data.parentNoteId; const isProtected = await treeService.getParentProtectedStatus(node); @@ -564,7 +565,7 @@ export default class NoteTreeWidget extends TabAwareWidget { }); } - async createNoteIntoEvent() { + async createNoteIntoCommand() { const node = this.getActiveNode(); if (node) { @@ -629,4 +630,165 @@ export default class NoteTreeWidget extends TabAwareWidget { this.triggerCommand('moveBranchIdsTo', {branchIds: selectedOrActiveBranchIds}); } + + async getHotKeys() { + const actions = await keyboardActionsService.getActionsForScope('note-tree'); + const hotKeyMap = { + // 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(this.clearSelectedNodes); + + return false; + }, + "right": node => { + node.navigate($.ui.keyCode.RIGHT, true).then(this.clearSelectedNodes); + + return false; + }, + "up": node => { + node.navigate($.ui.keyCode.UP, true).then(this.clearSelectedNodes); + + return false; + }, + "down": node => { + node.navigate($.ui.keyCode.DOWN, true).then(this.clearSelectedNodes); + + return false; + } + }; + + for (const action of actions) { + for (const shortcut of action.effectiveShortcuts) { + hotKeyMap[shortcut] = node => this.triggerCommand(action.actionName, {node}); + } + } + } + + /** + * @param {FancytreeNode} node + */ + getSelectedOrActiveBranchIds(node) { + const nodes = this.getSelectedOrActiveNodes(node); + + return nodes.map(node => node.data.branchId); + } + + deleteNotesCommand({node}) { + const branchIds = this.getSelectedOrActiveBranchIds(node); + + treeChangesService.deleteNotes(this, branchIds); + } + + moveNoteUpCommand({node}) { + const beforeNode = node.getPrevSibling(); + + if (beforeNode !== null) { + treeChangesService.moveBeforeBranch([node.data.branchId], beforeNode.data.branchId); + } + } + + moveNoteDownCommand({node}) { + const afterNode = node.getNextSibling(); + if (afterNode !== null) { + treeChangesService.moveAfterBranch([node.data.branchId], afterNode.data.branchId); + } + } + + moveNoteUpInHierarchyCommand({node}) { + treeChangesService.moveNodeUpInHierarchy(node); + } + + moveNoteDownInHierarchyCommand({node}) { + const toNode = node.getPrevSibling(); + + if (toNode !== null) { + treeChangesService.moveToParentNote([node.data.branchId], toNode.data.noteId); + } + } + + addNoteAboveToSelectionCommand() { + const node = this.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); + } + } + + addNoteBelowToSelectionCommand() { + const node = this.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); + } + } + + collapseSubtreeCommand({node}) { + this.collapseTree(node); + } + + sortChildNotesCommand({node}) { + treeService.sortAlphabetically(node.data.noteId); + } + + selectAllNotesInParentCommand({node}) { + for (const child of node.getParent().getChildren()) { + child.setSelected(true); + } + } + + copyNotesToClipboardCommand({node}) { + clipboard.copy(this.getSelectedOrActiveBranchIds(node)); + } + + cutNotesToClipboardCommand({node}) { + clipboard.cut(this.getSelectedOrActiveBranchIds(node)); + } + + pasteNotesFromClipboardCommand({node}) { + clipboard.pasteInto(node.data.noteId); + } + + editNoteTitleCommand({node}) { + appContext.triggerEvent('focusOnTitle'); + } + + activateParentNoteCommand({node}) { + if (!hoistedNoteService.isRootNode(node)) { + node.getParent().setActive().then(this.clearSelectedNodes); + } + } } \ No newline at end of file diff --git a/src/public/javascripts/widgets/note_type.js b/src/public/javascripts/widgets/note_type.js index c3d0ac262..f3383d8c0 100644 --- a/src/public/javascripts/widgets/note_type.js +++ b/src/public/javascripts/widgets/note_type.js @@ -130,8 +130,9 @@ export default class NoteTypeWidget extends TabAwareWidget { } async confirmChangeIfContent() { - // FIXME - if (!this.tabContext.getComponent().getContent()) { + const noteComplement = await this.tabContext.getNoteComplement(); + + if (!noteComplement.content || !noteComplement.content.trim().length) { return true; } diff --git a/src/public/javascripts/widgets/search_box.js b/src/public/javascripts/widgets/search_box.js index 637053df5..8079537c5 100644 --- a/src/public/javascripts/widgets/search_box.js +++ b/src/public/javascripts/widgets/search_box.js @@ -159,7 +159,7 @@ export default class SearchBoxWidget extends BasicWidget { } } - searchNotesEvent() { + searchNotesCommand() { this.toggleSearchEvent(); } @@ -167,7 +167,7 @@ export default class SearchBoxWidget extends BasicWidget { this.$searchInput.val(""); } - searchInSubtreeEvent({noteId}) { + searchInSubtreeCommand({noteId}) { noteId = noteId || appContext.tabManager.getActiveTabNoteId(); this.toggle(true); diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index b5f9e72f1..197f149b3 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -248,6 +248,7 @@ function BackendScriptApi(currentNote, apiParams) { /** * @method + * @deprecated please use createNote() API method instead * * @param {string} parentNoteId - create new note under this parent * @param {string} title