This is a plugin template for Zotero.
Some plugins created with this template:
📖 Plugin Development Documentation (Chinese, provides English translation)
🛠️ Zotero Plugin Toolkit | API Documentation
📌 Zotero Plugin Template (This repo)
👁 Watch this repo so that you can be notified whenever there are fixes & updates.
If you are using this repo, I recommended that you put this badge () on your README:
[![Using Zotero Plugin Template](https://img.shields.io/badge/Using-Zotero%20Plugin%20Template-blue?style=flat-square&logo=github)](https://github.com/windingwind/zotero-plugin-template)
❗The localization system is upgraded (dtd is deprecated and we do not use .properties anymore). Only supports Zotero 7.0.0-beta.12 or higher now. If you want to support Zotero 6, you may need to use
dtd
,properties
, andftl
at the same time. See the staled branchzotero6-bootstrap
.
- Event-driven, functional programming, under extensive skeleton;
- Simple and user-friendly, works out-of-the-box.
- ⭐[New!]Auto hot reload! Whenever the source code is modified, automatically compile and reload. See here→
- Abundant examples in
src/modules/examples.ts
, covering most of the commonly used APIs in plugins(using zotero-plugin-toolkit); - TypeScript support:
- Full type definition support for the whole Zotero project, which is written in JavaScript(using zotero-types);
- Global variables and environment setup;
- Plugin build/test/release workflow:
- Automatically generate/update plugin id/version, update configrations, and set environment variables(
development/production
); - Automatically build and reload code in Zotero;
- Automatically release to GitHub(using release-it);
- Automatically generate/update plugin id/version, update configrations, and set environment variables(
This repo provides examples for zotero-plugin-toolkit APIs.
Search @example
in src/examples.ts
. The examples are called in src/hooks.ts
.
- registerNotifier
- registerPrefs, unregisterPrefs
- registerShortcuts
- exampleShortcutLargerCallback
- exampleShortcutSmallerCallback
- exampleShortcutConflictionCallback
- registerStyleSheet(the official make-it-red example)
- registerRightClickMenuItem
- registerRightClickMenuPopup
- registerWindowMenuWithSeprator
- registerExtraColumn
- registerExtraColumnWithCustomCell
- registerCustomItemBoxRow
- registerLibraryTabPanel
- registerReaderTabPanel
- Preferences bindings
- UI Events
- Tabel
- Locale
See src/modules/preferenceScript.ts
- dialogExample
- clipboardExample
- filePickerExample
- progressWindowExample
- vtableExample(See Preference Pane Examples)
An Obsidian-style prompt(popup command input) module. It accepts text command to run callback, with optional display in the popup.
Activate with Shift+P
.
- registerAlertPromptExample
See how the examples work by directly downloading the xpi
file from GitHub release and install it to your Zotero.
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.
- Fork this repo/Click
Use this template
; - Git clone the forked repo;
- Enter the repo folder;
💡 Start with GitHub Codespace
GitHub CodeSpace enables you getting started without the need to download code/IDE/dependencies locally.
Replace the steps above and build you first plugin in 30 seconds!
- Goto top of the homepage, click the green button
Use this template
, clickOpen in codespace
. You may need to login to your GitHub account. - Wait for codespace to load.
-
Modify the settings in
./package.json
, including:{ version, author, description, homepage, config { releasepage, // URL to releases(`.xpi`) updaterdf, // URL to update.json addonName, // name to be displayed in the plugin manager addonID, // ID to avoid confliction. IMPORTANT! addonRef, // e.g. Element ID prefix addonInstance // the plugin's root instance: Zotero.${addonInstance} } }
Be careful to set the addonID and addonRef to avoid confliction.
-
Run
npm install
to set up the plugin and install dependencies. If you don't have NodeJS installed, please download it here; -
Run
npm run build
to build the plugin in production mode. Runnpm run build-dev
to build the plugin in development mode. The xpi for installation and the built code is underbuild
folder.What the difference between dev & prod?
- This environment variable is stored in
Zotero.${addonInstance}.data.env
. The outputs to console is disabled in prod mode. - You can decide what users cannot see/use based on this variable.
- This environment variable is stored in
To build and release, use
# 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
# release-it: https://github.com/release-it/release-it
npm run release
-
Install a beta version of Zotero: https://www.zotero.org/support/beta_builds (Zotero 7 beta: https://www.zotero.org/support/dev/zotero_7_for_developers)
-
Install Firefox 102 (for Zotero 7)
-
Copy zotero command line config file. Modify the commands that starts your installation of the beta Zotero.
(Optional) Do this only once: Start the beta Zotero with
/path/to/zotero -p
. Create a new profile and use it as your development profile. Put the path of the profile into theprofilePath
inzotero-cmd.json
to specify which profile to use.cp ./scripts/zotero-cmd-default.json ./scripts/zotero-cmd.json vim ./scripts/zotero-cmd.json
-
Build plugin and restart Zotero with
npm run restart
. -
Launch Firefox 102 (Zotero 7)
-
In Firefox, go to devtools, go to settings, click "enable remote debugging" and the one next to it that's also about debugging
Enter
about:debugging#/setup
in FF 102. -
In Zotero, go to setting, advanced, config editor, look up "debugging" and click on "allow remote debugging".
-
Connect to Zotero in Firefox. In FF 102, enter
localhost:6100
in the bottom input of remote-debugging page and clickadd
. -
Click
connect
in the leftside-bar of Firefox remote-debugging page. -
Click "Inspect Main Process"
Tired of endless restarting? Forget about it!
- Run
npm run start-watch
. (If Zotero is already running, usenpm run watch
) - Coding. (Yes, that's all)
When file changes are detected in src
or addon
, the plugin will be automatically compiled and reloaded.
💡 Steps to add this feature to an existing plugin
- Copy
scripts/reload.mjs
- Copy
reload
,watch
, andstart-watch
commands inpackage.json
- Run
npm install --save-dev chokidar-cli
- Done.
You can also:
- Test code snipastes in Tools->Developer->Run Javascript;
- Debug output with
Zotero.debug()
. Find the outputs in Help->Debug Output Logging->View Output; - Debug UI. Zotero is built on the Firefox XUL framework. Debug XUL UI with software like XUL Explorer.
XUL Documentation: http://www.devdoc.net/web/developer.mozilla.org/en-US/docs/XUL.html
See also
src/hooks.ts
- When install/enable/startup triggered from Zotero,
bootstrap.js
>startup
is called- Wait for Zotero ready
- Load
index.js
(the main entrance of plugin code, built fromindex.ts
) - Register resources if Zotero 7+
- In the main entrance
index.js
, the plugin object is injected underZotero
andhooks.ts
>onStartup
is called.- Initialize anything you want, including notify listeners, preference panes, and UI elements.
- When uninstall/disabled triggered from Zotero,
bootstrap.js
>shutdown
is called.events.ts
>onShutdown
is called. Remove UI elements, preference panes, or anything created by the plugin.- Remove scripts and release resources.
See also
src/index.ts
The bootstrapped plugin runs in a sandbox, which does not have default global variables like Zotero
or window
, which we used to have in the overlay plugins' window environment.
This template registers the following variables to the global scope:
Zotero, ZoteroPane, Zotero_Tabs, window, document, rootURI, ztoolkit, addon;
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. JustunregisterAll
at the exit. - Zotero 7 requires createElement()/createElementNS() → createXULElement() for remaining XUL elements, while Zotero 6 doesn't support
createXULElement
. The React.createElement-like APIcreateElement
detects namespace(xul/html/svg) and creates elements automatically, with the return element in the corresponding TS element type.
createElement(document, "div"); // returns HTMLDivElement
createElement(document, "hbox"); // returns XUL.Box
createElement(document, "button", { namespace: "xul" }); // manually set namespace. returns XUL.Button
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 (xhtml
, .flt
, et. al.).
Steps in scripts/build.mjs
:
- Clean
./build
- Copy
./addon
to./build
- Esbuild to
./build/addon/chrome/content/scripts
- Replace
__buildVersion__
and__buildTime__
in./build/addon
- Zip the
./build/addon
to./build/*.xpi
Zotero docs are outdated and incomplete. Clone https://github.com/zotero/zotero and search the keyword globally.
⭐The zotero-types provides most frequently used Zotero APIs. It's included in this template by default. Your IDE would provide hint for most of the APIs.
A trick for finding the API you want:
Search the UI label in .xhtml
/.flt
files, find the corresponding key in locale file. Then search this keys in .js
/.jsx
files.
This section shows the directory structure of a template.
- All
.js/.ts
code files are in./src
; - Addon config files:
./addon/manifest.json
; - UI files:
./addon/chrome/content/*.xhtml
. - Locale files:
./addon/locale/**/*.flt
; - Preferences file:
./addon/prefs.js
;Don't break the lines in the
prefs.js
.
|-- .eslintrc.json # eslint conf
|-- .gitattributes # git conf
|-- .github/ # github conf
|-- .gitignore # git conf
|-- .prettierrc # prettier conf
|-- .release-it.json # release-it conf
|-- .vscode # vs code conf
| |-- extensions.json
| |-- launch.json
| |-- setting.json
| `-- toolkit.code-snippets
|-- package-lock.json # npm conf
|-- package.json # npm conf
|-- LICENSE
|-- README.md
|-- addon
| |-- bootstrap.js # addon load/unload script, like a main.c
| |-- chrome
| | `-- content
| | |-- icons/
| | |-- preferences.xhtml # preference panel
| | `-- zoteroPane.css
| |-- locale # locale
| | |-- en-US
| | | |-- addon.ftl
| | | `-- preferences.ftl
| | `-- zh-CN
| | |-- addon.ftl
| | `-- preferences.ftl
| |-- manifest.json # addon config
| `-- prefs.js
|-- build/ # build dir
|-- scripts # scripts for dev
| |-- build.mjs # esbuild and replace
| |-- reload.mjs
| |-- start.mjs
| |-- stop.mjs
| `-- zotero-cmd-default.json
|-- src # source code
| |-- addon.ts # base class
| |-- hooks.ts # lifecycle hooks
| |-- index.ts # main entry
| |-- modules # sub modules
| | |-- examples.ts
| | `-- preferenceScript.ts
| `-- utils # utilities
| |-- locale.ts
| |-- prefs.ts
| |-- wait.ts
| `-- window.ts
|-- tsconfig.json # https://code.visualstudio.com/docs/languages/jsconfig
|-- typings # ts typings
| `-- global.d.ts
|-- update-template.json # template of `update.json`
`-- update.json
Use this code under AGPL. No warranties are provided. Keep the laws of your locality in mind!
If you want to change the license, please contact me at [email protected]