2023-05-24 20:07:18 +08:00
|
|
|
import {fetchSyncPost} from "../util/fetch";
|
2023-05-04 18:28:57 +08:00
|
|
|
import {App} from "../index";
|
|
|
|
|
import {Plugin} from "./index";
|
2023-05-16 18:49:12 +08:00
|
|
|
/// #if !MOBILE
|
2024-01-17 22:46:35 +08:00
|
|
|
import {resizeTopBar, saveLayout} from "../layout/util";
|
2023-05-16 18:49:12 +08:00
|
|
|
/// #endif
|
2023-11-09 17:00:55 +08:00
|
|
|
import {API} from "./API";
|
2023-05-29 20:34:16 +08:00
|
|
|
import {getFrontend, isMobile, isWindow} from "../util/functions";
|
2023-06-03 21:45:24 +08:00
|
|
|
import {Constants} from "../constants";
|
2024-01-20 23:01:41 +08:00
|
|
|
import {uninstall} from "./uninstall";
|
2023-05-04 18:28:57 +08:00
|
|
|
|
2023-12-04 14:36:04 +08:00
|
|
|
const requireFunc = (key: string) => {
|
2023-12-04 16:23:38 +08:00
|
|
|
const modules = {
|
|
|
|
|
siyuan: API
|
|
|
|
|
};
|
2023-11-09 17:00:55 +08:00
|
|
|
// @ts-ignore
|
2023-12-04 14:36:04 +08:00
|
|
|
return modules[key]
|
|
|
|
|
?? window.require?.(key);
|
2023-11-09 17:00:55 +08:00
|
|
|
};
|
2023-12-04 14:36:04 +08:00
|
|
|
if (window.require instanceof Function) {
|
|
|
|
|
requireFunc.__proto__ = window.require;
|
|
|
|
|
}
|
2023-11-09 17:00:55 +08:00
|
|
|
|
2023-05-04 18:28:57 +08:00
|
|
|
const runCode = (code: string, sourceURL: string) => {
|
2023-05-06 00:10:30 +08:00
|
|
|
return window.eval("(function anonymous(require, module, exports){".concat(code, "\n})\n//# sourceURL=").concat(sourceURL, "\n"));
|
2023-05-05 14:04:43 +08:00
|
|
|
};
|
2023-05-04 18:28:57 +08:00
|
|
|
|
2024-05-13 09:16:58 +08:00
|
|
|
export const loadPlugins = async (app: App, names?: string[]) => {
|
2023-05-29 20:34:16 +08:00
|
|
|
const response = await fetchSyncPost("/api/petal/loadPetals", {frontend: getFrontend()});
|
2023-05-24 09:19:48 +08:00
|
|
|
let css = "";
|
2023-05-26 23:31:32 +08:00
|
|
|
// 为加快启动速度,不进行 await
|
2023-05-24 09:19:48 +08:00
|
|
|
response.data.forEach((item: IPluginData) => {
|
2024-05-13 09:29:40 +08:00
|
|
|
if (!names || (names && names.includes(item.name))) {
|
2024-05-13 09:16:58 +08:00
|
|
|
loadPluginJS(app, item);
|
|
|
|
|
}
|
2023-05-24 09:19:48 +08:00
|
|
|
css += item.css || "" + "\n";
|
2023-05-05 14:04:43 +08:00
|
|
|
});
|
2023-10-24 10:42:04 +08:00
|
|
|
const pluginsStyle = document.getElementById("pluginsStyle");
|
2023-10-23 10:28:23 +08:00
|
|
|
if (pluginsStyle) {
|
|
|
|
|
pluginsStyle.innerHTML = css;
|
|
|
|
|
} else {
|
|
|
|
|
document.head.insertAdjacentHTML("beforeend", `<style id="pluginsStyle">${css}</style>`);
|
|
|
|
|
}
|
2023-05-05 14:04:43 +08:00
|
|
|
};
|
2023-05-16 10:31:01 +08:00
|
|
|
|
2023-05-26 23:31:32 +08:00
|
|
|
const loadPluginJS = async (app: App, item: IPluginData) => {
|
2023-05-16 10:31:01 +08:00
|
|
|
const exportsObj: { [key: string]: any } = {};
|
|
|
|
|
const moduleObj = {exports: exportsObj};
|
|
|
|
|
try {
|
2023-12-04 14:36:04 +08:00
|
|
|
runCode(item.js, "plugin:" + encodeURIComponent(item.name))(requireFunc, moduleObj, exportsObj);
|
2023-05-16 10:31:01 +08:00
|
|
|
} catch (e) {
|
2023-06-05 11:30:58 +08:00
|
|
|
console.error(`plugin ${item.name} run error:`, e);
|
2023-05-16 10:31:01 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const pluginClass = (moduleObj.exports || exportsObj).default || moduleObj.exports;
|
|
|
|
|
if (typeof pluginClass !== "function") {
|
|
|
|
|
console.error(`plugin ${item.name} has no export`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!(pluginClass.prototype instanceof Plugin)) {
|
|
|
|
|
console.error(`plugin ${item.name} does not extends Plugin`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const plugin = new pluginClass({
|
|
|
|
|
app,
|
2023-06-30 10:44:33 +08:00
|
|
|
displayName: item.displayName,
|
2023-05-16 10:31:01 +08:00
|
|
|
name: item.name,
|
|
|
|
|
i18n: item.i18n
|
|
|
|
|
});
|
|
|
|
|
app.plugins.push(plugin);
|
|
|
|
|
try {
|
2023-05-26 23:31:32 +08:00
|
|
|
await plugin.onload();
|
2023-05-16 10:31:01 +08:00
|
|
|
} catch (e) {
|
2023-05-24 09:19:48 +08:00
|
|
|
console.error(`plugin ${item.name} onload error:`, e);
|
2023-05-16 10:31:01 +08:00
|
|
|
}
|
|
|
|
|
return plugin;
|
2023-05-16 18:51:13 +08:00
|
|
|
};
|
2023-05-16 10:31:01 +08:00
|
|
|
|
2023-05-31 15:54:44 +08:00
|
|
|
// 启用插件
|
2023-05-26 23:31:32 +08:00
|
|
|
export const loadPlugin = async (app: App, item: IPluginData) => {
|
|
|
|
|
const plugin = await loadPluginJS(app, item);
|
2023-05-24 10:51:32 +08:00
|
|
|
const styleElement = document.createElement("style");
|
|
|
|
|
styleElement.textContent = item.css;
|
|
|
|
|
document.head.append(styleElement);
|
|
|
|
|
afterLoadPlugin(plugin);
|
2024-01-24 13:13:32 +08:00
|
|
|
saveLayout();
|
2023-06-21 23:29:40 +08:00
|
|
|
return plugin;
|
2023-05-24 10:51:32 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2024-03-25 09:33:22 +08:00
|
|
|
const updateDock = (dockItem: Config.IUILayoutDockTab[], index: number, plugin: Plugin, type: string) => {
|
2023-05-24 20:06:32 +08:00
|
|
|
const dockKeys = Object.keys(plugin.docks);
|
2024-03-25 09:33:22 +08:00
|
|
|
dockItem.forEach((tabItem: Config.IUILayoutDockTab, tabIndex: number) => {
|
2023-05-24 10:51:32 +08:00
|
|
|
if (dockKeys.includes(tabItem.type)) {
|
|
|
|
|
if (type === "Left") {
|
|
|
|
|
plugin.docks[tabItem.type].config.position = index === 0 ? "LeftTop" : "LeftBottom";
|
|
|
|
|
} else if (type === "Right") {
|
|
|
|
|
plugin.docks[tabItem.type].config.position = index === 0 ? "RightTop" : "RightBottom";
|
|
|
|
|
} else if (type === "Bottom") {
|
|
|
|
|
plugin.docks[tabItem.type].config.position = index === 0 ? "BottomLeft" : "BottomRight";
|
|
|
|
|
}
|
|
|
|
|
plugin.docks[tabItem.type].config.index = tabIndex;
|
2023-05-24 11:26:49 +08:00
|
|
|
plugin.docks[tabItem.type].config.show = tabItem.show;
|
2023-05-24 10:51:32 +08:00
|
|
|
plugin.docks[tabItem.type].config.size = tabItem.size;
|
|
|
|
|
}
|
2023-05-24 20:06:32 +08:00
|
|
|
});
|
|
|
|
|
};
|
2023-05-24 10:51:32 +08:00
|
|
|
|
|
|
|
|
export const afterLoadPlugin = (plugin: Plugin) => {
|
|
|
|
|
try {
|
|
|
|
|
plugin.onLayoutReady();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(`plugin ${plugin.name} onLayoutReady error:`, e);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 17:03:35 +08:00
|
|
|
if (!isWindow() || isMobile()) {
|
2023-10-25 22:27:07 +08:00
|
|
|
const unPinMenu: IMenu[] = [];
|
2023-05-26 17:03:35 +08:00
|
|
|
plugin.topBarIcons.forEach(element => {
|
|
|
|
|
if (isMobile()) {
|
2023-06-12 23:53:00 +08:00
|
|
|
if (window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].includes(element.id)) {
|
2023-10-25 22:27:07 +08:00
|
|
|
unPinMenu.push({
|
2023-06-12 23:53:00 +08:00
|
|
|
iconHTML: element.firstElementChild.outerHTML,
|
|
|
|
|
label: element.textContent.trim(),
|
|
|
|
|
click() {
|
|
|
|
|
element.dispatchEvent(new CustomEvent("click"));
|
|
|
|
|
}
|
2023-06-19 21:04:56 +08:00
|
|
|
});
|
2023-06-12 23:53:00 +08:00
|
|
|
} else {
|
|
|
|
|
document.querySelector("#menuAbout").after(element);
|
|
|
|
|
}
|
2023-05-26 17:03:35 +08:00
|
|
|
} else if (!isWindow()) {
|
2023-06-03 21:45:24 +08:00
|
|
|
if (window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].includes(element.id)) {
|
|
|
|
|
element.classList.add("fn__none");
|
|
|
|
|
}
|
2023-06-03 17:55:45 +08:00
|
|
|
document.querySelector("#" + (element.getAttribute("data-position") === "right" ? "barPlugins" : "drag")).before(element);
|
2023-05-26 17:03:35 +08:00
|
|
|
}
|
|
|
|
|
});
|
2023-10-25 22:27:07 +08:00
|
|
|
if (isMobile() && unPinMenu.length > 0) {
|
|
|
|
|
return unPinMenu;
|
2023-06-12 23:53:00 +08:00
|
|
|
}
|
2023-05-26 17:03:35 +08:00
|
|
|
}
|
2023-05-31 15:39:42 +08:00
|
|
|
/// #if !MOBILE
|
2023-10-25 17:06:19 +08:00
|
|
|
resizeTopBar();
|
2023-05-31 15:39:42 +08:00
|
|
|
plugin.statusBarIcons.forEach(element => {
|
2023-06-01 20:50:49 +08:00
|
|
|
const statusElement = document.getElementById("status");
|
2023-05-31 15:39:42 +08:00
|
|
|
if (element.getAttribute("data-position") === "right") {
|
|
|
|
|
statusElement.insertAdjacentElement("beforeend", element);
|
|
|
|
|
} else {
|
|
|
|
|
statusElement.insertAdjacentElement("afterbegin", element);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
/// #endif
|
2023-05-26 16:37:18 +08:00
|
|
|
if (isWindow()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 17:03:35 +08:00
|
|
|
/// #if !MOBILE
|
2024-03-25 09:33:22 +08:00
|
|
|
window.siyuan.config.uiLayout.left.data.forEach((dockItem: Config.IUILayoutDockTab[], index: number) => {
|
2023-05-24 20:06:32 +08:00
|
|
|
updateDock(dockItem, index, plugin, "Left");
|
|
|
|
|
});
|
2024-03-25 09:33:22 +08:00
|
|
|
window.siyuan.config.uiLayout.right.data.forEach((dockItem: Config.IUILayoutDockTab[], index: number) => {
|
2023-05-24 20:06:32 +08:00
|
|
|
updateDock(dockItem, index, plugin, "Right");
|
|
|
|
|
});
|
2024-03-25 09:33:22 +08:00
|
|
|
window.siyuan.config.uiLayout.bottom.data.forEach((dockItem: Config.IUILayoutDockTab[], index: number) => {
|
2023-05-24 20:06:32 +08:00
|
|
|
updateDock(dockItem, index, plugin, "Bottom");
|
|
|
|
|
});
|
2023-05-16 10:31:01 +08:00
|
|
|
Object.keys(plugin.docks).forEach(key => {
|
|
|
|
|
const dock = plugin.docks[key];
|
2024-03-22 09:45:26 +08:00
|
|
|
const hotkey = window.siyuan.config.keymap.plugin[plugin.name] ? window.siyuan.config.keymap.plugin[plugin.name][key]?.custom : undefined;
|
2023-05-16 10:31:01 +08:00
|
|
|
if (dock.config.position.startsWith("Left")) {
|
|
|
|
|
window.siyuan.layout.leftDock.genButton([{
|
|
|
|
|
type: key,
|
|
|
|
|
size: dock.config.size,
|
2023-05-24 11:26:49 +08:00
|
|
|
show: dock.config.show,
|
2023-05-16 10:31:01 +08:00
|
|
|
icon: dock.config.icon,
|
|
|
|
|
title: dock.config.title,
|
2024-03-19 23:14:18 +08:00
|
|
|
hotkey
|
2023-05-24 10:51:32 +08:00
|
|
|
}], dock.config.position === "LeftBottom" ? 1 : 0, dock.config.index);
|
2023-05-16 10:31:01 +08:00
|
|
|
} else if (dock.config.position.startsWith("Bottom")) {
|
|
|
|
|
window.siyuan.layout.bottomDock.genButton([{
|
|
|
|
|
type: key,
|
|
|
|
|
size: dock.config.size,
|
2023-05-24 11:26:49 +08:00
|
|
|
show: dock.config.show,
|
2023-05-16 10:31:01 +08:00
|
|
|
icon: dock.config.icon,
|
|
|
|
|
title: dock.config.title,
|
2024-03-19 23:14:18 +08:00
|
|
|
hotkey
|
2023-05-24 10:51:32 +08:00
|
|
|
}], dock.config.position === "BottomRight" ? 1 : 0, dock.config.index);
|
2023-05-16 10:31:01 +08:00
|
|
|
} else if (dock.config.position.startsWith("Right")) {
|
|
|
|
|
window.siyuan.layout.rightDock.genButton([{
|
|
|
|
|
type: key,
|
|
|
|
|
size: dock.config.size,
|
2023-05-24 11:26:49 +08:00
|
|
|
show: dock.config.show,
|
2023-05-16 10:31:01 +08:00
|
|
|
icon: dock.config.icon,
|
|
|
|
|
title: dock.config.title,
|
2024-03-19 23:14:18 +08:00
|
|
|
hotkey
|
2023-05-24 10:51:32 +08:00
|
|
|
}], dock.config.position === "RightBottom" ? 1 : 0, dock.config.index);
|
2023-05-16 10:31:01 +08:00
|
|
|
}
|
|
|
|
|
});
|
2023-05-26 17:03:35 +08:00
|
|
|
/// #endif
|
2023-05-24 20:06:32 +08:00
|
|
|
};
|
2024-01-20 23:01:41 +08:00
|
|
|
|
2024-05-13 09:16:58 +08:00
|
|
|
export const reloadPlugin = async (app: App, data: { upsertPlugins: string[], removePlugins: string[] }) => {
|
|
|
|
|
data.removePlugins.concat(data.upsertPlugins).forEach((item) => {
|
2024-05-13 09:39:19 +08:00
|
|
|
uninstall(app, item);
|
2024-01-20 23:01:41 +08:00
|
|
|
});
|
2024-05-13 09:39:19 +08:00
|
|
|
loadPlugins(app, data.upsertPlugins).then(() => {
|
2024-01-20 23:01:41 +08:00
|
|
|
app.plugins.forEach(item => {
|
2024-05-13 09:16:58 +08:00
|
|
|
if (data.upsertPlugins.includes(item.name)) {
|
|
|
|
|
afterLoadPlugin(item);
|
|
|
|
|
}
|
2024-01-20 23:01:41 +08:00
|
|
|
});
|
|
|
|
|
});
|
2024-01-24 13:13:32 +08:00
|
|
|
/// #if !MOBILE
|
|
|
|
|
saveLayout();
|
|
|
|
|
/// #endif
|
2024-01-20 23:01:41 +08:00
|
|
|
};
|