diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index 81872e23d..757c4b776 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -21,7 +21,7 @@ const NOTE_TYPE_ICONS = { "mermaid": "bx bx-selection", "canvas": "bx bx-pen", "web-view": "bx bx-globe-alt", - "shortcut": "bx bx-up-arrow-circle", + "shortcut": "bx bx-link", "doc": "bx bxs-file-doc" }; @@ -827,9 +827,7 @@ class NoteShort { } isLaunchBarConfig() { - // launch bar config should be max 2 levels deep - return this.noteId.startsWith("lb_") - || this.getParentBranchIds().find(branchId => branchId.startsWith("lb_")); + return this.type === 'shortcut' || this.noteId.startsWith("lb_"); } } diff --git a/src/public/app/widgets/buttons/button_from_note.js b/src/public/app/widgets/buttons/button_from_note.js index bafc809b4..f9ac81a6b 100644 --- a/src/public/app/widgets/buttons/button_from_note.js +++ b/src/public/app/widgets/buttons/button_from_note.js @@ -6,11 +6,17 @@ export default class ButtonFromNoteWidget extends ButtonWidget { constructor() { super(); - this.settings.buttonNoteId = null; + this.settings.buttonNoteIdProvider = null; + this.settings.defaultIconProvider = null; } - buttonNoteId(noteId) { - this.settings.buttonNoteId = noteId; + buttonNoteIdProvider(provider) { + this.settings.buttonNoteIdProvider = provider; + return this; + } + + defaultIconProvider(provider) { + this.settings.defaultIconProvider = provider; return this; } @@ -21,18 +27,32 @@ export default class ButtonFromNoteWidget extends ButtonWidget { } updateIcon() { - froca.getNote(this.settings.buttonNoteId).then(note => { - this.settings.icon = note.getLabelValue("iconClass"); + const buttonNoteId = this.settings.buttonNoteIdProvider(); + + if (!buttonNoteId && this.settings.defaultIconProvider()) { + this.settings.icon = this.settings.defaultIconProvider(); this.refreshIcon(); - }); + } else { + froca.getNote(buttonNoteId).then(note => { + this.settings.icon = note.getIcon(); + + this.refreshIcon(); + }); + } } entitiesReloadedEvent({loadResults}) { + const buttonNote = froca.getNoteFromCache(this.buttonNoteIdProvider()); + + if (!buttonNote) { + return; + } + if (loadResults.getAttributes(this.componentId).find(attr => attr.type === 'label' && attr.name === 'iconClass' - && attributeService.isAffecting(attr, this.note))) { + && attributeService.isAffecting(attr, buttonNote))) { this.updateIcon(); } diff --git a/src/public/app/widgets/buttons/history/history_back.js b/src/public/app/widgets/buttons/history/history_back.js index 63fc51f58..77ceff03b 100644 --- a/src/public/app/widgets/buttons/history/history_back.js +++ b/src/public/app/widgets/buttons/history/history_back.js @@ -8,7 +8,7 @@ export default class BackInHistoryButtonWidget extends AbstractHistoryNavigation .title("Go to previous note.") .command("backInNoteHistory") .titlePlacement("right") - .buttonNoteId('lb_backinhistory') + .buttonNoteIdProvider(() => 'lb_backinhistory') .onContextMenu(e => this.showContextMenu(e)); } } diff --git a/src/public/app/widgets/buttons/history/history_forward.js b/src/public/app/widgets/buttons/history/history_forward.js index 9b5fde004..7b824e6fd 100644 --- a/src/public/app/widgets/buttons/history/history_forward.js +++ b/src/public/app/widgets/buttons/history/history_forward.js @@ -8,7 +8,7 @@ export default class ForwardInHistoryButtonWidget extends AbstractHistoryNavigat .title("Go to next note.") .command("forwardInNoteHistory") .titlePlacement("right") - .buttonNoteId('lb_forwardinhistory') + .buttonNoteIdProvider(() => 'lb_forwardinhistory') .onContextMenu(e => this.showContextMenu(e)); } } diff --git a/src/public/app/widgets/containers/shortcut_container.js b/src/public/app/widgets/containers/shortcut_container.js index a7ffaf371..4215b8ca9 100644 --- a/src/public/app/widgets/containers/shortcut_container.js +++ b/src/public/app/widgets/containers/shortcut_container.js @@ -9,6 +9,8 @@ import ProtectedSessionStatusWidget from "../buttons/protected_session_status.js import SyncStatusWidget from "../sync_status.js"; import BackInHistoryButtonWidget from "../buttons/history/history_back.js"; import ForwardInHistoryButtonWidget from "../buttons/history/history_forward.js"; +import dialogService from "../../services/dialog.js"; +import ButtonFromNoteWidget from "../buttons/button_from_note.js"; export default class ShortcutContainer extends FlexContainer { constructor() { @@ -65,17 +67,29 @@ export default class ShortcutContainer extends FlexContainer { return; } - if (shortcut.getLabelValue("command")) { + const shortcutType = shortcut.getLabelValue("shortcutType"); + + if (shortcutType === 'command') { this.child(new ButtonWidget() .title(shortcut.title) .icon(shortcut.getIcon()) .command(shortcut.getLabelValue("command"))); - } else if (shortcut.hasRelation('targetNote')) { - this.child(new ButtonWidget() + } else if (shortcutType === 'note') { + this.child(new ButtonFromNoteWidget() .title(shortcut.title) - .icon(shortcut.getIcon()) - .onClick(() => appContext.tabManager.openTabWithNoteWithHoisting(shortcut.getRelationValue('targetNote'), true))); - } else if (shortcut.hasRelation('script')) { + .buttonNoteIdProvider(() => shortcut.getRelationValue('targetNote')) + .defaultIconProvider(() => shortcut.getIcon()) + .onClick(() => { + const targetNoteId = shortcut.getRelationValue('targetNote'); + + if (!targetNoteId) { + dialogService.info("This shortcut doesn't define target note."); + return; + } + + appContext.tabManager.openTabWithNoteWithHoisting(targetNoteId, true) + })); + } else if (shortcutType === 'script') { this.child(new ButtonWidget() .title(shortcut.title) .icon(shortcut.getIcon()) @@ -84,13 +98,13 @@ export default class ShortcutContainer extends FlexContainer { await script.executeScript(); })); - } else if (shortcut.hasRelation('widget')) { + } else if (shortcutType === 'customWidget') { const widget = await shortcut.getRelationTarget('widget'); const res = await widget.executeScript(); this.child(res); - } else { + } else if (shortcutType === 'builtinWidget') { const builtinWidget = shortcut.getLabelValue("builtinWidget"); if (builtinWidget) { @@ -117,9 +131,11 @@ export default class ShortcutContainer extends FlexContainer { } else if (builtinWidget === 'forwardInHistoryButton') { this.child(new ForwardInHistoryButtonWidget()); } else { - console.log(`Unrecognized builtin widget ${builtinWidget} for shortcut ${shortcut.noteId} "${shortcut.title}"`); + console.warn(`Unrecognized builtin widget ${builtinWidget} for shortcut ${shortcut.noteId} "${shortcut.title}"`); } } + } else { + console.warn(`Unrecognized shortcut type ${shortcutType} for shortcut '${shortcut.noteId}' title ${shortcut.title}`); } } catch (e) { diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index a5aa272f5..6475f78b6 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -1566,15 +1566,15 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } addWidgetShortcutCommand({node}) { - this.createShortcutNote(node, 'widget'); + this.createShortcutNote(node, 'customWidget'); } addSpacerShortcutCommand({node}) { this.createShortcutNote(node, 'spacer'); } - async createShortcutNote(node, type) { - const resp = await server.post(`special-notes/shortcuts/${node.data.noteId}/${type}`); + async createShortcutNote(node, shortcutType) { + const resp = await server.post(`special-notes/shortcuts/${node.data.noteId}/${shortcutType}`); if (!resp.success) { alert(resp.message); diff --git a/src/routes/api/special_notes.js b/src/routes/api/special_notes.js index cbbc4b1f1..900e9ea1e 100644 --- a/src/routes/api/special_notes.js +++ b/src/routes/api/special_notes.js @@ -67,7 +67,7 @@ function getHoistedNote() { } function createShortcut(req) { - return specialNotesService.createShortcut(req.params.parentNoteId, req.params.type); + return specialNotesService.createShortcut(req.params.parentNoteId, req.params.shortcutType); } function resetShortcut(req) { diff --git a/src/routes/routes.js b/src/routes/routes.js index 4cd7ebb98..1667c7054 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -327,7 +327,7 @@ function register(app) { apiRoute(POST, '/api/special-notes/search-note', specialNotesRoute.createSearchNote); apiRoute(POST, '/api/special-notes/save-search-note', specialNotesRoute.saveSearchNote); apiRoute(POST, '/api/special-notes/shortcuts/:noteId/reset', specialNotesRoute.resetShortcut); - apiRoute(POST, '/api/special-notes/shortcuts/:parentNoteId/:type', specialNotesRoute.createShortcut); + apiRoute(POST, '/api/special-notes/shortcuts/:parentNoteId/:shortcutType', specialNotesRoute.createShortcut); // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage); diff --git a/src/services/special_notes.js b/src/services/special_notes.js index 9754e8d7f..37bb6e495 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -6,6 +6,7 @@ const cls = require("./cls"); const dateUtils = require("./date_utils"); const LBTPL_ROOT = "lbtpl_root"; +const LBTPL_COMMAND = "lbtpl_command"; const LBTPL_NOTE_SHORTCUT = "lbtpl_noteshortcut"; const LBTPL_SCRIPT = "lbtpl_script"; const LBTPL_BUILTIN_WIDGET = "lbtpl_builtinwidget"; @@ -382,7 +383,7 @@ function createMissingSpecialNotes() { } if (shortcut.command) { - note.addRelation('template', LBTPL_NOTE_SHORTCUT); + note.addRelation('template', LBTPL_COMMAND); note.addLabel('command', shortcut.command); } else if (shortcut.builtinWidget) { if (shortcut.builtinWidget === 'spacer') { @@ -409,17 +410,19 @@ function createMissingSpecialNotes() { } } -function createShortcut(parentNoteId, type) { +function createShortcut(parentNoteId, shortcutType) { let note; - if (type === 'note') { + if (shortcutType === 'note') { note = noteService.createNewNote({ title: "Note shortcut", type: 'shortcut', content: '', parentNoteId: parentNoteId }).note; - } else if (type === 'script') { + + note.addRelation('template', LBTPL_NOTE_SHORTCUT); + } else if (shortcutType === 'script') { note = noteService.createNewNote({ title: "Script shortcut", type: 'shortcut', @@ -427,9 +430,8 @@ function createShortcut(parentNoteId, type) { parentNoteId: parentNoteId }).note; - note.addLabel('relation:script', 'promoted'); - note.addLabel('docName', 'launchbar_script_shortcut'); - } else if (type === 'widget') { + note.addRelation('template', LBTPL_SCRIPT); + } else if (shortcutType === 'customWidget') { note = noteService.createNewNote({ title: "Widget shortcut", type: 'shortcut', @@ -437,9 +439,8 @@ function createShortcut(parentNoteId, type) { parentNoteId: parentNoteId }).note; - note.addLabel('relation:widget', 'promoted'); - note.addLabel('docName', 'launchbar_widget_shortcut'); - } else if (type === 'spacer') { + note.addRelation('template', LBTPL_CUSTOM_WIDGET); + } else if (shortcutType === 'spacer') { note = noteService.createNewNote({ title: "Spacer", type: 'shortcut', @@ -447,15 +448,9 @@ function createShortcut(parentNoteId, type) { parentNoteId: parentNoteId }).note; - note.addLabel('builtinWidget', 'spacer'); - note.addLabel('iconClass', 'bx bx-move-vertical'); - note.addLabel('label:baseSize', 'promoted,number'); - note.addLabel('baseSize', '40'); - note.addLabel('label:growthFactor', 'promoted,number'); - note.addLabel('growthFactor', '0'); - note.addLabel('docName', 'launchbar_spacer'); + note.addRelation('template', LBTPL_SPACER); } else { - throw new Error(`Unrecognized shortcut type ${type}`); + throw new Error(`Unrecognized shortcut type ${shortcutType}`); } return { @@ -476,6 +471,19 @@ function createShortcutTemplates() { }); } + if (!(LBTPL_COMMAND in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_COMMAND, + noteId: LBTPL_COMMAND, + title: 'Command shortcut', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addLabel('shortcutType', 'command'); + } + if (!(LBTPL_NOTE_SHORTCUT in becca.notes)) { const tpl = noteService.createNewNote({ branchId: LBTPL_NOTE_SHORTCUT, @@ -549,7 +557,7 @@ function createShortcutTemplates() { parentNoteId: LBTPL_ROOT }).note; - tpl.addLabel('shortcutType', 'builtinWidget'); + tpl.addLabel('shortcutType', 'customWidget'); tpl.addLabel('relation:widget', 'promoted'); tpl.addLabel('docName', 'launchbar_widget_shortcut'); }