From eecfce3cc96ddf0aecb38706c4413e2002ce0be8 Mon Sep 17 00:00:00 2001 From: zadam Date: Mon, 28 Nov 2022 23:39:23 +0100 Subject: [PATCH] shortcuts use templates --- src/public/app/entities/note_short.js | 2 +- src/public/app/services/attribute_renderer.js | 2 +- src/public/app/services/link.js | 2 +- .../attribute_widgets/attribute_editor.js | 2 +- .../widgets/containers/shortcut_container.js | 141 +++++++++--------- .../type_widgets/abstract_text_type_widget.js | 2 +- src/services/notes.js | 8 +- src/services/special_notes.js | 136 ++++++++++++++--- 8 files changed, 198 insertions(+), 97 deletions(-) diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index d312b68b7..81872e23d 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -22,7 +22,7 @@ const NOTE_TYPE_ICONS = { "canvas": "bx bx-pen", "web-view": "bx bx-globe-alt", "shortcut": "bx bx-up-arrow-circle", - "doc": "bx bx-file-doc" + "doc": "bx bxs-file-doc" }; /** diff --git a/src/public/app/services/attribute_renderer.js b/src/public/app/services/attribute_renderer.js index 913aeb1d2..d8a68d8c5 100644 --- a/src/public/app/services/attribute_renderer.js +++ b/src/public/app/services/attribute_renderer.js @@ -55,7 +55,7 @@ async function createNoteLink(noteId) { } return $("", { - href: '#' + noteId, + href: '#root/' + noteId, class: 'reference-link', 'data-note-path': noteId }) diff --git a/src/public/app/services/link.js b/src/public/app/services/link.js index 276b5b4ff..d586cc678 100644 --- a/src/public/app/services/link.js +++ b/src/public/app/services/link.js @@ -5,7 +5,7 @@ import froca from "./froca.js"; import utils from "./utils.js"; function getNotePathFromUrl(url) { - const notePathMatch = /#(root[A-Za-z0-9/]*)$/.exec(url); + const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url); return notePathMatch === null ? null : notePathMatch[1]; } diff --git a/src/public/app/widgets/attribute_widgets/attribute_editor.js b/src/public/app/widgets/attribute_widgets/attribute_editor.js index cad9c5424..59e8b1906 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_editor.js +++ b/src/public/app/widgets/attribute_widgets/attribute_editor.js @@ -333,7 +333,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { getPreprocessedData() { const str = this.textEditor.getData() - .replace(/]+href="(#[A-Za-z0-9/]*)"[^>]*>[^<]*<\/a>/g, "$1") + .replace(/]+href="(#[A-Za-z0-9_/]*)"[^>]*>[^<]*<\/a>/g, "$1") .replace(/ /g, " "); // otherwise .text() below outputs non-breaking space in unicode return $("
").html(str).text(); diff --git a/src/public/app/widgets/containers/shortcut_container.js b/src/public/app/widgets/containers/shortcut_container.js index 2f5523ced..a7ffaf371 100644 --- a/src/public/app/widgets/containers/shortcut_container.js +++ b/src/public/app/widgets/containers/shortcut_container.js @@ -32,15 +32,10 @@ export default class ShortcutContainer extends FlexContainer { return; } - for (const shortcut of await visibleShortcutsRoot.getChildNotes()) { - try { - await this.initShortcut(shortcut); - } - catch (e) { - console.error(`Initialization of shortcut '${shortcut.noteId}' with title '${shortcut.title}' failed with error: ${e.message} ${e.stack}`); - continue; - } - } + await Promise.allSettled( + (await visibleShortcutsRoot.getChildNotes()) + .map(shortcut => this.initShortcut(shortcut)) + ); this.$widget.empty(); this.renderChildren(); @@ -49,77 +44,87 @@ export default class ShortcutContainer extends FlexContainer { const activeContext = appContext.tabManager.getActiveContext(); - await this.handleEvent('setNoteContext', { - noteContext: activeContext - }); - await this.handleEvent('noteSwitched', { - noteContext: activeContext, - notePath: activeContext.notePath - }); + if (activeContext) { + await this.handleEvent('setNoteContext', { + noteContext: activeContext + }); + + if (activeContext.notePath) { + await this.handleEvent('noteSwitched', { + noteContext: activeContext, + notePath: activeContext.notePath + }); + } + } } async initShortcut(shortcut) { - if (shortcut.type !== 'shortcut') { - console.warn(`Note ${shortcut.noteId} is not a shortcut even though it's in shortcut subtree`); - return; - } + try { + if (shortcut.type !== 'shortcut') { + console.warn(`Note ${shortcut.noteId} is not a shortcut even though it's in shortcut subtree`); + return; + } - if (shortcut.getLabelValue("command")) { - this.child(new ButtonWidget() - .title(shortcut.title) - .icon(shortcut.getIcon()) - .command(shortcut.getLabelValue("command"))); - } else if (shortcut.hasRelation('targetNote')) { - this.child(new ButtonWidget() - .title(shortcut.title) - .icon(shortcut.getIcon()) - .onClick(() => appContext.tabManager.openTabWithNoteWithHoisting(shortcut.getRelationValue('targetNote'), true))); - } else if (shortcut.hasRelation('script')) { - this.child(new ButtonWidget() - .title(shortcut.title) - .icon(shortcut.getIcon()) - .onClick(async () => { - const script = await shortcut.getRelationTarget('script'); + if (shortcut.getLabelValue("command")) { + this.child(new ButtonWidget() + .title(shortcut.title) + .icon(shortcut.getIcon()) + .command(shortcut.getLabelValue("command"))); + } else if (shortcut.hasRelation('targetNote')) { + this.child(new ButtonWidget() + .title(shortcut.title) + .icon(shortcut.getIcon()) + .onClick(() => appContext.tabManager.openTabWithNoteWithHoisting(shortcut.getRelationValue('targetNote'), true))); + } else if (shortcut.hasRelation('script')) { + this.child(new ButtonWidget() + .title(shortcut.title) + .icon(shortcut.getIcon()) + .onClick(async () => { + const script = await shortcut.getRelationTarget('script'); - await script.executeScript(); - })); - } else if (shortcut.hasRelation('widget')) { - const widget = await shortcut.getRelationTarget('widget'); + await script.executeScript(); + })); + } else if (shortcut.hasRelation('widget')) { + const widget = await shortcut.getRelationTarget('widget'); - const res = await widget.executeScript(); + const res = await widget.executeScript(); - this.child(res); - } else { - const builtinWidget = shortcut.getLabelValue("builtinWidget"); + this.child(res); + } else { + const builtinWidget = shortcut.getLabelValue("builtinWidget"); - if (builtinWidget) { - if (builtinWidget === 'calendar') { - this.child(new CalendarWidget(shortcut.title, shortcut.getIcon())); - } else if (builtinWidget === 'spacer') { - // || has to be inside since 0 is a valid value - const baseSize = parseInt(shortcut.getLabelValue("baseSize") || "40"); - const growthFactor = parseInt(shortcut.getLabelValue("growthFactor") || "100"); + if (builtinWidget) { + if (builtinWidget === 'calendar') { + this.child(new CalendarWidget(shortcut.title, shortcut.getIcon())); + } else if (builtinWidget === 'spacer') { + // || has to be inside since 0 is a valid value + const baseSize = parseInt(shortcut.getLabelValue("baseSize") || "40"); + const growthFactor = parseInt(shortcut.getLabelValue("growthFactor") || "100"); - this.child(new SpacerWidget(baseSize, growthFactor)); - } else if (builtinWidget === 'pluginButtons') { - this.child(new FlexContainer("column") - .id("plugin-buttons") - .contentSized()); - } else if (builtinWidget === 'bookmarks') { - this.child(new BookmarkButtons()); - } else if (builtinWidget === 'protectedSession') { - this.child(new ProtectedSessionStatusWidget()); - } else if (builtinWidget === 'syncStatus') { - this.child(new SyncStatusWidget()); - } else if (builtinWidget === 'backInHistoryButton') { - this.child(new BackInHistoryButtonWidget()); - } else if (builtinWidget === 'forwardInHistoryButton') { - this.child(new ForwardInHistoryButtonWidget()); - } else { - console.log(`Unrecognized builtin widget ${builtinWidget} for shortcut ${shortcut.noteId} "${shortcut.title}"`); + this.child(new SpacerWidget(baseSize, growthFactor)); + } else if (builtinWidget === 'pluginButtons') { + this.child(new FlexContainer("column") + .id("plugin-buttons") + .contentSized()); + } else if (builtinWidget === 'bookmarks') { + this.child(new BookmarkButtons()); + } else if (builtinWidget === 'protectedSession') { + this.child(new ProtectedSessionStatusWidget()); + } else if (builtinWidget === 'syncStatus') { + this.child(new SyncStatusWidget()); + } else if (builtinWidget === 'backInHistoryButton') { + this.child(new BackInHistoryButtonWidget()); + } else if (builtinWidget === 'forwardInHistoryButton') { + this.child(new ForwardInHistoryButtonWidget()); + } else { + console.log(`Unrecognized builtin widget ${builtinWidget} for shortcut ${shortcut.noteId} "${shortcut.title}"`); + } } } } + catch (e) { + console.error(`Initialization of shortcut '${shortcut.noteId}' with title '${shortcut.title}' failed with error: ${e.message} ${e.stack}`); + } } entitiesReloadedEvent({loadResults}) { diff --git a/src/public/app/widgets/type_widgets/abstract_text_type_widget.js b/src/public/app/widgets/type_widgets/abstract_text_type_widget.js index e742ec2ef..1e8049b0d 100644 --- a/src/public/app/widgets/type_widgets/abstract_text_type_widget.js +++ b/src/public/app/widgets/type_widgets/abstract_text_type_widget.js @@ -41,7 +41,7 @@ export default class AbstractTextTypeWidget extends TypeWidget { } getNoteIdFromImage(imgSrc) { - const match = imgSrc.match(/\/api\/images\/([A-Za-z0-9]+)\//); + const match = imgSrc.match(/\/api\/images\/([A-Za-z0-9_]+)\//); return match ? match[1] : null; } diff --git a/src/services/notes.js b/src/services/notes.js index 7062cdbcb..486d21364 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -114,7 +114,7 @@ function getAndValidateParent(params) { throw new Error(`Shortcuts should not have child notes.`); } - if (['hidden', 'lb_root'].includes(parentNote.noteId)) { + if (!params.ignoreForbiddenParents && ['lb_root'].includes(parentNote.noteId)) { throw new Error(`Creating child notes into '${parentNote.noteId}' is not allowed.`); } @@ -300,7 +300,7 @@ function protectNote(note, protect) { } function findImageLinks(content, foundLinks) { - const re = /src="[^"]*api\/images\/([a-zA-Z0-9]+)\//g; + const re = /src="[^"]*api\/images\/([a-zA-Z0-9_]+)\//g; let match; while (match = re.exec(content)) { @@ -316,7 +316,7 @@ function findImageLinks(content, foundLinks) { } function findInternalLinks(content, foundLinks) { - const re = /href="[^"]*#root[a-zA-Z0-9\/]*\/([a-zA-Z0-9]+)\/?"/g; + const re = /href="[^"]*#root[a-zA-Z0-9_\/]*\/([a-zA-Z0-9_]+)\/?"/g; let match; while (match = re.exec(content)) { @@ -331,7 +331,7 @@ function findInternalLinks(content, foundLinks) { } function findIncludeNoteLinks(content, foundLinks) { - const re = /
]*>/g; + const re = /
]*>/g; let match; while (match = re.exec(content)) { diff --git a/src/services/special_notes.js b/src/services/special_notes.js index 3aeb0cec8..9754e8d7f 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -5,6 +5,13 @@ const noteService = require("./notes"); const cls = require("./cls"); const dateUtils = require("./date_utils"); +const LBTPL_ROOT = "lbtpl_root"; +const LBTPL_NOTE_SHORTCUT = "lbtpl_noteshortcut"; +const LBTPL_SCRIPT = "lbtpl_script"; +const LBTPL_BUILTIN_WIDGET = "lbtpl_builtinwidget"; +const LBTPL_SPACER = "lbtpl_spacer"; +const LBTPL_CUSTOM_WIDGET = "lbtpl_customwidget"; + function getInboxNote(date) { const hoistedNote = getHoistedNote(); @@ -277,7 +284,8 @@ function getLaunchBarAvailableShortcutsRoot() { title: 'Available shortcuts', type: 'doc', content: '', - parentNoteId: getLaunchBarRoot().noteId + parentNoteId: getLaunchBarRoot().noteId, + ignoreForbiddenParents: true }).note; note.addLabel("iconClass", "bx bx-hide"); @@ -303,7 +311,8 @@ function getLaunchBarVisibleShortcutsRoot() { title: 'Visible shortcuts', type: 'doc', content: '', - parentNoteId: getLaunchBarRoot().noteId + parentNoteId: getLaunchBarRoot().noteId, + ignoreForbiddenParents: true }).note; note.addLabel("iconClass", "bx bx-show"); @@ -326,16 +335,10 @@ const shortcuts = [ { id: 'lb_jumpto', command: 'jumpToNote', title: 'Jump to note', icon: 'bx bx-send', isVisible: true }, { id: 'lb_notemap', targetNoteId: 'globalnotemap', title: 'Note map', icon: 'bx bx-map-alt', isVisible: true }, { id: 'lb_calendar', builtinWidget: 'calendar', title: 'Calendar', icon: 'bx bx-calendar', isVisible: true }, - { id: 'lb_spacer1', builtinWidget: 'spacer', title: 'Spacer', icon: 'bx bx-move-vertical', isVisible: true, labels: [ - { type: "number", name: "baseSize", value: "40" }, - { type: "number", name: "growthFactor", value: "100" }, - ] }, + { id: 'lb_spacer1', builtinWidget: 'spacer', title: 'Spacer', isVisible: true }, { id: 'lb_pluginbuttons', builtinWidget: 'pluginButtons', title: 'Plugin buttons', icon: 'bx bx-extension', isVisible: true }, { id: 'lb_bookmarks', builtinWidget: 'bookmarks', title: 'Bookmarks', icon: 'bx bx-bookmark', isVisible: true }, - { id: 'lb_spacer2', builtinWidget: 'spacer', title: 'Spacer', icon: 'bx bx-move-vertical', isVisible: true, labels: [ - { type: "number", name: "baseSize", value: "40" }, - { type: "number", name: "growthFactor", value: "100" }, - ] }, + { id: 'lb_spacer2', builtinWidget: 'spacer', title: 'Spacer', isVisible: true }, { id: 'lb_protectedsession', builtinWidget: 'protectedSession', title: 'Protected session', icon: 'bx bx bx-shield-quarter', isVisible: true }, { id: 'lb_syncstatus', builtinWidget: 'syncStatus', title: 'Sync status', icon: 'bx bx-wifi', isVisible: true }, @@ -349,6 +352,7 @@ function createMissingSpecialNotes() { getSqlConsoleRoot(); getGlobalNoteMap(); getBulkActionNote(); + createShortcutTemplates(); getLaunchBarRoot(); getLaunchBarAvailableShortcutsRoot(); getLaunchBarVisibleShortcutsRoot(); @@ -373,23 +377,27 @@ function createMissingSpecialNotes() { parentNoteId: parentNoteId }).note; - note.addLabel('builtinShortcut'); - note.addLabel('iconClass', shortcut.icon); + if (shortcut.icon) { + note.addLabel('iconClass', shortcut.icon); + } if (shortcut.command) { + note.addRelation('template', LBTPL_NOTE_SHORTCUT); note.addLabel('command', shortcut.command); } else if (shortcut.builtinWidget) { + if (shortcut.builtinWidget === 'spacer') { + note.addRelation('template', LBTPL_SPACER); + } else { + note.addRelation('template', LBTPL_BUILTIN_WIDGET); + } + note.addLabel('builtinWidget', shortcut.builtinWidget); } else if (shortcut.targetNoteId) { + note.addRelation('template', LBTPL_NOTE_SHORTCUT); note.addRelation('targetNote', shortcut.targetNoteId); } else { throw new Error(`No action defined for shortcut ${JSON.stringify(shortcut)}`); } - - for (const label of shortcut.labels || []) { - note.addLabel('label:' + label.name, "promoted," + label.type); - note.addLabel(label.name, label.value); - } } // share root is not automatically created since it's visible in the tree and many won't need it/use it @@ -411,9 +419,6 @@ function createShortcut(parentNoteId, type) { content: '', parentNoteId: parentNoteId }).note; - - note.addLabel('relation:targetNote', 'promoted'); - note.addLabel('docName', 'launchbar_note_shortcut'); } else if (type === 'script') { note = noteService.createNewNote({ title: "Script shortcut", @@ -459,6 +464,97 @@ function createShortcut(parentNoteId, type) { }; } +function createShortcutTemplates() { + if (!(LBTPL_ROOT in becca.notes)) { + noteService.createNewNote({ + branchId: LBTPL_ROOT, + noteId: LBTPL_ROOT, + title: 'Launch bar templates', + type: 'doc', + content: '', + parentNoteId: getHiddenRoot().noteId + }); + } + + if (!(LBTPL_NOTE_SHORTCUT in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_NOTE_SHORTCUT, + noteId: LBTPL_NOTE_SHORTCUT, + title: 'Note shortcut', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addLabel('shortcutType', 'note'); + tpl.addLabel('relation:targetNote', 'promoted'); + tpl.addLabel('docName', 'launchbar_note_shortcut'); + } + + if (!(LBTPL_SCRIPT in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_SCRIPT, + noteId: LBTPL_SCRIPT, + title: 'Script', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addLabel('shortcutType', 'script'); + tpl.addLabel('relation:script', 'promoted'); + tpl.addLabel('docName', 'launchbar_script_shortcut'); + } + + if (!(LBTPL_BUILTIN_WIDGET in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_BUILTIN_WIDGET, + noteId: LBTPL_BUILTIN_WIDGET, + title: 'Builtin widget', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addLabel('shortcutType', 'builtinWidget'); + } + + if (!(LBTPL_SPACER in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_SPACER, + noteId: LBTPL_SPACER, + title: 'Spacer', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addRelation('template', LBTPL_BUILTIN_WIDGET); + tpl.addLabel('builtinWidget', 'spacer'); + tpl.addLabel('iconClass', 'bx bx-move-vertical'); + tpl.addLabel('label:baseSize', 'promoted,number'); + tpl.addLabel('baseSize', '40'); + tpl.addLabel('label:growthFactor', 'promoted,number'); + tpl.addLabel('growthFactor', '0'); + tpl.addLabel('docName', 'launchbar_spacer'); + } + + if (!(LBTPL_CUSTOM_WIDGET in becca.notes)) { + const tpl = noteService.createNewNote({ + branchId: LBTPL_CUSTOM_WIDGET, + noteId: LBTPL_CUSTOM_WIDGET, + title: 'Custom widget', + type: 'doc', + content: '', + parentNoteId: LBTPL_ROOT + }).note; + + tpl.addLabel('shortcutType', 'builtinWidget'); + tpl.addLabel('relation:widget', 'promoted'); + tpl.addLabel('docName', 'launchbar_widget_shortcut'); + } +} + function resetShortcut(noteId) { if (noteId.startsWith('lb_')) { const note = becca.getNote(noteId);