1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00
joplin/packages/lib/services/commands/MenuUtils.ts

147 lines
4.0 KiB
TypeScript
Raw Normal View History

import { MenuItemLocation } from '../../plugin_types/services/plugins/api/types';
import CommandService from '../CommandService';
import KeymapService from '../KeymapService';
import { PluginStates, utils as pluginUtils } from '../plugins/reducer';
import propsHaveChanged from './propsHaveChanged';
const { createSelectorCreator, defaultMemoize } = require('reselect');
const { createCachedSelector } = require('re-reselect');
interface MenuItem {
id: string;
label: string;
click: Function;
role?: any;
accelerator?: string;
}
interface MenuItems {
[key: string]: MenuItem;
}
interface MenuItemProps {
[key: string]: any;
}
interface MenuItemPropsCache {
[key: string]: any;
}
interface MenuItemCache {
[key: string]: MenuItems;
}
const createShallowObjectEqualSelector = createSelectorCreator(
defaultMemoize,
(prev: any, next: any) => {
if (Object.keys(prev).length !== Object.keys(next).length) return false;
for (const n in prev) {
if (prev[n] !== next[n]) return false;
}
return true;
}
);
// This selector ensures that for the given command names, the same toolbar
// button array is returned if the underlying toolbar buttons have not changed.
const selectObjectByCommands = createCachedSelector(
(state: any) => state.array,
(array: any[]) => array
)({
keySelector: (_state: any, commandNames: string[]) => {
return commandNames.join('_');
},
selectorCreator: createShallowObjectEqualSelector,
});
export default class MenuUtils {
private service_: CommandService;
private menuItemCache_: MenuItemCache = {};
private menuItemPropsCache_: MenuItemPropsCache = {};
constructor(service: CommandService) {
this.service_ = service;
}
private get service(): CommandService {
return this.service_;
}
private get keymapService(): KeymapService {
return KeymapService.instance();
}
public commandToMenuItem(commandName: string, onClick: Function): MenuItem {
const command = this.service.commandByName(commandName);
const item: MenuItem = {
id: command.declaration.name,
label: this.service.label(commandName),
click: () => onClick(command.declaration.name),
};
if (command.declaration.role) item.role = command.declaration.role;
if (this.keymapService && this.keymapService.acceleratorExists(commandName)) {
item.accelerator = this.keymapService.getAccelerator(commandName);
}
return item;
}
public commandToStatefulMenuItem(commandName: string, ...args: any[]): MenuItem {
return this.commandToMenuItem(commandName, () => {
return this.service.execute(commandName, ...args);
});
}
public commandsToMenuItems(commandNames: string[], onClick: Function): MenuItems {
const key: string = `${this.keymapService.lastSaveTime}_${commandNames.join('_')}`;
if (this.menuItemCache_[key]) return this.menuItemCache_[key];
const output: MenuItems = {};
for (const commandName of commandNames) {
output[commandName] = this.commandToMenuItem(commandName, onClick);
}
this.menuItemCache_[key] = output;
return output;
}
public commandsToMenuItemProps(commandNames: string[], whenClauseContext: any): MenuItemProps {
const output: MenuItemProps = {};
for (const commandName of commandNames) {
const newProps = {
enabled: this.service.isEnabled(commandName, whenClauseContext),
};
if (newProps === null || propsHaveChanged(this.menuItemPropsCache_[commandName], newProps)) {
output[commandName] = newProps;
this.menuItemPropsCache_[commandName] = newProps;
} else {
output[commandName] = this.menuItemPropsCache_[commandName];
}
}
return selectObjectByCommands({ array: output }, commandNames);
}
public pluginContextMenuItems(plugins: PluginStates, location: MenuItemLocation): MenuItem[] {
const output: MenuItem[] = [];
const pluginViewInfos = pluginUtils.viewInfosByType(plugins, 'menuItem');
for (const info of pluginViewInfos) {
if (info.view.location !== location) continue;
output.push(this.commandToStatefulMenuItem(info.view.commandName));
}
if (output.length) output.splice(0, 0, { type: 'separator' } as any);
return output;
}
}