init: bootstrap extension mode
This commit is contained in:
parent
9976511dc9
commit
cfd3014559
12
README.md
12
README.md
@ -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
71
addon/bootstrap.js
vendored
Normal 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) {}
|
@ -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
|
||||
|
@ -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>
|
@ -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>
|
Before Width: | Height: | Size: 677 B After Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 836 B |
@ -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>
|
||||
|
1
build.js
1
build.js
@ -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: [
|
||||
|
@ -34,6 +34,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"release-it": "^14.14.0",
|
||||
"zotero-types": "^0.0.3"
|
||||
"zotero-types": "^0.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
16
src/index.ts
16
src/index.ts
@ -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);
|
||||
}
|
||||
|
20
src/views.ts
20
src/views.ts
@ -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(
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user