From c94346c6b9f670f352fa5df951df45d0bbd9356b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 11 Jan 2025 01:46:00 +0200 Subject: [PATCH] chore(client/ts): port widgets/buttons/launcher --- src/public/app/menus/link_context_menu.ts | 2 +- src/public/app/services/utils.ts | 2 +- ...tract_launcher.js => abstract_launcher.ts} | 24 ++++++++++-------- .../{note_launcher.js => note_launcher.ts} | 25 +++++++++++++------ ...{script_launcher.js => script_launcher.ts} | 8 +++--- .../{today_launcher.js => today_launcher.ts} | 2 +- 6 files changed, 40 insertions(+), 23 deletions(-) rename src/public/app/widgets/buttons/launcher/{abstract_launcher.js => abstract_launcher.ts} (62%) rename src/public/app/widgets/buttons/launcher/{note_launcher.js => note_launcher.ts} (79%) rename src/public/app/widgets/buttons/launcher/{script_launcher.js => script_launcher.ts} (76%) rename src/public/app/widgets/buttons/launcher/{today_launcher.js => today_launcher.ts} (92%) diff --git a/src/public/app/menus/link_context_menu.ts b/src/public/app/menus/link_context_menu.ts index a099f306dc..b2eb973ec1 100644 --- a/src/public/app/menus/link_context_menu.ts +++ b/src/public/app/menus/link_context_menu.ts @@ -3,7 +3,7 @@ import contextMenu from "./context_menu.js"; import appContext from "../components/app_context.js"; import type { ViewScope } from "../services/link.js"; -function openContextMenu(notePath: string, e: PointerEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) { +function openContextMenu(notePath: string, e: PointerEvent | JQuery.ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) { contextMenu.show({ x: e.pageX, y: e.pageY, diff --git a/src/public/app/services/utils.ts b/src/public/app/services/utils.ts index 3d1d72969c..9c7cb2d57a 100644 --- a/src/public/app/services/utils.ts +++ b/src/public/app/services/utils.ts @@ -97,7 +97,7 @@ function isMac() { return navigator.platform.indexOf("Mac") > -1; } -function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent) { +function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent) { return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey); } diff --git a/src/public/app/widgets/buttons/launcher/abstract_launcher.js b/src/public/app/widgets/buttons/launcher/abstract_launcher.ts similarity index 62% rename from src/public/app/widgets/buttons/launcher/abstract_launcher.js rename to src/public/app/widgets/buttons/launcher/abstract_launcher.ts index 0bdb703671..26218daed1 100644 --- a/src/public/app/widgets/buttons/launcher/abstract_launcher.js +++ b/src/public/app/widgets/buttons/launcher/abstract_launcher.ts @@ -1,14 +1,20 @@ import shortcutService from "../../../services/shortcuts.js"; import attributesService from "../../../services/attributes.js"; import OnClickButtonWidget from "../onclick_button.js"; +import type FNote from "../../../entities/fnote.js"; +import type FAttribute from "../../../entities/fattribute.js"; +import type { EventData } from "../../../components/app_context.js"; +import type { AttributeRow } from "../../../services/load_results.js"; -export default class AbstractLauncher extends OnClickButtonWidget { - constructor(launcherNote) { +export default abstract class AbstractLauncher extends OnClickButtonWidget { + + protected launcherNote: FNote; + + constructor(launcherNote: FNote) { super(); this.class("launcher-button"); - /** @type {FNote} */ this.launcherNote = launcherNote; for (const label of launcherNote.getOwnedLabels("keyboardShortcut")) { @@ -16,22 +22,20 @@ export default class AbstractLauncher extends OnClickButtonWidget { } } - launch() { - throw new Error("Abstract implementation"); - } + abstract launch(): void; - bindNoteShortcutHandler(labelOrRow) { + bindNoteShortcutHandler(labelOrRow: FAttribute | AttributeRow) { const namespace = labelOrRow.attributeId; - if (labelOrRow.isDeleted) { + if ("isDeleted" in labelOrRow && labelOrRow.isDeleted) { // only applicable if row shortcutService.removeGlobalShortcut(namespace); - } else { + } else if (labelOrRow.value) { shortcutService.bindGlobalShortcut(labelOrRow.value, () => this.launch(), namespace); } } - entitiesReloadedEvent({ loadResults }) { + entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { for (const attr of loadResults.getAttributeRows()) { if (attr.noteId === this.launcherNote.noteId && attr.type === "label" && attr.name === "keyboardShortcut") { this.bindNoteShortcutHandler(attr); diff --git a/src/public/app/widgets/buttons/launcher/note_launcher.js b/src/public/app/widgets/buttons/launcher/note_launcher.ts similarity index 79% rename from src/public/app/widgets/buttons/launcher/note_launcher.js rename to src/public/app/widgets/buttons/launcher/note_launcher.ts index c06a562f6d..9500210913 100644 --- a/src/public/app/widgets/buttons/launcher/note_launcher.js +++ b/src/public/app/widgets/buttons/launcher/note_launcher.ts @@ -4,6 +4,7 @@ import dialogService from "../../../services/dialog.js"; import appContext from "../../../components/app_context.js"; import utils from "../../../services/utils.js"; import linkContextMenuService from "../../../menus/link_context_menu.js"; +import type FNote from "../../../entities/fnote.js"; // we're intentionally displaying the launcher title and icon instead of the target, // e.g. you want to make launchers to 2 mermaid diagrams which both have mermaid icon (ok), @@ -13,16 +14,17 @@ import linkContextMenuService from "../../../menus/link_context_menu.js"; // The only downside is more work in setting up the typical case // where you actually want to have both title and icon in sync, but for those cases there are bookmarks export default class NoteLauncher extends AbstractLauncher { - constructor(launcherNote) { + constructor(launcherNote: FNote) { super(launcherNote); this.title(() => this.launcherNote.title) .icon(() => this.launcherNote.getIcon()) .onClick((widget, evt) => this.launch(evt)) .onAuxClick((widget, evt) => this.launch(evt)) - .onContextMenu((evt) => { - const targetNoteId = this.getTargetNoteId(); - if (!targetNoteId) { + .onContextMenu(async (evt) => { + let targetNoteId = await Promise.resolve(this.getTargetNoteId()); + + if (!targetNoteId || !evt) { return; } @@ -32,30 +34,39 @@ export default class NoteLauncher extends AbstractLauncher { }); } - async launch(evt) { + async launch(evt?: JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent) { // await because subclass overrides can be async const targetNoteId = await this.getTargetNoteId(); - if (!targetNoteId || evt.which === 3) { + if (!targetNoteId || evt?.which === 3) { return; } const hoistedNoteId = await this.getHoistedNoteId(); + if (!hoistedNoteId) { + return; + } if (!evt) { // keyboard shortcut + // TODO: Fix once tabManager is ported. + //@ts-ignore await appContext.tabManager.openInSameTab(targetNoteId, hoistedNoteId); } else { const ctrlKey = utils.isCtrlKey(evt); if ((evt.which === 1 && ctrlKey) || evt.which === 2) { + // TODO: Fix once tabManager is ported. + //@ts-ignore await appContext.tabManager.openInNewTab(targetNoteId, hoistedNoteId); } else { + // TODO: Fix once tabManager is ported. + //@ts-ignore await appContext.tabManager.openInSameTab(targetNoteId, hoistedNoteId); } } } - getTargetNoteId() { + getTargetNoteId(): void | string | Promise { const targetNoteId = this.launcherNote.getRelationValue("target"); if (!targetNoteId) { diff --git a/src/public/app/widgets/buttons/launcher/script_launcher.js b/src/public/app/widgets/buttons/launcher/script_launcher.ts similarity index 76% rename from src/public/app/widgets/buttons/launcher/script_launcher.js rename to src/public/app/widgets/buttons/launcher/script_launcher.ts index 466ce45eca..8a91e08b1f 100644 --- a/src/public/app/widgets/buttons/launcher/script_launcher.js +++ b/src/public/app/widgets/buttons/launcher/script_launcher.ts @@ -1,7 +1,8 @@ +import type FNote from "../../../entities/fnote.js"; import AbstractLauncher from "./abstract_launcher.js"; export default class ScriptLauncher extends AbstractLauncher { - constructor(launcherNote) { + constructor(launcherNote: FNote) { super(launcherNote); this.title(() => this.launcherNote.title) @@ -14,8 +15,9 @@ export default class ScriptLauncher extends AbstractLauncher { await this.launcherNote.executeScript(); } else { const script = await this.launcherNote.getRelationTarget("script"); - - await script.executeScript(); + if (script) { + await script.executeScript(); + } } } } diff --git a/src/public/app/widgets/buttons/launcher/today_launcher.js b/src/public/app/widgets/buttons/launcher/today_launcher.ts similarity index 92% rename from src/public/app/widgets/buttons/launcher/today_launcher.js rename to src/public/app/widgets/buttons/launcher/today_launcher.ts index dd8dea1a42..838fa41c23 100644 --- a/src/public/app/widgets/buttons/launcher/today_launcher.js +++ b/src/public/app/widgets/buttons/launcher/today_launcher.ts @@ -6,7 +6,7 @@ export default class TodayLauncher extends NoteLauncher { async getTargetNoteId() { const todayNote = await dateNotesService.getTodayNote(); - return todayNote.noteId; + return todayNote?.noteId; } getHoistedNoteId() {