diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index 0432d4c30..208836f8e 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -226,7 +226,7 @@ export default class TabManager extends Component { async openEmptyTab(ntxId = null, hoistedNoteId = 'root', mainNtxId = null) { const noteContext = new NoteContext(ntxId, hoistedNoteId, mainNtxId); - let existingNoteContext + let existingNoteContext; if (utils.isMobile()) { // kind of hacky way to enforce a single tab on mobile interface - all requests to create a new one diff --git a/src/public/app/doc_notes/launchbar_note_launcher.html b/src/public/app/doc_notes/launchbar_note_launcher.html index 055bca59e..8cb967877 100644 --- a/src/public/app/doc_notes/launchbar_note_launcher.html +++ b/src/public/app/doc_notes/launchbar_note_launcher.html @@ -1,3 +1,9 @@ -
Please define the target note in the promoted attributes.
+You can define the following attributes:
+ +targetNote
- note which should be opened upon activating the launcherhoistedNote
- optional, will change the hoisted note before opening the target notekeyboardShortcut
- optional, pressing the keyboard shortcut will open the noteLaunchbar displays the title / icon from the shortcut which does not necessarily mirrors those of the target note.
diff --git a/src/public/app/menus/link_context_menu.js b/src/public/app/menus/link_context_menu.js index 76debd781..8435eaf52 100644 --- a/src/public/app/menus/link_context_menu.js +++ b/src/public/app/menus/link_context_menu.js @@ -1,7 +1,7 @@ import contextMenu from "./context_menu.js"; import appContext from "../components/app_context.js"; -function openContextMenu(notePath, e) { +function openContextMenu(notePath, hoistedNoteId, e) { contextMenu.show({ x: e.pageX, y: e.pageY, @@ -11,17 +11,21 @@ function openContextMenu(notePath, e) { {title: "Open note in a new window", command: "openNoteInNewWindow", uiIcon: "bx bx-window-open"} ], selectMenuItemHandler: ({command}) => { + if (!hoistedNoteId) { + hoistedNoteId = appContext.tabManager.getActiveContext().hoistedNoteId; + } + if (command === 'openNoteInNewTab') { - appContext.tabManager.openTabWithNoteWithHoisting(notePath); + appContext.tabManager.openContextWithNote(notePath, false, null, hoistedNoteId); } else if (command === 'openNoteInNewSplit') { const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); const {ntxId} = subContexts[subContexts.length - 1]; - appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath}); + appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath, hoistedNoteId}); } else if (command === 'openNoteInNewWindow') { - appContext.triggerCommand('openInWindow', {notePath, hoistedNoteId: 'root'}); + appContext.triggerCommand('openInWindow', {notePath, hoistedNoteId}); } } }); diff --git a/src/public/app/services/link.js b/src/public/app/services/link.js index e799d33e0..d5b8988d5 100644 --- a/src/public/app/services/link.js +++ b/src/public/app/services/link.js @@ -155,7 +155,7 @@ function linkContextMenu(e) { e.preventDefault(); - linkContextMenuService.openContextMenu(notePath, e); + linkContextMenuService.openContextMenu(notePath, null, e); } async function loadReferenceLinkTitle(noteId, $el) { diff --git a/src/public/app/widgets/buttons/launcher/abstract_launcher.js b/src/public/app/widgets/buttons/launcher/abstract_launcher.js index dd868a9e4..02c7576bb 100644 --- a/src/public/app/widgets/buttons/launcher/abstract_launcher.js +++ b/src/public/app/widgets/buttons/launcher/abstract_launcher.js @@ -1,4 +1,5 @@ import shortcutService from "../../../services/shortcuts.js"; +import attributesService from "../../../services/attributes.js"; import OnClickButtonWidget from "../onclick_button.js"; export default class AbstractLauncher extends OnClickButtonWidget { @@ -33,6 +34,8 @@ export default class AbstractLauncher extends OnClickButtonWidget { for (const attr of loadResults.getAttributes()) { if (attr.noteId === this.launcherNote.noteId && attr.type === 'label' && attr.name === 'keyboardShortcut') { this.bindNoteShortcutHandler(attr); + } else if (attr.type === 'label' && attr.name === 'iconClass' && attributesService.isAffecting(attr, this.launcherNote)) { + this.refreshIcon(); } } } diff --git a/src/public/app/widgets/buttons/launcher/note_launcher.js b/src/public/app/widgets/buttons/launcher/note_launcher.js index 87e85caec..9bac3b6db 100644 --- a/src/public/app/widgets/buttons/launcher/note_launcher.js +++ b/src/public/app/widgets/buttons/launcher/note_launcher.js @@ -15,8 +15,8 @@ export default class NoteLauncher extends AbstractLauncher { constructor(launcherNote) { super(launcherNote); - this.title(this.launcherNote.title) - .icon(this.launcherNote.getIcon()) + this.title(() => this.launcherNote.title) + .icon(() => this.launcherNote.getIcon()) .onClick((widget, evt) => this.launch(evt)) .onAuxClick((widget, evt) => this.launch(evt)) .onContextMenu(evt => { @@ -25,30 +25,46 @@ export default class NoteLauncher extends AbstractLauncher { return; } - linkContextMenuService.openContextMenu(targetNoteId, evt); + const hoistedNoteId = this.getHoistedNoteId(); + + linkContextMenuService.openContextMenu(targetNoteId, hoistedNoteId, evt); }); } - launch(evt) { + async launch(evt) { const targetNoteId = this.getTargetNoteId(); if (!targetNoteId) { return; } + const hoistedNoteId = this.getHoistedNoteId(); + if (!evt) { // keyboard shortcut - appContext.tabManager.getActiveContext().setNote(targetNoteId) - return; - } - - const ctrlKey = utils.isCtrlKey(evt); - if ((evt.which === 1 && ctrlKey) || evt.which === 2) { - appContext.tabManager.openTabWithNoteWithHoisting(targetNoteId); + await this.openInSameTab(targetNoteId, hoistedNoteId); } else { - appContext.tabManager.getActiveContext().setNote(targetNoteId); + const ctrlKey = utils.isCtrlKey(evt); + + if ((evt.which === 1 && ctrlKey) || evt.which === 2) { + await this.openInNewTab(targetNoteId, hoistedNoteId); + } else { + await this.openInSameTab(targetNoteId, hoistedNoteId); + } } } + async openInNewTab(targetNoteId, hoistedNoteId) { + const noteContext = await appContext.tabManager.openEmptyTab(null, hoistedNoteId); + + await noteContext.setNote(targetNoteId); + } + + async openInSameTab(targetNoteId, hoistedNoteId) { + const activeContext = appContext.tabManager.getActiveContext(); + await activeContext.setHoistedNoteId(hoistedNoteId); + await activeContext.setNote(targetNoteId); + } + getTargetNoteId() { const targetNoteId = this.launcherNote.getRelationValue('targetNote'); @@ -60,6 +76,11 @@ export default class NoteLauncher extends AbstractLauncher { return targetNoteId; } + getHoistedNoteId() { + return this.launcherNote.getRelationValue('hoistedNote') + || appContext.tabManager.getActiveContext().hoistedNoteId; + } + getTitle() { const shortcuts = this.launcherNote.getLabels("keyboardShortcut") .map(l => l.value) @@ -73,4 +94,4 @@ export default class NoteLauncher extends AbstractLauncher { return title; } -} \ No newline at end of file +} diff --git a/src/public/app/widgets/buttons/launcher/script_launcher.js b/src/public/app/widgets/buttons/launcher/script_launcher.js index c8ee4c6b4..b5cfebbf9 100644 --- a/src/public/app/widgets/buttons/launcher/script_launcher.js +++ b/src/public/app/widgets/buttons/launcher/script_launcher.js @@ -4,8 +4,8 @@ export default class ScriptLauncher extends AbstractLauncher { constructor(launcherNote) { super(launcherNote); - this.title(this.launcherNote.title) - .icon(this.launcherNote.getIcon()) + this.title(() => this.launcherNote.title) + .icon(() => this.launcherNote.getIcon()) .onClick(() => this.launch()); } diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 6cad410de..4a031f271 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -34,7 +34,7 @@ export default class SplitNoteContainer extends FlexContainer { this.child(widget); } - async openNewNoteSplitEvent({ntxId, notePath}) { + async openNewNoteSplitEvent({ntxId, notePath, hoistedNoteId}) { const mainNtxId = appContext.tabManager.getActiveMainContext().ntxId; if (!ntxId) { @@ -43,7 +43,7 @@ export default class SplitNoteContainer extends FlexContainer { ntxId = mainNtxId; } - const hoistedNoteId = appContext.tabManager.getActiveContext().hoistedNoteId; + hoistedNoteId = hoistedNoteId || appContext.tabManager.getActiveContext().hoistedNoteId; const noteContext = await appContext.tabManager.openEmptyTab(null, hoistedNoteId, mainNtxId); diff --git a/src/public/app/widgets/note_map.js b/src/public/app/widgets/note_map.js index ecff45b48..62fb14a77 100644 --- a/src/public/app/widgets/note_map.js +++ b/src/public/app/widgets/note_map.js @@ -110,7 +110,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget { .linkWidth(1) .linkColor(() => this.css.mutedTextColor) .onNodeClick(node => appContext.tabManager.getActiveContext().setNote(node.id)) - .onNodeRightClick((node, e) => linkContextMenuService.openContextMenu(node.id, e)); + .onNodeRightClick((node, e) => linkContextMenuService.openContextMenu(node.id, null, e)); if (this.mapType === 'link') { this.graph diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css index e6baccd83..4ca958ca5 100644 --- a/src/public/stylesheets/style.css +++ b/src/public/stylesheets/style.css @@ -757,7 +757,7 @@ li.dropdown-submenu:hover > ul.dropdown-menu { .dropdown-submenu > .dropdown-menu { top: 0; left: calc(100% - 2px); /* -2px, otherwise there's a small gap between menu and submenu where the hover can disappear */ - margin-top: -6px; + margin-top: -10px; min-width: 15rem; /* to make submenu scrollable https://github.com/zadam/trilium/issues/3136 */ max-height: 600px; diff --git a/src/services/hidden_subtree.js b/src/services/hidden_subtree.js index cb0043184..0e8232b8d 100644 --- a/src/services/hidden_subtree.js +++ b/src/services/hidden_subtree.js @@ -97,6 +97,7 @@ const HIDDEN_SUBTREE_DEFINITION = { { type: 'relation', name: 'template', value: LBTPL_BASE }, { type: 'label', name: 'launcherType', value: 'note' }, { type: 'label', name: 'relation:targetNote', value: 'promoted' }, + { type: 'label', name: 'relation:hoistedNote', value: 'promoted' }, { type: 'label', name: 'label:keyboardShortcut', value: 'promoted,text' }, { type: 'label', name: 'docName', value: 'launchbar_note_launcher' } ]