diff --git a/README.md b/README.md index de101ec..07cbca0 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ See how the examples work by directly downloading the `xpi` file from GitHub rel This is also how your plugin will be released and used by others. > The release do not promise any real functions. It is probably not up-to-date. -> +> > The `xpi` package is a zip file. However, please don't modify it directly. Modify the source code and build it. ### Build from Source @@ -129,6 +129,7 @@ This is also how your plugin will be released and used by others. ### Release To build and release, use + ```shell # A release-it command: version increase, npm run build, git push, and GitHub release # You need to set the environment variable GITHUB_TOKEN https://github.com/settings/tokens @@ -246,14 +247,18 @@ Remember to call `unregister()` on plugin unload. The plugin template provides new APIs for bootstrap plugins. We have two reasons to use these APIs, instead of the `createElement/createElementNS`: -- In bootstrap mode, plugins have to clean up all UI elements on exit (disable or uninstall), which is very annoying. Using the `createElement`, the plugin template will maintain these elements. Just `unregister` on exit. -- Zotero 7 requires createElement()/createElementNS() → createXULElement() for remaining XUL elements, while Zotero 6 doesn't support `createXULElement`. Using `createElement`, it switches API depending on the current platform automatically. +- In bootstrap mode, plugins have to clean up all UI elements on exit (disable or uninstall), which is very annoying. Using the `createElement`, the plugin template will maintain these elements. Just `unregisterAll` at the exit. +- Zotero 7 requires createElement()/createElementNS() → createXULElement() for remaining XUL elements, while Zotero 6 doesn't support `createXULElement`. The React.createElement-like API `createElement` detects namespace(xul/html/svg) and creates elements automatically, with the return element in the corresponding TS element type. -There are more advanced APIs for creating elements in batch: `creatElementsFromJSON`. Input an element tree in JSON and return a fragment/element. These elements are also maintained by this plugin template. +```ts +createElement(document, "div"); // returns HTMLDivElement +createElement(document, "hbox"); // returns XUL.Box +createElement(document, "button", { namespace: "xul" }); // manually set namespace. returns XUL.Button +``` ### About Build -Use esbuild to build `.ts` source code to `.js`. +Use Esbuild to build `.ts` source code to `.js`. Use `replace-in-file` to replace keywords and configurations defined in `package.json` in non-build files (`.xul/xhtml`, `.dtd`, and `.properties`). diff --git a/package.json b/package.json index d696b65..c27c21a 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/windingwind/zotero-addon-template#readme", "dependencies": { - "zotero-plugin-toolkit": "^1.0.3" + "zotero-plugin-toolkit": "^1.0.4" }, "devDependencies": { "@types/node": "^18.11.17", diff --git a/src/index.ts b/src/index.ts index 0b008dd..ba1d1de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,7 @@ if (!basicTool.getGlobal("Zotero").AddonTemplate) { _globalThis.ztoolkit = addon.data.ztoolkit; ztoolkit.basicOptions.log.prefix = `[${config.addonName}]`; ztoolkit.basicOptions.log.disableConsole = addon.data.env === "production"; - ztoolkit.UI.elementOptions.enableElementJSONLog = + ztoolkit.UI.basicOptions.ui.enableElementJSONLog = addon.data.env === "development"; Zotero.AddonTemplate = addon; // Trigger addon hook for initialization diff --git a/src/modules/examples.ts b/src/modules/examples.ts index 804a043..2ea7959 100644 --- a/src/modules/examples.ts +++ b/src/modules/examples.ts @@ -184,14 +184,13 @@ export class KeyExampleFactory { export class UIExampleFactory { @example static registerStyleSheet() { - const styles = ztoolkit.UI.creatElementsFromJSON(document, { - tag: "link", - directAttributes: { + const styles = ztoolkit.UI.createElement(document, "link", { + properties: { type: "text/css", rel: "stylesheet", href: `chrome://${config.addonRef}/content/zoteroPane.css`, }, - }) as HTMLLinkElement; + }); document.documentElement.appendChild(styles); document .getElementById("zotero-item-pane-content") @@ -218,7 +217,7 @@ export class UIExampleFactory { { tag: "menu", label: getString("menupopup.label"), - subElementOptions: [ + children: [ { tag: "menuitem", label: getString("menuitem.submenulabel"), @@ -313,28 +312,24 @@ export class UIExampleFactory { const tabId = ztoolkit.LibraryTabPanel.register( getString("tabpanel.lib.tab.label"), (panel: XUL.Element, win: Window) => { - const elem = ztoolkit.UI.creatElementsFromJSON(win.document, { - tag: "vbox", - namespace: "xul", - subElementOptions: [ + const elem = ztoolkit.UI.createElement(win.document, "vbox", { + children: [ { tag: "h2", - namespace: "html", - directAttributes: { + properties: { innerText: "Hello World!", }, }, { tag: "div", - namespace: "html", - directAttributes: { + properties: { innerText: "This is a library tab.", }, }, { tag: "button", namespace: "html", - directAttributes: { + properties: { innerText: "Unregister", }, listeners: [ @@ -373,46 +368,40 @@ export class UIExampleFactory { return; } ztoolkit.log(reader); - const elem = ztoolkit.UI.creatElementsFromJSON(win.document, { - tag: "vbox", + const elem = ztoolkit.UI.createElement(win.document, "vbox", { id: `${config.addonRef}-${reader._instanceID}-extra-reader-tab-div`, - namespace: "xul", // This is important! Don't create content for multiple times // ignoreIfExists: true, removeIfExists: true, - subElementOptions: [ + children: [ { tag: "h2", - namespace: "html", - directAttributes: { + properties: { innerText: "Hello World!", }, }, { tag: "div", - namespace: "html", - directAttributes: { + properties: { innerText: "This is a reader tab.", }, }, { tag: "div", - namespace: "html", - directAttributes: { + properties: { innerText: `Reader: ${reader._title.slice(0, 20)}`, }, }, { tag: "div", - namespace: "html", - directAttributes: { + properties: { innerText: `itemID: ${reader.itemID}.`, }, }, { tag: "button", namespace: "html", - directAttributes: { + properties: { innerText: "Unregister", }, listeners: [