@whitesev/utils
Version:
一个常用的工具库
477 lines (473 loc) • 13 kB
text/typescript
import type {
UtilsGMMenuConstructorOptions,
UtilsGMMenuOption,
UtilsGMMenuOptionData,
} from "./types/UtilsGMMenu";
import { Utils } from "./Utils";
class GMMenu {
private GM_Api = {
/**
* 获取存储的数据
*/
getValue: null as any,
/**
* 设置数据到存储
*/
setValue: null as any,
/**
* 注册菜单
*/
registerMenuCommand: null as any,
/**
* 卸载菜单
*/
unregisterMenuCommand: null as any,
};
private MenuHandle = {
context: this,
$data: {
/**
* 菜单数据
*/
data: <UtilsGMMenuOptionData[]>[],
/**
* 本地存储的键名
*/
key: "GM_Menu_Local_Map",
},
$default: {
/** 自动刷新网页,默认为true */
autoReload: true,
/**
* 菜单isStoreValue的默认值
*/
isStoreValue: true,
},
$emoji: {
/**
* 菜单enable为true的emoji
*/
success: "✅",
/**
* 菜单enable为false的emoji
*/
error: "❌",
},
/**
* 初始化数据
*/
init() {
for (let index = 0; index < this.$data.data.length; index++) {
let menuOption = this.$data.data[index]["data"];
menuOption.enable = Boolean(
this.getLocalMenuData(menuOption.key, menuOption.enable as boolean)
);
if (typeof menuOption.showText !== "function") {
menuOption.showText = (menuText, menuEnable) => {
if (menuEnable) {
return this.$emoji.success + " " + menuText;
} else {
return this.$emoji.error + " " + menuText;
}
};
}
}
},
/**
* 注册油猴菜单
* @param menuOptions 如果存在,使用它
*/
register(menuOptions?: UtilsGMMenuOptionData[]) {
let that = this;
if (menuOptions == null) {
throw new TypeError("register菜单数据不能为空");
}
if (!Array.isArray(menuOptions)) {
menuOptions = [menuOptions];
}
for (let index = 0; index < menuOptions.length; index++) {
let cloneMenuOptionData = Utils.deepClone(menuOptions[index].data);
const { showText, clickCallBack } = this.handleMenuData(
cloneMenuOptionData as Required<UtilsGMMenuOption>
);
let menuId = that.context.GM_Api.registerMenuCommand(
showText,
clickCallBack
);
menuOptions[index].id = menuId;
(cloneMenuOptionData as any).deleteMenu = function () {
that.context.GM_Api.unregisterMenuCommand(menuId);
};
Reflect.deleteProperty(menuOptions[index], "handleData");
(menuOptions[index] as any).handleData = cloneMenuOptionData;
}
},
/**
* 获取本地存储菜单键值
* @param {string} key 键
*/
getLocalMenuData(key: string, defaultValue: boolean): boolean {
let localData = this.context.GM_Api.getValue(this.$data.key, {});
if (key in localData) {
return (localData as any)[key];
} else {
return defaultValue;
}
},
/**
* 设置本地存储菜单键值
* @param key 键
* @param value 值
*/
setLocalMenuData(key: string, value: boolean) {
let localData = this.context.GM_Api.getValue(this.$data.key, {});
(localData as any)[key] = value;
this.context.GM_Api.setValue(this.$data.key, localData);
},
/**
* 处理初始化配置
* @param menuOption
*/
handleInitDetail(menuOption: Required<UtilsGMMenuOption>) {
menuOption.enable = Boolean(
this.getLocalMenuData(menuOption.key, menuOption.enable)
);
if (typeof menuOption.showText !== "function") {
menuOption.showText = (menuText, menuEnable) => {
if (menuEnable) {
return this.$emoji.success + " " + menuText;
} else {
return this.$emoji.error + " " + menuText;
}
};
}
return menuOption;
},
/**
* 对菜单数据进行处理
* @param menuOption
*/
handleMenuData(menuOption: Required<UtilsGMMenuOption>) {
let that = this;
let menuLocalDataItemKey = menuOption.key;
/* 菜单默认开启的状态 */
let defaultEnable = Boolean(
this.getLocalMenuData(menuLocalDataItemKey, menuOption.enable)
);
/** 油猴菜单上显示的文本 */
let showText = menuOption.showText(menuOption.text, defaultEnable);
// @ts-ignore
const GMMenuOptions = {
/**
* 菜单的id
*/
id: menuOption.id,
/**
* 点击菜单项后是否应关闭弹出菜单
*/
autoClose: menuOption.autoClose,
/**
* 菜单项的可选访问键
*/
accessKey: menuOption.accessKey,
/**
* 菜单项的鼠标悬浮上的工具提示
*/
title: menuOption.title,
};
/* 点击菜单后触发callback后的网页是否刷新 */
menuOption.autoReload =
typeof menuOption.autoReload !== "boolean"
? this.$default.autoReload
: menuOption.autoReload;
/* 点击菜单后触发callback后的网页是否存储值 */
menuOption.isStoreValue =
typeof menuOption.isStoreValue !== "boolean"
? this.$default.isStoreValue
: menuOption.isStoreValue;
/**
* 用户点击菜单后的回调函数
* @param event
*/
function clickCallBack(event: MouseEvent | PointerEvent) {
let localEnable = Boolean(
that.getLocalMenuData(menuLocalDataItemKey, defaultEnable)
);
if (menuOption.isStoreValue) {
that.setLocalMenuData(menuLocalDataItemKey, !localEnable);
}
if (typeof menuOption.callback === "function") {
menuOption.callback({
key: menuLocalDataItemKey,
enable: !localEnable,
oldEnable: localEnable,
event: event,
storeValue(value) {
that.setLocalMenuData(menuLocalDataItemKey, value);
},
});
}
/* 不刷新网页就刷新菜单 */
if (menuOption.autoReload) {
window.location.reload();
} else {
that.context.update();
}
}
return {
showText,
clickCallBack,
};
},
/**
* 获取目标菜单配置数据
* @param menuKey 菜单-键key
*/
getMenuData(menuKey: string) {
return this.$data.data.find((item) => item.data.key === menuKey);
},
/**
* 获取目标菜单配置
* @param menuKey 菜单-键key
*/
getMenuOption(menuKey: string) {
return this.$data.data.find((item) => item.data.key === menuKey)?.data;
},
/**
* 获取目标菜单处理后的配置
* @param menuKey 菜单-键key
*/
getMenuHandledOption(menuKey: string) {
return this.$data.data.find((item) => item!.handleData!.key === menuKey)
?.handleData;
},
};
constructor(details: UtilsGMMenuConstructorOptions) {
this.GM_Api.getValue = details.GM_getValue;
this.GM_Api.setValue = details.GM_setValue;
this.GM_Api.registerMenuCommand = details.GM_registerMenuCommand;
this.GM_Api.unregisterMenuCommand = details.GM_unregisterMenuCommand;
this.MenuHandle.$default.autoReload =
typeof details.autoReload === "boolean" ? details.autoReload : true;
for (const keyName of Object.keys(this.GM_Api)) {
if (typeof (this.GM_Api as any)[keyName] !== "function") {
throw new Error(
`Utils.GM_Menu 请在脚本开头加上 ${keyName},且传入该对象`
);
}
}
this.add(details?.data || []);
}
/**
* 新增菜单数据
* @param menuOption
*/
private __add(menuOption: UtilsGMMenuOption[] | UtilsGMMenuOption) {
if (Array.isArray(menuOption)) {
for (let index = 0; index < menuOption.length; index++) {
const option = menuOption[index];
this.MenuHandle.$data.data.push({
data: option,
id: void 0,
});
}
} else {
this.MenuHandle.$data.data.push({
data: menuOption,
id: void 0,
});
}
}
/**
* 新增菜单数据
*
* 自动调用.update()
* @param menuOption
*/
add(menuOption: UtilsGMMenuOption[] | UtilsGMMenuOption) {
this.__add(menuOption);
this.update();
}
/**
* 更新菜单数据
*
* 实现方式:先取消注册所有已注册的菜单、再依次注册所有菜单项
*
* 如果菜单不存在,新增菜单项
*
* 如果菜单已存在,新菜单项覆盖旧的菜单项
* @param options 数据
*/
update(options?: UtilsGMMenuOption[] | UtilsGMMenuOption) {
let menuOptionList: UtilsGMMenuOption[] = [];
if (Array.isArray(options)) {
menuOptionList = [...menuOptionList, ...options];
} else if (options != null) {
menuOptionList = [...menuOptionList, options];
}
menuOptionList.forEach((menuOption) => {
let oldMenuOption = this.MenuHandle.getMenuOption(menuOption.key);
if (oldMenuOption) {
// 覆盖
Object.assign(oldMenuOption, menuOption);
} else {
this.__add(menuOption);
}
});
this.MenuHandle.$data.data.forEach((value) => {
if (value.handleData) {
value.handleData.deleteMenu();
}
});
this.MenuHandle.init();
this.MenuHandle.register(this.MenuHandle.$data.data);
}
/**
* 卸载菜单
* @param menuId 已注册的菜单id
*/
delete(menuId: number) {
this.GM_Api.unregisterMenuCommand(menuId);
}
/**
* 根据键值获取enable值
* @param menuKey 菜单-键key
* @deprecated
*/
get(menuKey: string): boolean {
return this.getEnable(menuKey);
}
/**
* 根据键值获取enable值
* @param menuKey 菜单-键key
*/
getEnable(menuKey: string): boolean {
return this.MenuHandle.getMenuHandledOption(menuKey)!.enable as boolean;
}
/**
* 根据键值获取text值
* @param menuKey 菜单-键key
*/
getText(menuKey: string): string {
return this.MenuHandle.getMenuHandledOption(menuKey)!.text;
}
/**
* 根据键值获取showText函数的值
* @param menuKey 菜单-键key
*/
getShowTextValue(menuKey: string): string {
return this.MenuHandle.getMenuHandledOption(menuKey)!.showText(
this.getText(menuKey),
this.getEnable(menuKey)
);
}
/**
* 获取当前已注册菜单的id
* @param menuKey
*/
getMenuId(menuKey: string): number | undefined | null {
let result = null;
for (let index = 0; index < this.MenuHandle.$data.data.length; index++) {
const optionData = this.MenuHandle.$data.data[index];
if (optionData!.handleData!.key === menuKey) {
result = optionData.id;
break;
}
}
return result;
}
/**
* 根据键值获取accessKey值
* @param menuKey 菜单-键key
*/
getAccessKey(menuKey: string): string | undefined {
return this.MenuHandle.getMenuHandledOption(menuKey)?.accessKey;
}
/**
* 根据键值获取autoClose值
* @param menuKey 菜单-键key
*/
getAutoClose(menuKey: string): boolean | undefined {
return this.MenuHandle.getMenuHandledOption(menuKey)?.autoClose;
}
/**
* 根据键值获取autoReload值
* @param menuKey 菜单-键key
*/
getAutoReload(menuKey: string): boolean | undefined {
return this.MenuHandle.getMenuHandledOption(menuKey)?.autoReload;
}
/**
* 根据键值获取callback函数
* @param menuKey 菜单-键key
*/
getCallBack(menuKey: string): Function | undefined {
return this.MenuHandle.getMenuHandledOption(menuKey)?.callback;
}
/**
* 获取当enable为true时默认显示在菜单中前面的emoji图标
*/
getEnableTrueEmoji() {
return this.MenuHandle.$emoji.success;
}
/**
* 获取当enable为false时默认显示在菜单中前面的emoji图标
*/
getEnableFalseEmoji() {
return this.MenuHandle.$emoji.error;
}
/**
* 获取本地存储的菜单外部的键名
* @param keyName
*/
getLocalStorageKeyName() {
return this.MenuHandle.$data.key;
}
/**
* 设置菜单的值
* @param menuKey 菜单-键key
* @param value 需要设置的值
*/
setValue(menuKey: string, value: any) {
this.MenuHandle.setLocalMenuData(menuKey, value);
}
/**
* 设置菜单的值
* @param menuKey 菜单-键key
* @param value 需要设置的值
*/
setEnable(menuKey: string, value: boolean) {
this.setValue(menuKey, Boolean(value));
}
/**
* 设置当enable为true时默认显示在菜单中前面的emoji图标
* @param emojiString
*/
setEnableTrueEmoji(emojiString: string) {
if (typeof emojiString !== "string") {
throw new Error("参数emojiString必须是string类型");
}
this.MenuHandle.$emoji.success = emojiString;
}
/**
* 设置当enable为false时默认显示在菜单中前面的emoji图标
* @param emojiString
*/
setEnableFalseEmoji(emojiString: string) {
if (typeof emojiString !== "string") {
throw new Error("参数emojiString必须是string类型");
}
this.MenuHandle.$emoji.error = emojiString;
}
/**
* 设置本地存储的菜单外部的键名
* @param keyName
*/
setLocalStorageKeyName(keyName: string) {
if (typeof keyName !== "string") {
throw new Error("参数keyName必须是string类型");
}
this.MenuHandle.$data.key = keyName;
}
}
export { GMMenu };