浏览代码

:sparkles: enable plugin

Vanessa 2 年之前
父节点
当前提交
85496345ef
共有 4 个文件被更改,包括 105 次插入41 次删除
  1. 6 8
      app/src/config/bazaar.ts
  2. 14 4
      app/src/layout/dock/index.ts
  3. 78 29
      app/src/plugin/loader.ts
  4. 7 0
      app/src/types/index.d.ts

+ 6 - 8
app/src/config/bazaar.ts

@@ -16,6 +16,7 @@ import {Plugin} from "../plugin";
 import {App} from "../index";
 import {escapeAttr} from "../util/escape";
 import {uninstall} from "../plugin/uninstall";
+import {loadPlugin} from "../plugin/loader";
 
 export const bazaar = {
     element: undefined as Element,
@@ -635,19 +636,16 @@ export const bazaar = {
                     event.stopPropagation();
                     break;
                 } else if (type === "plugin-enable") {
-                    const itemElement = hasClosestByClassName(target, "b3-card");
-                    if (itemElement) {
+                    if (!target.getAttribute("disabled")) {
+                        target.setAttribute("disabled", "disabled");
                         const enabled = (target as HTMLInputElement).checked;
                         fetchPost("/api/petal/setPetalEnabled", {
                             packageName: dataObj.name,
                             enabled,
-                        }, () => {
+                        }, (response) => {
+                            target.removeAttribute("disabled");
                             if (enabled) {
-                                exportLayout({
-                                    reload: true,
-                                    onlyData: false,
-                                    errorExit: false,
-                                });
+                                loadPlugin(app, response.data);
                             } else {
                                 uninstall(app, dataObj.name);
                             }

+ 14 - 4
app/src/layout/dock/index.ts

@@ -549,7 +549,9 @@ export class Dock {
         this.toggleModel(key, false, true, true);
         this.element.querySelector(`[data-type="${key}"]`).remove();
         const custom = this.data[key] as Custom;
-        custom.parent.parent.removeTab(custom.parent.id);
+        if (custom.parent) {
+            custom.parent.parent.removeTab(custom.parent.id);
+        }
         delete this.data[key];
     }
 
@@ -603,7 +605,7 @@ export class Dock {
         return max;
     }
 
-    private genButton(data: IDockTab[], index: number) {
+    public genButton(data: IDockTab[], index: number, append = false) {
         let html = "";
         data.forEach(item => {
             html += `<span data-height="${item.size.height}" data-width="${item.size.width}" data-type="${item.type}" data-index="${index}" data-hotkey="${item.hotkey || ""}" data-hotkeyLangId="${item.hotkeyLangId || ""}" data-title="${item.title}" class="dock__item${item.show ? " dock__item--active" : ""} b3-tooltips b3-tooltips__${this.getClassDirect(index)}" aria-label="${item.title} ${item.hotkey ? updateHotkeyTip(item.hotkey) : ""}${window.siyuan.languages.dockTip}">
@@ -612,11 +614,19 @@ export class Dock {
             this.data[item.type] = true;
         });
         if (index === 0) {
-            this.element.firstElementChild.innerHTML = `${html}<span class="dock__item dock__item--pin b3-tooltips b3-tooltips__${this.getClassDirect(index)}" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
+            if (append) {
+                this.element.firstElementChild.lastElementChild.insertAdjacentHTML("beforebegin", html);
+            } else {
+                this.element.firstElementChild.innerHTML = `${html}<span class="dock__item dock__item--pin b3-tooltips b3-tooltips__${this.getClassDirect(index)}" aria-label="${this.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}">
     <svg><use xlink:href="#iconPin"></use></svg>
 </span>`;
+            }
         } else {
-            this.element.lastElementChild.innerHTML = html;
+            if (append) {
+                this.element.lastElementChild.insertAdjacentHTML("beforeend", html);
+            } else {
+                this.element.lastElementChild.innerHTML = html;
+            }
         }
     }
 }

+ 78 - 29
app/src/plugin/loader.ts

@@ -2,6 +2,7 @@ import {fetchPost} from "../util/fetch";
 import {App} from "../index";
 import {Plugin} from "./index";
 import {API} from "./API";
+import {exportLayout} from "../layout/util";
 
 const getObject = (key: string) => {
     const api = {
@@ -18,35 +19,8 @@ const runCode = (code: string, sourceURL: string) => {
 export const loadPlugins = (app: App) => {
     fetchPost("/api/petal/loadPetals", {}, response => {
         let css = "";
-        response.data.forEach((item: { name: string, js: string, css: string, i18n: IObject }) => {
-            const exportsObj: { [key: string]: any } = {};
-            const moduleObj = {exports: exportsObj};
-            try {
-                runCode(item.js, "plugin:" + encodeURIComponent(item.name))(getObject, moduleObj, exportsObj);
-            } catch (e) {
-                console.error(`eval plugin ${item.name} error:`, e);
-                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,
-                name: item.name,
-                i18n: item.i18n
-            });
-            app.plugins.push(plugin);
-            try {
-                plugin.onload();
-            } catch (e) {
-                console.error(`plugin ${item.name} load error:`, e);
-            }
+        response.data.forEach((item: IPluginData) => {
+            loadPluginJS(app, item);
             css += item.css || "" + "\n";
         });
         const styleElement = document.createElement("style");
@@ -54,3 +28,78 @@ export const loadPlugins = (app: App) => {
         document.head.append(styleElement);
     });
 };
+
+const loadPluginJS = (app: App, item: IPluginData) => {
+    const exportsObj: { [key: string]: any } = {};
+    const moduleObj = {exports: exportsObj};
+    try {
+        runCode(item.js, "plugin:" + encodeURIComponent(item.name))(getObject, moduleObj, exportsObj);
+    } catch (e) {
+        console.error(`eval plugin ${item.name} error:`, e);
+        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,
+        name: item.name,
+        i18n: item.i18n
+    });
+    app.plugins.push(plugin);
+    try {
+        plugin.onload();
+    } catch (e) {
+        console.error(`plugin ${item.name} load error:`, e);
+    }
+    return plugin;
+}
+
+export const loadPlugin = (app: App, item: IPluginData) => {
+    const plugin = loadPluginJS(app, item);
+    Object.keys(plugin.docks).forEach(key => {
+        const dock = plugin.docks[key];
+        if (dock.config.position.startsWith("Left")) {
+            window.siyuan.layout.leftDock.genButton([{
+                type: key,
+                size: dock.config.size,
+                show: false,
+                icon: dock.config.icon,
+                title: dock.config.title,
+                hotkey: dock.config.hotkey
+            }], dock.config.position === "LeftBottom" ? 1 : 0, true)
+        } else if (dock.config.position.startsWith("Bottom")) {
+            window.siyuan.layout.bottomDock.genButton([{
+                type: key,
+                size: dock.config.size,
+                show: false,
+                icon: dock.config.icon,
+                title: dock.config.title,
+                hotkey: dock.config.hotkey
+            }], dock.config.position === "BottomRight" ? 1 : 0, true)
+        } else if (dock.config.position.startsWith("Right")) {
+            window.siyuan.layout.rightDock.genButton([{
+                type: key,
+                size: dock.config.size,
+                show: false,
+                icon: dock.config.icon,
+                title: dock.config.title,
+                hotkey: dock.config.hotkey
+            }], dock.config.position === "RightBottom" ? 1 : 0, true)
+        }
+    });
+    const styleElement = document.createElement("style");
+    styleElement.textContent = item.css;
+    document.head.append(styleElement);
+    exportLayout({
+        reload: false,
+        onlyData: false,
+        errorExit: false
+    });
+};

+ 7 - 0
app/src/types/index.d.ts

@@ -298,6 +298,13 @@ declare interface IDockTab {
     hotkeyLangId?: string   // 常量中无法存变量
 }
 
+declare interface IPluginData {
+    name: string,
+    js: string,
+    css: string,
+    i18n: IObject
+}
+
 declare interface IPluginDockTab {
     position: TPluginDockPosition,
     size: { width: number, height: number },