From 2ad19ddd36777320e9c044a7e0ea118e3b24dcad Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 7 Dec 2022 12:46:41 +0100 Subject: [PATCH] generate hidden subtree declaratively --- src/becca/entities/attribute.js | 9 +- .../buttons/open_note_button_widget.js | 2 +- src/public/app/widgets/containers/launcher.js | 4 +- .../widgets/type_widgets/content_widget.js | 6 +- src/services/hidden_subtree.js | 283 ++++++++++ src/services/scheduler.js | 4 +- src/services/special_notes.js | 490 +----------------- 7 files changed, 306 insertions(+), 492 deletions(-) create mode 100644 src/services/hidden_subtree.js diff --git a/src/becca/entities/attribute.js b/src/becca/entities/attribute.js index d276afc18..8a188e0c7 100644 --- a/src/becca/entities/attribute.js +++ b/src/becca/entities/attribute.js @@ -62,7 +62,6 @@ class Attribute extends AbstractEntity { return this; } - init() { if (this.attributeId) { this.becca.attributes[this.attributeId] = this; @@ -163,11 +162,11 @@ class Attribute extends AbstractEntity { } beforeSaving() { - if (!this.value) { - if (this.type === 'relation') { - throw new Error(`Cannot save relation ${this.name} since it does not target any note.`); + if (this.type === 'relation') { + if (!(this.value in this.becca.notes)) { + throw new Error(`Cannot save relation '${this.name}' since it target not existing note '${this.value}'.`); } - + } else if (!this.value) { // null value isn't allowed this.value = ""; } diff --git a/src/public/app/widgets/buttons/open_note_button_widget.js b/src/public/app/widgets/buttons/open_note_button_widget.js index b38b81f23..f36cc881d 100644 --- a/src/public/app/widgets/buttons/open_note_button_widget.js +++ b/src/public/app/widgets/buttons/open_note_button_widget.js @@ -13,7 +13,7 @@ export default class OpenNoteButtonWidget extends OnClickButtonWidget { if (!this.retried) { this.retried = true; - setTimeout(() => this.targetNote(noteId), 15000); // should be higher than timeout for createMissingSpecialNotes + setTimeout(() => this.targetNote(noteId), 15000); // should be higher than timeout for checkHiddenSubtree } return; diff --git a/src/public/app/widgets/containers/launcher.js b/src/public/app/widgets/containers/launcher.js index 67977437d..61e1c60aa 100644 --- a/src/public/app/widgets/containers/launcher.js +++ b/src/public/app/widgets/containers/launcher.js @@ -14,7 +14,7 @@ import CommandButtonWidget from "../buttons/command_button.js"; export default class LauncherWidget extends BasicWidget { constructor() { super(); - + this.innerWidget = null; } @@ -44,7 +44,7 @@ export default class LauncherWidget extends BasicWidget { } else if (launcherType === 'builtinWidget') { this.innerWidget = this.initBuiltinWidget(note); } else { - throw new Error(`Unrecognized launcher type '${launcherType}' for launcher '${note.noteId}' title ${note.title}`); + throw new Error(`Unrecognized launcher type '${launcherType}' for launcher '${note.noteId}' title '${note.title}'`); } if (!this.innerWidget) { diff --git a/src/public/app/widgets/type_widgets/content_widget.js b/src/public/app/widgets/type_widgets/content_widget.js index 363050337..c8c9ed676 100644 --- a/src/public/app/widgets/type_widgets/content_widget.js +++ b/src/public/app/widgets/type_widgets/content_widget.js @@ -36,12 +36,10 @@ export default class ContentWidgetTypeWidget extends TypeWidget { } async doRefresh(note) { - const contentWidget = note.getLabelValue('contentWidget'); - this.$content.empty(); this.children = []; - const contentWidgets = CONTENT_WIDGETS[contentWidget]; + const contentWidgets = CONTENT_WIDGETS[note.noteId]; if (contentWidgets) { for (const clazz of contentWidgets) { @@ -54,7 +52,7 @@ export default class ContentWidgetTypeWidget extends TypeWidget { await widget.refresh(); } } else { - this.$content.append(`Unknown widget of type "${contentWidget}"`); + this.$content.append(`Unknown widget for "${note.noteId}"`); } } } diff --git a/src/services/hidden_subtree.js b/src/services/hidden_subtree.js new file mode 100644 index 000000000..c905cf135 --- /dev/null +++ b/src/services/hidden_subtree.js @@ -0,0 +1,283 @@ +const becca = require("../becca/becca"); +const noteService = require("./notes"); +const log = require("./log.js"); + +const LBTPL_ROOT = "lbTplRoot"; +const LBTPL_BASE = "lbTplBase"; +const LBTPL_COMMAND = "lbTplCommand"; +const LBTPL_NOTE_LAUNCHER = "lbTplNoteLauncher"; +const LBTPL_SCRIPT = "lbTplScript"; +const LBTPL_BUILTIN_WIDGET = "lbTplBuiltinWidget"; +const LBTPL_SPACER = "lbTplSpacer"; +const LBTPL_CUSTOM_WIDGET = "lbTplCustomWidget"; + +const HIDDEN_SUBTREE_DEFINITION = { + id: 'hidden', + title: 'hidden', + type: 'doc', + icon: 'bx bx-chip', + // we want to keep the hidden subtree always last, otherwise there will be problems with e.g. keyboard navigation + // over tree when it's in the middle + notePosition: 999_999_999, + attributes: [ + // isInheritable: false means that this notePath is automatically not preffered but at the same time + // the flag is not inherited to the children + { type: 'label', name: 'archived' }, + { type: 'label', name: 'excludeFromNoteMap', isInheritable: true } + ], + children: [ + { + id: 'search', + title: 'search', + type: 'doc' + }, + { + id: 'globalNoteMap', + title: 'Note Map', + type: 'noteMap', + attributes: [ + { type: 'label', name: 'mapRootId', value: 'hoisted' } + ] + }, + { + id: 'sqlConsole', + title: 'SQL Console', + type: 'doc', + icon: 'bx-data' + }, + { + id: 'share', + title: 'Shared Notes', + type: 'doc', + attributes: [ { type: 'label', name: 'docName', value: 'share' } ] + }, + { + id: 'bulkAction', + title: 'Bulk action', + type: 'doc', + }, + { + id: LBTPL_ROOT, + title: 'Launch Bar Templates', + type: 'doc', + children: [ + { + id: LBTPL_BASE, + title: 'Base Abstract Launcher', + type: 'doc' + }, + { + id: LBTPL_COMMAND, + title: 'Command Launcher', + type: 'doc', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BASE }, + { type: 'label', name: 'launcherType', value: 'command' }, + { type: 'label', name: 'docName', value: 'launchbar_command_launcher' } + ] + }, + { + id: LBTPL_NOTE_LAUNCHER, + title: 'Note Launcher', + type: 'doc', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BASE }, + { type: 'label', name: 'launcherType', value: 'note' }, + { type: 'label', name: 'relation:targetNote', value: 'promoted' }, + { type: 'label', name: 'label:keyboardShortcut', value: 'promoted,text' }, + { type: 'label', name: 'docName', value: 'launchbar_note_launcher' } + ] + }, + { + id: LBTPL_SCRIPT, + title: 'Script Launcher', + type: 'doc', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BASE }, + { type: 'label', name: 'launcherType', value: 'script' }, + { type: 'label', name: 'relation:script', value: 'promoted' }, + { type: 'label', name: 'label:keyboardShortcut', value: 'promoted,text' }, + { type: 'label', name: 'docName', value: 'launchbar_script_launcher' } + ] + }, + { + id: LBTPL_BUILTIN_WIDGET, + title: 'Built-in Widget', + type: 'doc', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BASE }, + { type: 'label', name: 'launcherType', value: 'builtinWidget' } + ] + }, + { + id: LBTPL_SPACER, + title: 'Spacer', + type: 'doc', + icon: 'bx-move-vertical', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BUILTIN_WIDGET }, + { type: 'label', name: 'builtinWidget', value: 'spacer' }, + { type: 'label', name: 'label:baseSize', value: 'promoted,number' }, + { type: 'label', name: 'label:growthFactor', value: 'promoted,number' }, + { type: 'label', name: 'docName', value: 'launchbar_spacer' } + ] + }, + { + id: LBTPL_CUSTOM_WIDGET, + title: 'Custom Widget', + type: 'doc', + attributes: [ + { type: 'relation', name: 'template', value: LBTPL_BASE }, + { type: 'label', name: 'launcherType', value: 'customWidget' }, + { type: 'label', name: 'relation:widget', value: 'promoted' }, + { type: 'label', name: 'docName', value: 'launchbar_widget_launcher' } + ] + }, + ] + }, + { + id: 'lbRoot', + title: 'Launch bar', + type: 'doc', + icon: 'bx-sidebar', + isExpanded: true, + attributes: [ { type: 'label', name: 'docName', value: 'launchbar_intro' } ], + children: [ + { + id: 'lbAvailableLaunchers', + title: 'Available Launchers', + type: 'doc', + icon: 'bx-hide', + isExpanded: true, + attributes: [ { type: 'label', name: 'docName', value: 'launchbar_intro' } ], + children: [ + { id: 'lbBackInHistory', title: 'Back in history', type: 'launcher', builtinWidget: 'backInHistoryButton', icon: 'bx bxs-left-arrow-square' }, + { id: 'lbForwardInHistory', title: 'Forward in history', type: 'launcher', builtinWidget: 'forwardInHistoryButton', icon: 'bx bxs-right-arrow-square' }, + ] + }, + { + id: 'lbVisibleLaunchers', + title: 'Visible Launchers', + type: 'doc', + icon: 'bx-show', + isExpanded: true, + attributes: [ { type: 'label', name: 'docName', value: 'launchbar_intro' } ], + children: [ + { id: 'lbNewNote', title: 'New Note', type: 'launcher', command: 'createNoteIntoInbox', icon: 'bx bx-file-blank' }, + { id: 'lbSearch', title: 'Search Notes', type: 'launcher', command: 'searchNotes', icon: 'bx bx-search' }, + { id: 'lbJumpTo', title: 'Jump to Note', type: 'launcher', command: 'jumpToNote', icon: 'bx bx-send' }, + { id: 'lbNoteMap', title: 'Note Map', type: 'launcher', targetNoteId: 'globalNoteMap', icon: 'bx bx-map-alt' }, + { id: 'lbCalendar', title: 'Calendar', type: 'launcher', builtinWidget: 'calendar', icon: 'bx bx-calendar' }, + { id: 'lbRecentChanges', title: 'Recent Changes', type: 'launcher', command: 'showRecentChanges', icon: 'bx bx-history' }, + { id: 'lbSpacer1', title: 'Spacer', type: 'launcher', builtinWidget: 'spacer', baseSize: "50", growthFactor: "0" }, + { id: 'lbBookmarks', title: 'Bookmarks', type: 'launcher', builtinWidget: 'bookmarks', icon: 'bx bx-bookmark' }, + { id: 'lbSpacer2', title: 'Spacer', type: 'launcher', builtinWidget: 'spacer', baseSize: "0", growthFactor: "1" }, + { id: 'lbProtectedSession', title: 'Protected Session', type: 'launcher', builtinWidget: 'protectedSession', icon: 'bx bx bx-shield-quarter' }, + { id: 'lbSyncStatus', title: 'Sync Status', type: 'launcher', builtinWidget: 'syncStatus', icon: 'bx bx-wifi' } + ] + } + ] + }, + { + id: 'options', + title: 'Options', + type: 'book', + children: [ + { id: 'optionsAppearance', title: 'Appearance', type: 'contentWidget' }, + { id: 'optionsShortcuts', title: 'Shortcuts', type: 'contentWidget' }, + { id: 'optionsTextNotes', title: 'Text Notes', type: 'contentWidget' }, + { id: 'optionsCodeNotes', title: 'Code Notes', type: 'contentWidget' }, + { id: 'optionsImages', title: 'Images', type: 'contentWidget' }, + { id: 'optionsSpellcheck', title: 'Spellcheck', type: 'contentWidget' }, + { id: 'optionsPassword', title: 'Password', type: 'contentWidget' }, + { id: 'optionsEtapi', title: 'ETAPI', type: 'contentWidget' }, + { id: 'optionsBackup', title: 'Backup', type: 'contentWidget' }, + { id: 'optionsSync', title: 'Sync', type: 'contentWidget' }, + { id: 'optionsOther', title: 'Other', type: 'contentWidget' }, + { id: 'optionsAdvanced', title: 'Advanced', type: 'contentWidget' } + ] + } + ] +}; + +function checkHiddenSubtree() { + checkHiddenSubtreeRecursively('root', HIDDEN_SUBTREE_DEFINITION); +} + +function checkHiddenSubtreeRecursively(parentNoteId, item) { + if (!item.id || !item.type || !item.title) { + throw new Error(`Item does not contain mandatory properties: ` + JSON.stringify(item)); + } + + let note = becca.notes[item.id]; + let branch = becca.branches[item.id]; + + const attrs = [...(item.attributes || [])]; + + if (item.icon) { + attrs.push({ type: 'label', name: 'iconClass', value: 'bx ' + item.icon }); + } + + if (!note) { + ({note, branch} = noteService.createNewNote({ + branchId: item.id, + noteId: item.id, + title: item.title, + type: item.type, + parentNoteId: parentNoteId, + content: '', + ignoreForbiddenParents: true + })); + + if (item.type === 'launcher') { + if (item.command) { + attrs.push({ type: 'relation', name: 'template', value: LBTPL_COMMAND }); + attrs.push({ type: 'label', name: 'command', value: item.command }); + } else if (item.builtinWidget) { + if (item.builtinWidget === 'spacer') { + attrs.push({ type: 'relation', name: 'template', value: LBTPL_SPACER }); + attrs.push({ type: 'label', name: 'baseSize', value: item.baseSize }); + attrs.push({ type: 'label', name: 'growthFactor', value: item.growthFactor }); + } else { + attrs.push({ type: 'relation', name: 'template', value: LBTPL_BUILTIN_WIDGET }); + } + + attrs.push({ type: 'label', name: 'builtinWidget', value: item.builtinWidget }); + } else if (item.targetNoteId) { + attrs.push({ type: 'relation', name: 'template', value: LBTPL_NOTE_LAUNCHER }); + attrs.push({ type: 'relation', name: 'targetNote', value: item.targetNoteId }); + } else { + throw new Error(`No action defined for launcher ${JSON.stringify(item)}`); + } + } + } + + if (!branch) { + // not sure if there's some better way to recover + log.error(`Cannot find branch id='${item.id}', ignoring...`); + } else { + if (item.notePosition !== undefined && branch.notePosition !== item.notePosition) { + branch.notePosition = item.notePosition; + branch.save(); + } + + if (item.isExpanded !== undefined && branch.isExpanded !== item.isExpanded) { + branch.isExpanded = item.isExpanded; + branch.save(); + } + } + + for (const attr of attrs) { + if (!note.hasAttribute(attr.type, attr.name)) { + note.addAttribute(attr.type, attr.name, attr.value); + } + } + + for (const child of item.children || []) { + checkHiddenSubtreeRecursively(item.id, child); + } +} + +module.exports = { + checkHiddenSubtree +}; diff --git a/src/services/scheduler.js b/src/services/scheduler.js index 20b964802..70dc23589 100644 --- a/src/services/scheduler.js +++ b/src/services/scheduler.js @@ -5,8 +5,8 @@ const config = require('./config'); const log = require('./log'); const sql = require("./sql"); const becca = require("../becca/becca"); -const specialNotesService = require("../services/special_notes"); const protectedSessionService = require("../services/protected_session"); +const hiddenSubtreeService = require("./hidden_subtree"); function getRunAtHours(note) { try { @@ -52,7 +52,7 @@ function runNotesWithLabel(runAttrValue) { sqlInit.dbReady.then(() => { if (!process.env.TRILIUM_SAFE_MODE) { - cls.init(() => specialNotesService.createMissingSpecialNotes()); + cls.init(() => hiddenSubtreeService.checkHiddenSubtree()); setTimeout(cls.wrap(() => runNotesWithLabel('backendStartup')), 10 * 1000); diff --git a/src/services/special_notes.js b/src/services/special_notes.js index edcf6a044..5e318bd11 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -5,15 +5,7 @@ const noteService = require("./notes"); const cls = require("./cls"); const dateUtils = require("./date_utils"); const log = require("./log.js"); - -const LBTPL_ROOT = "lbtpl_root"; -const LBTPL_BASE = "lbtpl_base"; -const LBTPL_COMMAND = "lbtpl_command"; -const LBTPL_NOTE_LAUNCHER = "lbtpl_notelauncher"; -const LBTPL_SCRIPT = "lbtpl_script"; -const LBTPL_BUILTIN_WIDGET = "lbtpl_builtinwidget"; -const LBTPL_SPACER = "lbtpl_spacer"; -const LBTPL_CUSTOM_WIDGET = "lbtpl_customwidget"; +const hiddenSubtreeService = require("./hidden_subtree"); function getInboxNote(date) { const hoistedNote = getHoistedNote(); @@ -39,97 +31,9 @@ function getInboxNote(date) { return inbox; } -function getHiddenRoot() { - let hidden = becca.getNote('hidden'); - - if (!hidden) { - hidden = noteService.createNewNote({ - branchId: 'hidden', - noteId: 'hidden', - title: 'hidden', - type: 'doc', - content: '', - parentNoteId: 'root' - }).note; - - // isInheritable: false means that this notePath is automatically not preffered but at the same time - // the flag is not inherited to the children - hidden.addLabel('archived', "", false); - hidden.addLabel('excludeFromNoteMap', "", true); - hidden.addLabel('iconClass', "bx bx-chip", false); - } - - const MAX_POS = 999_999_999; - - const branch = hidden.getBranches()[0]; - if (branch.notePosition !== MAX_POS) { - // we want to keep the hidden subtree always last, otherwise there will be problems with e.g. keyboard navigation - // over tree when it's in the middle - branch.notePosition = MAX_POS; - branch.save(); - } - - return hidden; -} - -function getSearchRoot() { - let searchRoot = becca.getNote('search'); - - if (!searchRoot) { - searchRoot = noteService.createNewNote({ - branchId: 'search', - noteId: 'search', - title: 'search', - type: 'doc', - content: '', - parentNoteId: getHiddenRoot().noteId - }).note; - } - - return searchRoot; -} - -function getGlobalNoteMap() { - let globalNoteMap = becca.getNote('globalNoteMap'); - - if (!globalNoteMap) { - globalNoteMap = noteService.createNewNote({ - branchId: 'globalNoteMap', - noteId: 'globalNoteMap', - title: 'Global Note Map', - type: 'noteMap', - content: '', - parentNoteId: getHiddenRoot().noteId - }).note; - - globalNoteMap.addLabel('mapRootNoteId', 'hoisted'); - } - - return globalNoteMap; -} - -function getSqlConsoleRoot() { - let sqlConsoleRoot = becca.getNote('sqlConsole'); - - if (!sqlConsoleRoot) { - sqlConsoleRoot = noteService.createNewNote({ - branchId: 'sqlConsole', - noteId: 'sqlConsole', - title: 'SQL Console', - type: 'doc', - content: '', - parentNoteId: getHiddenRoot().noteId - }).note; - - sqlConsoleRoot.addLabel('iconClass', 'bx bx-data'); - } - - return sqlConsoleRoot; -} - function createSqlConsole() { const {note} = noteService.createNewNote({ - parentNoteId: getSqlConsoleRoot().noteId, + parentNoteId: 'sqlConsole', title: 'SQL Console', content: "SELECT title, isDeleted, isProtected FROM notes WHERE noteId = ''\n\n\n\n", type: 'code', @@ -163,7 +67,7 @@ function saveSqlConsole(sqlConsoleNoteId) { function createSearchNote(searchString, ancestorNoteId) { const {note} = noteService.createNewNote({ - parentNoteId: getSearchRoot().noteId, + parentNoteId: 'search', title: 'Search: ' + searchString, content: "", type: 'search', @@ -213,215 +117,36 @@ function getHoistedNote() { return becca.getNote(cls.getHoistedNoteId()); } -function getShareRoot() { - let shareRoot = becca.getNote('share'); - - if (!shareRoot) { - const hiddenRoot = getHiddenRoot(); - - shareRoot = noteService.createNewNote({ - branchId: 'share', - noteId: 'share', - title: 'Shared notes', - type: 'doc', - content: '', - parentNoteId: hiddenRoot.noteId - }).note; - } - - if (!shareRoot.hasOwnedLabel("docName")) { - shareRoot.addLabel("docName", "share"); - } - - return shareRoot; -} - -function getBulkActionNote() { - let bulkActionNote = becca.getNote('bulkAction'); - - if (!bulkActionNote) { - bulkActionNote = noteService.createNewNote({ - branchId: 'bulkAction', - noteId: 'bulkAction', - title: 'Bulk action', - type: 'text', - content: '', - parentNoteId: getHiddenRoot().noteId - }).note; - } - - return bulkActionNote; -} - -function getLaunchBarRoot() { - let note = becca.getNote('lbRoot'); - - if (!note) { - note = noteService.createNewNote({ - branchId: 'lbRoot', - noteId: 'lbRoot', - title: 'Launch bar', - type: 'doc', - content: '', - parentNoteId: getHiddenRoot().noteId - }).note; - - note.addLabel("iconClass", "bx bx-sidebar"); - note.addLabel("docName", "launchbar_intro"); - } - - return note; -} - -function getLaunchBarAvailableLaunchersRoot() { - let note = becca.getNote('lbAvailableLaunchers'); - - if (!note) { - note = noteService.createNewNote({ - branchId: 'lbAvailableLaunchers', - noteId: 'lbAvailableLaunchers', - title: 'Available launchers', - type: 'doc', - content: '', - parentNoteId: getLaunchBarRoot().noteId, - ignoreForbiddenParents: true - }).note; - - note.addLabel("iconClass", "bx bx-hide"); - note.addLabel("docName", "launchbar_intro"); - } - - const branch = becca.getBranch('lbAvailableLaunchers'); - if (!branch.isExpanded) { - branch.isExpanded = true; - branch.save(); - } - - return note; -} - -function getLaunchBarVisibleLaunchersRoot() { - let note = becca.getNote('lbVisibleLaunchers'); - - if (!note) { - note = noteService.createNewNote({ - branchId: 'lbVisibleLaunchers', - noteId: 'lbVisibleLaunchers', - title: 'Visible launchers', - type: 'doc', - content: '', - parentNoteId: getLaunchBarRoot().noteId, - ignoreForbiddenParents: true - }).note; - - note.addLabel("iconClass", "bx bx-show"); - note.addLabel("docName", "launchbar_intro"); - } - - const branch = becca.getBranch('lbVisibleLaunchers'); - if (!branch.isExpanded) { - branch.isExpanded = true; - branch.save(); - } - - return note; -} - -const launchers = [ - // visible launchers: - { id: 'lbNewNote', command: 'createNoteIntoInbox', title: 'New note', icon: 'bx bx-file-blank', isVisible: true }, - { id: 'lbSearch', command: 'searchNotes', title: 'Search notes', icon: 'bx bx-search', isVisible: true }, - { id: 'lbJumpTo', command: 'jumpToNote', title: 'Jump to note', icon: 'bx bx-send', isVisible: true }, - { id: 'lbNoteMap', targetNoteId: 'globalNotemap', title: 'Note map', icon: 'bx bx-map-alt', isVisible: true }, - { id: 'lbCalendar', builtinWidget: 'calendar', title: 'Calendar', icon: 'bx bx-calendar', isVisible: true }, - { id: 'lbSpacer1', builtinWidget: 'spacer', title: 'Spacer', isVisible: true, baseSize: "50", growthFactor: "0" }, - { id: 'lbBookmarks', builtinWidget: 'bookmarks', title: 'Bookmarks', icon: 'bx bx-bookmark', isVisible: true }, - { id: 'lbSpacer2', builtinWidget: 'spacer', title: 'Spacer', isVisible: true, baseSize: "0", growthFactor: "1" }, - { id: 'lbProtectedSession', builtinWidget: 'protectedSession', title: 'Protected session', icon: 'bx bx bx-shield-quarter', isVisible: true }, - { id: 'lbSyncStatus', builtinWidget: 'syncStatus', title: 'Sync status', icon: 'bx bx-wifi', isVisible: true }, - - // available launchers: - { id: 'lbRecentChanges', command: 'showRecentChanges', title: 'Recent changes', icon: 'bx bx-history', isVisible: false }, - { id: 'lbBackInHistory', builtinWidget: 'backInHistoryButton', title: 'Back in history', icon: 'bx bxs-left-arrow-square', isVisible: false }, - { id: 'lbForwardInHistory', builtinWidget: 'forwardInHistoryButton', title: 'Forward in history', icon: 'bx bxs-right-arrow-square', isVisible: false }, -]; - -function createLaunchers() { - for (const launcher of launchers) { - let note = becca.getNote(launcher.id); - - if (note) { - continue; - } - - const parentNoteId = launcher.isVisible - ? getLaunchBarVisibleLaunchersRoot().noteId - : getLaunchBarAvailableLaunchersRoot().noteId; - - note = noteService.createNewNote({ - noteId: launcher.id, - title: launcher.title, - type: 'launcher', - content: '', - parentNoteId: parentNoteId - }).note; - - if (launcher.icon) { - note.addLabel('iconClass', launcher.icon); - } - - if (launcher.command) { - note.addRelation('template', LBTPL_COMMAND); - note.addLabel('command', launcher.command); - } else if (launcher.builtinWidget) { - if (launcher.builtinWidget === 'spacer') { - note.addRelation('template', LBTPL_SPACER); - note.addLabel("baseSize", launcher.baseSize); - note.addLabel("growthFactor", launcher.growthFactor); - } else { - note.addRelation('template', LBTPL_BUILTIN_WIDGET); - } - - note.addLabel('builtinWidget', launcher.builtinWidget); - } else if (launcher.targetNoteId) { - note.addRelation('template', LBTPL_NOTE_LAUNCHER); - note.addRelation('targetNote', launcher.targetNoteId); - } else { - throw new Error(`No action defined for launcher ${JSON.stringify(launcher)}`); - } - } -} - function createLauncher(parentNoteId, launcherType) { let note; if (launcherType === 'note') { note = noteService.createNewNote({ - title: "Note launcher", + title: "Note Launcher", type: 'launcher', content: '', parentNoteId: parentNoteId }).note; - note.addRelation('template', LBTPL_NOTE_LAUNCHER); + note.addRelation('template', 'lbTplNoteLauncher'); } else if (launcherType === 'script') { note = noteService.createNewNote({ - title: "Script launcher", + title: "Script Launcher", type: 'launcher', content: '', parentNoteId: parentNoteId }).note; - note.addRelation('template', LBTPL_SCRIPT); + note.addRelation('template', 'lbTplScriptLauncher'); } else if (launcherType === 'customWidget') { note = noteService.createNewNote({ - title: "Widget launcher", + title: "Widget Launcher", type: 'launcher', content: '', parentNoteId: parentNoteId }).note; - note.addRelation('template', LBTPL_CUSTOM_WIDGET); + note.addRelation('template', 'lbTplCustomWidget'); } else if (launcherType === 'spacer') { note = noteService.createNewNote({ title: "Spacer", @@ -430,9 +155,9 @@ function createLauncher(parentNoteId, launcherType) { parentNoteId: parentNoteId }).note; - note.addRelation('template', LBTPL_SPACER); + note.addRelation('template', 'lbTplSpacer'); } else { - throw new Error(`Unrecognized launcher type ${launcherType}`); + throw new Error(`Unrecognized launcher type '${launcherType}'`); } return { @@ -441,193 +166,6 @@ function createLauncher(parentNoteId, launcherType) { }; } -function initHiddenRoot() { - const hidden = getHiddenRoot(); - - if (!hidden.hasOwnedLabel("docName")) { - hidden.addLabel("docName", "hidden"); - } - - if (!hidden.hasOwnedLabel('excludeFromNoteMap')) { - hidden.addLabel('excludeFromNoteMap', "", true); - } -} - -function createLauncherTemplates() { - 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_BASE in becca.notes)) { - noteService.createNewNote({ - branchId: LBTPL_BASE, - noteId: LBTPL_BASE, - title: 'Launch bar base launcher', - type: 'doc', - content: '', - parentNoteId: LBTPL_ROOT - }); - } - - if (!(LBTPL_COMMAND in becca.notes)) { - const tpl = noteService.createNewNote({ - branchId: LBTPL_COMMAND, - noteId: LBTPL_COMMAND, - title: 'Command launcher', - type: 'doc', - content: '', - parentNoteId: LBTPL_ROOT - }).note; - - tpl.addRelation('template', LBTPL_BASE); - tpl.addLabel('launcherType', 'command'); - tpl.addLabel('docName', 'launchbar_command_launcher'); - } - - if (!(LBTPL_NOTE_LAUNCHER in becca.notes)) { - const tpl = noteService.createNewNote({ - branchId: LBTPL_NOTE_LAUNCHER, - noteId: LBTPL_NOTE_LAUNCHER, - title: 'Note launcher', - type: 'doc', - content: '', - parentNoteId: LBTPL_ROOT - }).note; - - tpl.addRelation('template', LBTPL_BASE); - tpl.addLabel('launcherType', 'note'); - tpl.addLabel('relation:targetNote', 'promoted'); - tpl.addLabel('docName', 'launchbar_note_launcher'); - tpl.addLabel('label:keyboardShortcut', 'promoted,text'); - } - - 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.addRelation('template', LBTPL_BASE); - tpl.addLabel('launcherType', 'script'); - tpl.addLabel('relation:script', 'promoted'); - tpl.addLabel('docName', 'launchbar_script_launcher'); - tpl.addLabel('label:keyboardShortcut', 'promoted,text'); - } - - 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.addRelation('template', LBTPL_BASE); - tpl.addLabel('launcherType', '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('label:growthFactor', 'promoted,number'); - 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.addRelation('template', LBTPL_BASE); - tpl.addLabel('launcherType', 'customWidget'); - tpl.addLabel('relation:widget', 'promoted'); - tpl.addLabel('docName', 'launchbar_widget_launcher'); - } -} - -const OPTIONS_ROOT = "opt_root"; -const OPTIONS_APPEARANCE = "opt_appearance"; -const OPTIONS_ADVANCED = "opt_advanced"; -const OPTIONS_BACKUP = "opt_backup"; -const OPTIONS_CODE_NOTES = "opt_code_notes"; -const OPTIONS_ETAPI = "opt_etapi"; -const OPTIONS_IMAGES = "opt_images"; -const OPTIONS_OTHER = "opt_other"; -const OPTIONS_PASSWORD = "opt_password"; -const OPTIONS_SHORTCUTS = "opt_shortcuts"; -const OPTIONS_SPELLCHECK = "opt_spellcheck"; -const OPTIONS_SYNC = "opt_sync"; -const OPTIONS_TEXT_NOTES = "opt_textnotes"; - -function createOptionNotes() { - if (!(OPTIONS_ROOT in becca.notes)) { - noteService.createNewNote({ - branchId: OPTIONS_ROOT, - noteId: OPTIONS_ROOT, - title: 'Options', - type: 'book', - content: '', - parentNoteId: getHiddenRoot().noteId - }); - } - - if (!(OPTIONS_APPEARANCE in becca.notes)) { - const note = noteService.createNewNote({ - branchId: OPTIONS_APPEARANCE, - noteId: OPTIONS_APPEARANCE, - title: 'Appearance', - type: 'contentWidget', - content: '', - parentNoteId: OPTIONS_ROOT - }).note; - - note.addLabel('contentWidget', 'optionsAppearance'); - } -} - -function createMissingSpecialNotes() { - initHiddenRoot(); - getSqlConsoleRoot(); - getGlobalNoteMap(); - getBulkActionNote(); - createLauncherTemplates(); - getLaunchBarRoot(); - getLaunchBarAvailableLaunchersRoot(); - getLaunchBarVisibleLaunchersRoot(); - createLaunchers(); - createOptionNotes(); - getShareRoot(); -} - function resetLauncher(noteId) { const note = becca.getNote(noteId); @@ -648,7 +186,7 @@ function resetLauncher(noteId) { log.info(`Note ${noteId} is not a resettable launcher note.`); } - createMissingSpecialNotes(); + hiddenSubtreeService.checkHiddenSubtree(); } module.exports = { @@ -657,10 +195,6 @@ module.exports = { saveSqlConsole, createSearchNote, saveSearchNote, - createMissingSpecialNotes, - getShareRoot, - getHiddenRoot, - getBulkActionNote, createLauncher, resetLauncher };