You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-10 22:11:50 +02:00
Plugins: Added the webviewApi.menuPopupFromTemplate() API to create context menus
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import ElectronAppWrapper from './ElectronAppWrapper';
|
||||
import shim, { MessageBoxType } from '@joplin/lib/shim';
|
||||
import { _, setLocale } from '@joplin/lib/locale';
|
||||
import { BrowserWindow, nativeTheme, nativeImage, shell, dialog, MessageBoxSyncOptions, safeStorage } from 'electron';
|
||||
import { BrowserWindow, nativeTheme, nativeImage, shell, dialog, MessageBoxSyncOptions, safeStorage, Menu, MenuItemConstructorOptions, MenuItem } from 'electron';
|
||||
import { dirname, toSystemSlashes } from '@joplin/lib/path-utils';
|
||||
import { fileUriToPath } from '@joplin/utils/url';
|
||||
import { urlDecode } from '@joplin/lib/string-utils';
|
||||
@@ -602,6 +602,11 @@ export class Bridge {
|
||||
return nativeImage.createFromPath(path);
|
||||
}
|
||||
|
||||
public menuPopupFromTemplate(template: ((MenuItemConstructorOptions) | (MenuItem))[]) {
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
return menu.popup({ window: this.mainWindow() });
|
||||
}
|
||||
|
||||
public safeStorage = {
|
||||
isEncryptionAvailable() {
|
||||
return safeStorage.isEncryptionAvailable();
|
||||
|
@@ -33,6 +33,13 @@
|
||||
target: 'postMessageService.registerViewMessageHandler',
|
||||
});
|
||||
},
|
||||
|
||||
menuPopupFromTemplate: (args) => {
|
||||
postMessage({
|
||||
target: 'webviewApi.menuPopupFromTemplate',
|
||||
args,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
function docReady(fn) {
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import PostMessageService, { MessageResponse, ResponderComponentType } from '@joplin/lib/services/PostMessageService';
|
||||
import { RefObject, useEffect } from 'react';
|
||||
|
||||
import bridge from '../../bridge';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
import { MenuItemConstructorOptions } from 'electron';
|
||||
import { MenuTemplateItem } from '@joplin/lib/services/plugins/api/types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied, Old code before rule was applied
|
||||
export default function(webviewRef: RefObject<HTMLIFrameElement>, isReady: boolean, pluginId: string, viewId: string, windowId: string, postMessage: Function) {
|
||||
@@ -32,6 +35,19 @@ export default function(webviewRef: RefObject<HTMLIFrameElement>, isReady: boole
|
||||
windowId,
|
||||
...event.data.message,
|
||||
});
|
||||
} else if (event.data.target === 'webviewApi.menuPopupFromTemplate') {
|
||||
const template = event.data.args as MenuTemplateItem[];
|
||||
const finalTemplate = template.map((menuItem) => {
|
||||
const output: MenuItemConstructorOptions = {
|
||||
label: menuItem.label ?? '',
|
||||
click: () => {
|
||||
const args = menuItem.commandArgs ?? [];
|
||||
void CommandService.instance().execute(menuItem.command, ...args);
|
||||
},
|
||||
};
|
||||
return output;
|
||||
});
|
||||
bridge().menuPopupFromTemplate(finalTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,8 @@ import type { WhenClauseContext } from './commands/stateToWhenClauseContext';
|
||||
type LabelFunction = ()=> string;
|
||||
type EnabledCondition = string;
|
||||
|
||||
export type CommandArgument = string|number|object|boolean|null;
|
||||
|
||||
export interface CommandContext {
|
||||
// The state may also be of type "AppState" (used by the desktop app), which inherits from "State" (used by all apps)
|
||||
state: State;
|
||||
@@ -17,7 +19,7 @@ export interface CommandContext {
|
||||
|
||||
export interface CommandRuntime {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
execute(context: CommandContext, ...args: any[]): Promise<any | void>;
|
||||
execute(context: CommandContext, ...args: CommandArgument[]): Promise<any | void>;
|
||||
enabledCondition?: EnabledCondition;
|
||||
// Used for the (optional) toolbar button title
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
@@ -317,7 +319,7 @@ export default class CommandService extends BaseService {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
public async execute(commandName: string, ...args: any[]): Promise<any | void> {
|
||||
public async execute(commandName: string, ...args: CommandArgument[]): Promise<any | void> {
|
||||
const command = this.commandByName(commandName);
|
||||
// Some commands such as "showModalMessage" can be executed many
|
||||
// times per seconds, so we should only display this message in
|
||||
|
@@ -12,8 +12,17 @@ import JoplinViewsEditors from './JoplinViewsEditor';
|
||||
/**
|
||||
* This namespace provides access to view-related services.
|
||||
*
|
||||
* All view services provide a `create()` method which you would use to create the view object, whether it's a dialog, a toolbar button or a menu item.
|
||||
* In some cases, the `create()` method will return a [[ViewHandle]], which you would use to act on the view, for example to set certain properties or call some methods.
|
||||
* ## Creating a view
|
||||
*
|
||||
* All view services provide a `create()` method which you would use to create the view object,
|
||||
* whether it's a dialog, a toolbar button or a menu item. In some cases, the `create()` method will
|
||||
* return a [[ViewHandle]], which you would use to act on the view, for example to set certain
|
||||
* properties or call some methods.
|
||||
*
|
||||
* ## The `webviewApi` object
|
||||
*
|
||||
* Within a view, you can use the global object `webviewApi` for various utility functions, such as
|
||||
* sending messages or displaying context menu. Refer to [[WebviewApi]] for the full documentation.
|
||||
*/
|
||||
export default class JoplinViews {
|
||||
|
||||
|
@@ -417,6 +417,20 @@ export interface EditorActivationCheckFilterObject {
|
||||
|
||||
export type FilterHandler<T> = (object: T)=> Promise<T>;
|
||||
|
||||
export type CommandArgument = string|number|object|boolean|null;
|
||||
|
||||
export interface MenuTemplateItem {
|
||||
label?: string;
|
||||
command?: string;
|
||||
commandArgs?: CommandArgument[];
|
||||
}
|
||||
|
||||
export interface WebviewApi {
|
||||
postMessage: (message: object)=> unknown;
|
||||
onMessage: (message: object)=> void;
|
||||
menuPopupFromTemplate: (template: MenuTemplateItem[])=> void;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Settings types
|
||||
// =================================================================
|
||||
|
Reference in New Issue
Block a user