]+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);