launchbar WIP

This commit is contained in:
zadam 2022-08-05 16:44:26 +02:00
parent 7565458332
commit 42cade17cb
24 changed files with 208 additions and 53 deletions

View File

@ -4,7 +4,7 @@ import noteTooltipService from './services/note_tooltip.js';
import bundleService from "./services/bundle.js";
import noteAutocompleteService from './services/note_autocomplete.js';
import macInit from './services/mac_init.js';
import contextMenu from "./services/context_menu.js";
import contextMenu from "./menus/context_menu.js";
import DesktopLayout from "./layouts/desktop_layout.js";
import glob from "./services/glob.js";
import zoomService from './services/zoom.js';

View File

@ -1,4 +1,4 @@
import keyboardActionService from './keyboard_actions.js';
import keyboardActionService from '../services/keyboard_actions.js';
class ContextMenu {
constructor() {

View File

@ -1,5 +1,5 @@
import contextMenu from "./context_menu.js";
import appContext from "./app_context.js";
import appContext from "../services/app_context.js";
function openContextMenu(notePath, e) {
contextMenu.show({

View File

@ -0,0 +1,92 @@
import treeService from '../services/tree.js';
import froca from "../services/froca.js";
import noteCreateService from "../services/note_create.js";
import contextMenu from "./context_menu.js";
import appContext from "../services/app_context.js";
export default class ShortcutContextMenu {
/**
* @param {NoteTreeWidget} treeWidget
* @param {FancytreeNode} node
*/
constructor(treeWidget, node) {
this.treeWidget = treeWidget;
this.node = node;
}
async show(e) {
contextMenu.show({
x: e.pageX,
y: e.pageY,
items: await this.getMenuItems(),
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item, e)
})
}
async getMenuItems() {
const note = await froca.getNote(this.node.data.noteId);
const branch = froca.getBranch(this.node.data.branchId);
const isVisibleRoot = note.noteId === 'lb_visibleshortcuts';
const isAvailableRoot = note.noteId === 'lb_availableshortcuts';
const isVisibleItem = this.node.getParent().data.noteId === 'lb_visibleshortcuts';
const isAvailableItem = this.node.getParent().data.noteId === 'lb_availableshortcuts';
const isItem = isVisibleItem || isAvailableItem;
return [
(isVisibleRoot || isAvailableRoot) ? { title: 'Add note shortcut' } : null,
(isVisibleRoot || isAvailableRoot) ? { title: 'Add widget shortcut' } : null,
(isVisibleRoot || isAvailableRoot) ? { title: 'Add spacer' } : null,
{ title: "----" },
{ title: 'Delete <kbd data-command="deleteNotes"></kbd>', command: "deleteNotes", uiIcon: "bx bx-trash",
enabled: isItem },
{ title: "----" },
isAvailableItem ? { title: 'Move to visible shortcuts', command: "moveNotesTo", uiIcon: "bx bx-empty", enabled: true } : null,
isVisibleItem ? { title: 'Move to available shortcuts', command: "moveNotesTo", uiIcon: "bx bx-empty", enabled: true } : null,
{ title: `Duplicate shortcut <kbd data-command="duplicateSubtree">`, command: "duplicateSubtree", uiIcon: "bx bx-empty",
enabled: isItem }
].filter(row => row !== null);
}
async selectMenuItemHandler({command, type, templateNoteId}) {
const notePath = treeService.getNotePath(this.node);
if (command === 'openInTab') {
appContext.tabManager.openTabWithNoteWithHoisting(notePath);
}
else if (command === "insertNoteAfter") {
const parentNotePath = treeService.getNotePath(this.node.getParent());
const isProtected = await treeService.getParentProtectedStatus(this.node);
noteCreateService.createNote(parentNotePath, {
target: 'after',
targetBranchId: this.node.data.branchId,
type: type,
isProtected: isProtected,
templateNoteId: templateNoteId
});
}
else if (command === "insertChildNote") {
const parentNotePath = treeService.getNotePath(this.node);
noteCreateService.createNote(parentNotePath, {
type: type,
isProtected: this.node.data.isProtected,
templateNoteId: templateNoteId
});
}
else if (command === 'openNoteInSplit') {
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
const {ntxId} = subContexts[subContexts.length - 1];
this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath});
}
else {
this.treeWidget.triggerCommand(command, {
node: this.node,
notePath: notePath,
selectedOrActiveBranchIds: this.treeWidget.getSelectedOrActiveBranchIds(this.node),
selectedOrActiveNoteIds: this.treeWidget.getSelectedOrActiveNoteIds(this.node)
});
}
}
}

View File

@ -1,12 +1,12 @@
import treeService from './tree.js';
import froca from "./froca.js";
import clipboard from './clipboard.js';
import noteCreateService from "./note_create.js";
import treeService from '../services/tree.js';
import froca from "../services/froca.js";
import clipboard from '../services/clipboard.js';
import noteCreateService from "../services/note_create.js";
import contextMenu from "./context_menu.js";
import appContext from "./app_context.js";
import noteTypesService from "./note_types.js";
import appContext from "../services/app_context.js";
import noteTypesService from "../services/note_types.js";
class TreeContextMenu {
export default class TreeContextMenu {
/**
* @param {NoteTreeWidget} treeWidget
* @param {FancytreeNode} node
@ -139,5 +139,3 @@ class TreeContextMenu {
}
}
}
export default TreeContextMenu;

View File

@ -1,5 +1,5 @@
import treeService from './tree.js';
import linkContextMenuService from "./link_context_menu.js";
import linkContextMenuService from "../menus/link_context_menu.js";
import appContext from "./app_context.js";
import froca from "./froca.js";
import utils from "./utils.js";

View File

@ -71,7 +71,9 @@ export default class RootCommandExecutor extends Component {
options.toggle('leftPaneVisible');
}
showLaunchBarShortcutsCommand() {
appContext.tabManager.openContextWithNote('lb_root', true, null, 'lb_root');
async showLaunchBarShortcutsCommand() {
await appContext.tabManager.openContextWithNote('lb_root', true, null, 'lb_root');
}
}

View File

@ -1,7 +1,7 @@
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import noteAutocompleteService from "../../services/note_autocomplete.js";
import server from "../../services/server.js";
import contextMenuService from "../../services/context_menu.js";
import contextMenuService from "../../menus/context_menu.js";
import attributesParser from "../../services/attribute_parser.js";
import libraryLoader from "../../services/library_loader.js";
import froca from "../../services/froca.js";

View File

@ -44,7 +44,7 @@ const DROPDOWN_TPL = `
export default class BookmarkFolderWidget extends RightDropdownButtonWidget {
constructor(note) {
super(note.getIcon(), note.title, DROPDOWN_TPL);
super(note.title, note.getIcon(), DROPDOWN_TPL);
this.note = note;
}

View File

@ -28,8 +28,8 @@ const DROPDOWN_TPL = `
</div>`;
export default class CalendarWidget extends RightDropdownButtonWidget {
constructor() {
super("bx-calendar", "Calendar", DROPDOWN_TPL);
constructor(title, icon) {
super(title, icon, DROPDOWN_TPL);
}
doRender() {

View File

@ -2,6 +2,8 @@ import ButtonWidget from "./button_widget.js";
import appContext from "../../services/app_context.js";
import froca from "../../services/froca.js";
// FIXME: this widget might not be useful anymore
export default class OpenNoteButtonWidget extends ButtonWidget {
targetNote(noteId) {
froca.getNote(noteId).then(note => {

View File

@ -18,7 +18,7 @@ const TPL = `
`;
export default class RightDropdownButtonWidget extends BasicWidget {
constructor(iconClass, title, dropdownTpl) {
constructor(title, iconClass, dropdownTpl) {
super();
this.iconClass = iconClass;

View File

@ -1,6 +1,8 @@
import FlexContainer from "./flex_container.js";
import froca from "../../services/froca.js";
import ButtonWidget from "../buttons/button_widget.js";
import CalendarWidget from "../buttons/calendar.js";
import appContext from "../../services/app_context.js";
export default class ShortcutContainer extends FlexContainer {
constructor() {
@ -18,13 +20,28 @@ export default class ShortcutContainer extends FlexContainer {
const visibleShortcutsRoot = await froca.getNote('lb_visibleshortcuts');
console.log(await visibleShortcutsRoot.getChildNotes());
for (const shortcut of await visibleShortcutsRoot.getChildNotes()) {
this.child(new ButtonWidget()
.icon(shortcut.getLabelValue("iconClass"))
.title(shortcut.title)
.command(shortcut.getLabelValue("command")));
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 {
const builtinWidget = shortcut.getLabelValue("builtinWidget");
if (builtinWidget) {
if (builtinWidget === 'calendar') {
this.child(new CalendarWidget(shortcut.title, shortcut.getIcon()));
} else {
console.log(`Unrecognized builtin widget ${builtinWidget} for shortcut ${shortcut.noteId} "${shortcut.title}"`);
}
}
}
}
this.$widget.empty();
@ -34,8 +51,9 @@ export default class ShortcutContainer extends FlexContainer {
}
entitiesReloadedEvent({loadResults}) {
if (loadResults.getNotes().find(note => note.noteId.startsWith("lb_"))
|| loadResults.getBranches().find(branch => branch.branchId.startsWith("lb_"))) {
if (loadResults.getNoteIds().find(noteId => noteId.startsWith("lb_"))
|| loadResults.getBranches().find(branch => branch.branchId.startsWith("lb_"))
|| loadResults.getAttributes().find(attr => attr.noteId.startsWith("lb_"))) {
this.load();
}
}

View File

@ -1,7 +1,4 @@
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import dialogService from "../dialog.js";
import server from "../../services/server.js";
import toastService from "../../services/toast.js";
const TPL = `
<div>

View File

@ -1,6 +1,6 @@
import BasicWidget from "./basic_widget.js";
import utils from "../services/utils.js";
import contextMenu from "../services/context_menu.js";
import contextMenu from "../menus/context_menu.js";
import treeService from "../services/tree.js";
const TPL = `

View File

@ -1,6 +1,6 @@
import BasicWidget from "../basic_widget.js";
import appContext from "../../services/app_context.js";
import contextMenu from "../../services/context_menu.js";
import contextMenu from "../../menus/context_menu.js";
import noteCreateService from "../../services/note_create.js";
import branchService from "../../services/branches.js";
import treeService from "../../services/tree.js";

View File

@ -4,7 +4,7 @@ import attributeService from "../services/attributes.js";
import hoistedNoteService from "../services/hoisted_note.js";
import appContext from "../services/app_context.js";
import NoteContextAwareWidget from "./note_context_aware_widget.js";
import linkContextMenuService from "../services/link_context_menu.js";
import linkContextMenuService from "../menus/link_context_menu.js";
const TPL = `<div class="note-map-widget" style="position: relative;">
<style>
@ -16,13 +16,13 @@ const TPL = `<div class="note-map-widget" style="position: relative;">
.map-type-switcher {
position: absolute;
top: 10px;
right: 10px;
background-color: var(--accented-background-color);
left: 10px;
z-index: 10; /* should be below dropdown (note actions) */
}
.map-type-switcher .bx {
font-size: 120%;
.map-type-switcher button.bx {
font-size: 130%;
padding: 1px 10px 1px 10px;
}
</style>

View File

@ -1,7 +1,7 @@
import hoistedNoteService from "../services/hoisted_note.js";
import treeService from "../services/tree.js";
import utils from "../services/utils.js";
import contextMenu from "../services/context_menu.js";
import contextMenu from "../menus/context_menu.js";
import froca from "../services/froca.js";
import branchService from "../services/branches.js";
import ws from "../services/ws.js";
@ -87,6 +87,10 @@ const TPL = `
width: 340px;
border-radius: 10px;
}
.tree .hidden-node-is-hidden {
display: none;
}
</style>
<div class="tree"></div>
@ -361,6 +365,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
return false;
}
},
beforeActivate: (event, data) => {
// hidden subtree is hidden hackily, prevent activating it e.g. by keyboard
return data.node.data.noteId !== 'hidden';
},
activate: async (event, data) => {
// click event won't propagate so let's close context menu manually
contextMenu.hide();
@ -569,10 +577,17 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
this.$tree.on('contextmenu', '.fancytree-node', e => {
const node = $.ui.fancytree.getNode(e);
import("../services/tree_context_menu.js").then(({default: TreeContextMenu}) => {
const treeContextMenu = new TreeContextMenu(this, node);
treeContextMenu.show(e);
});
if (hoistedNoteService.getHoistedNoteId() === 'lb_root') {
import("../menus/shortcut_context_menu.js").then(({default: ShortcutContextMenu}) => {
const shortcutContextMenu = new ShortcutContextMenu(this, node);
shortcutContextMenu.show(e);
});
} else {
import("../menus/tree_context_menu.js").then(({default: TreeContextMenu}) => {
const treeContextMenu = new TreeContextMenu(this, node);
treeContextMenu.show(e);
});
}
return false; // blocks default browser right click menu
});
@ -1250,14 +1265,22 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
if (this.noteContext.hoistedNoteId === 'root') {
this.tree.clearFilter();
this.toggleHiddenNode(false); // show everything but the hidden subtree
} else {
// hack when hoisted note is cloned then it could be filtered multiple times while we want only 1
this.tree.filterBranches(node =>
node.data.noteId === this.noteContext.hoistedNoteId // optimization to not having always resolve the node path
&& treeService.getNotePath(node) === hoistedNotePath);
this.toggleHiddenNode(true); // hoisting will handle hidden note visibility
}
}
toggleHiddenNode(show) {
const hiddenNode = this.getNodesByNoteId('hidden')[0];
$(hiddenNode.li).toggleClass("hidden-node-is-hidden", !show);
}
frocaReloadedEvent() {
this.reloadTreeFromCache();
}

View File

@ -1,5 +1,5 @@
import BasicWidget from "./basic_widget.js";
import contextMenu from "../services/context_menu.js";
import contextMenu from "../menus/context_menu.js";
import utils from "../services/utils.js";
import keyboardActionService from "../services/keyboard_actions.js";
import appContext from "../services/app_context.js";

View File

@ -1,7 +1,7 @@
import server from "../../services/server.js";
import linkService from "../../services/link.js";
import libraryLoader from "../../services/library_loader.js";
import contextMenu from "../../services/context_menu.js";
import contextMenu from "../../menus/context_menu.js";
import toastService from "../../services/toast.js";
import attributeAutocompleteService from "../../services/attribute_autocomplete.js";
import TypeWidget from "./type_widget.js";

View File

@ -72,11 +72,11 @@ span.fancytree-node.fancytree-hide {
color: inherit !important;
display: block;
border-radius: 50%;
border-color: #000 transparent #000 transparent;
border-color: var(--main-text-color) transparent var(--main-text-color) transparent;
animation: lds-dual-ring 1.2s linear infinite;
width: 12px;
height: 12px;
margin-top: 4px;
margin-top: 2px;
margin-left: 1px;
border-width: 1px;
border-style: solid;

View File

@ -8,7 +8,8 @@ function setupPage(req, res) {
if (sqlInit.isDbInitialized()) {
if (utils.isElectron()) {
const windowService = require('../services/window');
windowService.createMainWindow();
const {app} = require('electron');
windowService.createMainWindow(app);
windowService.closeSetupWindow();
}
else {

View File

@ -52,13 +52,13 @@ function runNotesWithLabel(runAttrValue) {
sqlInit.dbReady.then(() => {
if (!process.env.TRILIUM_SAFE_MODE) {
cls.init(() => specialNotesService.createMissingSpecialNotes());
setTimeout(cls.wrap(() => runNotesWithLabel('backendStartup')), 10 * 1000);
setInterval(cls.wrap(() => runNotesWithLabel('hourly')), 3600 * 1000);
setInterval(cls.wrap(() => runNotesWithLabel('daily')), 24 * 3600 * 1000);
setTimeout(cls.wrap(() => specialNotesService.createMissingSpecialNotes()), 10 * 1000);
}
setInterval(() => protectedSessionService.checkProtectedSessionExpiration(), 30000);

View File

@ -267,6 +267,12 @@ function getLaunchBarAvailableShortcutsRoot() {
}).note;
}
const branch = becca.getBranch('lb_availableshortcuts');
if (!branch.isExpanded) {
branch.isExpanded = true;
branch.save();
}
return note;
}
@ -284,6 +290,12 @@ function getLaunchBarVisibleShortcutsRoot() {
}).note;
}
const branch = becca.getBranch('lb_visibleshortcuts');
if (!branch.isExpanded) {
branch.isExpanded = true;
branch.save();
}
return note;
}
@ -291,8 +303,9 @@ const shortcuts = [
{ id: 'lb_newnote', command: 'createNoteIntoInbox', title: 'New note', icon: 'bx bx-file-blank', isVisible: true },
{ id: 'lb_search', command: 'searchNotes', title: 'Search notes', icon: 'bx bx-search', isVisible: true },
{ id: 'lb_jumpto', command: 'jumpToNote', title: 'Jump to note', icon: 'bx bx-send', isVisible: true },
{ id: 'lb_notemap', targetNote: 'globalnotemap', title: 'Note map', icon: 'bx bx-map-alt', isVisible: true },
{ id: 'lb_recentchanges', command: 'showRecentChanges', title: 'Show recent changes', icon: 'bx bx-history', isVisible: false }
{ id: 'lb_notemap', targetNoteId: 'globalnotemap', title: 'Note map', icon: 'bx bx-map-alt', isVisible: true },
{ id: 'lb_recentchanges', command: 'showRecentChanges', title: 'Recent changes', icon: 'bx bx-history', isVisible: false },
{ id: 'lb_calendar', builtinWidget: 'calendar', title: 'Calendar', icon: 'bx bx-calendar', isVisible: true },
];
function createMissingSpecialNotes() {
@ -320,7 +333,16 @@ function createMissingSpecialNotes() {
note.addLabel('builtinShortcut');
note.addLabel('iconClass', shortcut.icon);
note.addLabel('command', shortcut.command);
if (shortcut.command) {
note.addLabel('command', shortcut.command);
} else if (shortcut.builtinWidget) {
note.addLabel('builtinWidget', shortcut.builtinWidget);
} else if (shortcut.targetNoteId) {
note.addRelation('targetNote', shortcut.targetNoteId);
} else {
throw new Error(`No action defined for shortcut ${JSON.stringify(shortcut)}`);
}
}
}