init: bootstrap extension mode

This commit is contained in:
xiangyu 2022-09-13 12:37:09 +08:00
parent 9976511dc9
commit cfd3014559
14 changed files with 144 additions and 47 deletions

View File

@ -2,6 +2,12 @@
This is an addon/plugin template for [Zotero](https://www.zotero.org/).
[Documentation](https://zotero.yuque.com/books/share/8d230829-6004-4934-b4c6-685a7001bfa0/vec88d)(Chinese, provides English translation)
> 👍You are currently in `bootstrap` extension mode. To use `overlay` mode, plsase switch to `overlay` branch in git.
> ⚠️`overlay` mode will no longer be supported in the coming Zotero 7. Please use the `bootstrap` extension mode instead. See discussion here: https://groups.google.com/g/zotero-dev/c/TT_rcLVpQwg
## Features
- TypeScript support;
@ -49,7 +55,7 @@ This section shows the directory structure of a template.
```shell
│ .gitignore
│ .release-it.json # release-it conf
| jsconfig.json # https://code.visualstudio.com/docs/languages/jsconfig#
| tsconfig.json # https://code.visualstudio.com/docs/languages/jsconfig#
│ build.js # esbuild
│ LICENSE
│ package.json # npm conf
@ -61,10 +67,10 @@ This section shows the directory structure of a template.
├─addon # addon dir
│ │ chrome.manifest #addon conf
│ │ install.rdf # addon install conf
│ │ bootstrap.js # addon load/unload script, like a main.c
│ │
│ └─chrome
│ ├─content # UI
│ │ │ overlay.xul
│ │ │ preferences.xul
│ │ │
│ │ └─scripts
@ -152,6 +158,8 @@ You can also debug code in these ways:
Zotero docs are outdated or incomplete. Searching the source code of Zotero is unavoidable.
Clone https://github.com/zotero/zotero and search the keyword globally. You can search the UI text in `.xul`/`.dtd` files, and then search the keys of the text value in `.js`/`.xul` files.
> ⭐The [zotero-types](https://github.com/windingwind/zotero-types) provides most frequently used Zotero APIs. It's included in this template by default.
## Disclaimer
Use this code under AGPL. No warranties are provided. Keep the laws of your locality in mind!

71
addon/bootstrap.js vendored Normal file
View File

@ -0,0 +1,71 @@
/* Copyright 2012 Will Shanks.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* global Components, Services */
/* global addon, APP_SHUTDOWN */
const { classes: Cc, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
function install(data, reason) {}
function startup(data, reason) {
// Load the addon to Zotero if window is ready
const loadAddon = (window) => {
console.log(window);
if (window.document.readyState === "complete" && window.Zotero) {
Services.scriptloader.loadSubScript(
"chrome://__addonRef__/content/scripts/index.js"
);
} else {
window.addEventListener("load", (e) => {
if (window.Zotero) {
Services.scriptloader.loadSubScript(
"chrome://__addonRef__/content/scripts/index.js"
);
}
});
}
};
// Listen to windows
var WindowListener = {
onOpenWindow: function (xulWindow) {
loadAddon(
xulWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow)
);
},
};
Services.wm.addListener(WindowListener);
// Scan current windows
const windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
loadAddon(
windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow)
);
}
}
function shutdown(data, reason) {
if (reason === APP_SHUTDOWN) {
return;
}
var _Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
Components.interfaces.nsISupports
).wrappedJSObject;
_Zotero.AddonTemplate.events.onUnInit(_Zotero);
Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService)
.flushBundles();
Cu.unload("chrome://_addonRef__/scripts/index.js");
}
function uninstall(data, reason) {}

View File

@ -2,6 +2,3 @@ content __addonRef__ chrome/content/
skin __addonRef__ default chrome/skin/default/__addonRef__/
locale __addonRef__ en-US chrome/locale/en-US/
locale __addonRef__ zh-CN chrome/locale/zh-CN/
overlay chrome://zotero/content/zoteroPane.xul chrome://__addonRef__/content/overlay.xul
overlay chrome://zotero/content/preferences/preferences.xul chrome://__addonRef__/content/preferences.xul

View File

@ -1,11 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://__addonRef__/skin/overlay.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://__addonRef__/locale/overlay.dtd">
<overlay id="__addonRef__" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://__addonRef__/content/scripts/index.js" />
<popup id="zotero-itemmenu">
<menuseparator />
<menuitem id="zotero-itemmenu-__addonRef__-test" label="&zotero.__addonRef__.itemmenu.test.label;" oncommand="alert('Hello World!')" class="menuitem-iconic" style="list-style-image: url('chrome://__addonRef__/skin/favicon@0.5x.png');" />
</popup>
</overlay>

View File

@ -1,14 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE window SYSTEM "chrome://__addonRef__/locale/overlay.dtd">
<!DOCTYPE prefwindow SYSTEM "chrome://__addonRef__/locale/overlay.dtd">
<overlay id="__addonRef__-preferences" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/preferences.css"?>
<prefwindow id="zotero-prefs">
<prefpane id="zotero-prefpane-__addonRef__" insertafter="zotero-prefpane-advanced" label="__addonName__" image="chrome://__addonRef__/skin/favicon.png" onpaneload="Zotero.AddonTemplate.prefs.initPreferences(window)">
<preferences id="zotero-preferences-__addonRef__">
<preference id="pref-__addonRef__-enable" name="extensions.zotero.__addonRef__.enable" type="bool" />
</preferences>
<checkbox id="zotero-prefpane-__addonRef__-enable" preference="pref-__addonRef__-enable" label="&zotero.__addonRef__.pref.enable.label;" />
</prefpane>
</prefwindow>
</overlay>
<prefwindow id="__addonRef__-prefs" title="&zotero.__addonRef__.pref.title;" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://zotero/content/include.js" />
<prefpane id=" zotero-prefpane-__addonRef__" insertafter=" zotero-prefpane-advanced" label=" __addonName__" image=" chrome: __addonRef__ skin favicon.png" onpaneload=" Zotero.AddonTemplate.prefs.initPreferences(window)">
<preferences id=" zotero-preferences-__addonRef__">
<preference id=" pref-__addonRef__-enable" name=" extensions.zotero.__addonRef__.enable" type=" bool" />
</preferences>
<checkbox id=" zotero-prefpane-__addonRef__-enable" preference=" pref-__addonRef__-enable" label=" &zotero.__addonRef__.pref.enable.label;" />
</prefpane>
</prefwindow>

View File

Before

Width:  |  Height:  |  Size: 677 B

After

Width:  |  Height:  |  Size: 677 B

View File

Before

Width:  |  Height:  |  Size: 836 B

After

Width:  |  Height:  |  Size: 836 B

View File

@ -13,7 +13,10 @@
em:description="__description__"
em:homepageURL="__homepage__"
em:iconURL="chrome://__addonRef__/skin/favicon.png"
em:updateURL="__updaterdf__">>
em:optionsURL="chrome://__addonRef__/content/preferences.xul"
em:updateURL="__updaterdf__"
em:multiprocessCompatible="true"
em:bootstrap="true">>
<em:type>2</em:type>
<em:targetApplication RDF:resource="rdf:#$x61SL3"/>
<em:targetApplication>

View File

@ -115,6 +115,7 @@ async function main() {
path.join(buildDir, "**/*.xul"),
path.join(buildDir, "**/*.manifest"),
path.join(buildDir, "addon/defaults", "**/*.js"),
path.join(buildDir, "addon/bootstrap.js"),
"update.rdf",
],
from: [

View File

@ -34,6 +34,6 @@
},
"devDependencies": {
"release-it": "^14.14.0",
"zotero-types": "^0.0.3"
"zotero-types": "^0.0.4"
}
}

View File

@ -27,30 +27,32 @@ class AddonEvents extends AddonModule {
};
}
public async onInit() {
public async onInit(_Zotero) {
// This function is the setup code of the addon
Zotero.debug(`${addonName}: init called`);
console.log(`${addonName}: init called`);
_Zotero.debug(`${addonName}: init called`);
// alert(112233);
// Reset prefs
this.resetState();
// Register the callback in Zotero as an item observer
let notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, [
let notifierID = _Zotero.Notifier.registerObserver(this.notifierCallback, [
"tab",
"item",
"file",
]);
// Unregister callback when the window closes (important to avoid a memory leak)
window.addEventListener(
_Zotero.getMainWindow().addEventListener(
"unload",
function (e) {
Zotero.Notifier.unregisterObserver(notifierID);
_Zotero.Notifier.unregisterObserver(notifierID);
},
false
);
this._Addon.views.initViews();
this._Addon.views.initViews(_Zotero);
}
private resetState(): void {
@ -65,6 +67,15 @@ class AddonEvents extends AddonModule {
// Zotero.Prefs.set("addonTemplate.testPref", true);
// }
}
public onUnInit(_Zotero): void {
console.log(`${addonName}: uninit called`);
_Zotero.debug(`${addonName}: uninit called`);
// Remove elements and do clean up
this._Addon.views.unInitViews(_Zotero);
// Remove addon object
_Zotero.AddonTemplate = undefined;
}
}
export default AddonEvents;

View File

@ -1,11 +1,9 @@
import { Addon } from "./addon";
Zotero.AddonTemplate = new Addon();
window.addEventListener(
"load",
async function (e) {
Zotero.AddonTemplate.events.onInit();
},
false
);
var _Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
Components.interfaces.nsISupports
).wrappedJSObject;
if (!_Zotero.AddonTemplate) {
_Zotero.AddonTemplate = new Addon();
_Zotero.AddonTemplate.events.onInit(_Zotero);
}

View File

@ -16,9 +16,27 @@ class AddonViews extends AddonModule {
};
}
public initViews() {
public initViews(_Zotero) {
// You can init the UI elements that
// cannot be initialized with overlay.xul
console.log("Initializing UI");
const _window: Window = _Zotero.getMainWindow();
const menuitem = _window.document.createElement("menuitem");
menuitem.id = "zotero-itemmenu-addontemplate-test";
menuitem.setAttribute("label", "Addon Template");
menuitem.setAttribute("oncommand", "alert('Hello World!')");
menuitem.className = "menuitem-iconic";
menuitem.style["list-style-image"] =
"url('chrome://addontemplate/skin/favicon@0.5x.png')";
_window.document.querySelector("#zotero-itemmenu").appendChild(menuitem);
}
public unInitViews(_Zotero) {
console.log("Uninitializing UI");
const _window: Window = _Zotero.getMainWindow();
_window.document
.querySelector("#zotero-itemmenu-addontemplate-test")
?.remove();
}
public showProgressWindow(

View File

@ -11,7 +11,7 @@
<em:id>zotero@chnm.gmu.edu</em:id>
<em:minVersion>5.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
<em:updateLink>__releasepage__</em:updateLink>
<em:updateLink>https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi</em:updateLink>
</rdf:Description>
</em:targetApplication>
<em:targetApplication>
@ -19,7 +19,7 @@
<em:id>juris-m@juris-m.github.io</em:id>
<em:minVersion>5.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
<em:updateLink>__releasepage__</em:updateLink>
<em:updateLink>https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi</em:updateLink>
</rdf:Description>
</em:targetApplication>
</rdf:Description>