update: bootstrap for zotero 7
This commit is contained in:
parent
51bbc58590
commit
56ac4d5320
137
addon/bootstrap.js
vendored
137
addon/bootstrap.js
vendored
@ -3,69 +3,114 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
"use strict";
|
if (typeof Zotero == "undefined") {
|
||||||
/* global Components, Services */
|
var Zotero;
|
||||||
/* global addon, APP_SHUTDOWN */
|
}
|
||||||
const { classes: Cc, utils: Cu } = Components;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
// In Zotero 6, bootstrap methods are called before Zotero is initialized, and using include.js
|
||||||
|
// to get the Zotero XPCOM service would risk breaking Zotero startup. Instead, wait for the main
|
||||||
|
// Zotero window to open and get the Zotero object from there.
|
||||||
|
//
|
||||||
|
// In Zotero 7, bootstrap methods are not called until Zotero is initialized, and the 'Zotero' is
|
||||||
|
// automatically made available.
|
||||||
|
async function waitForZotero() {
|
||||||
|
if (typeof Zotero != "undefined") {
|
||||||
|
await Zotero.initializationPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
var windows = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
var found = false;
|
||||||
|
while (windows.hasMoreElements()) {
|
||||||
|
let win = windows.getNext();
|
||||||
|
if (win.Zotero) {
|
||||||
|
Zotero = win.Zotero;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
var listener = {
|
||||||
|
onOpenWindow: function (aWindow) {
|
||||||
|
// Wait for the window to finish loading
|
||||||
|
let domWindow = aWindow
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
|
||||||
|
domWindow.addEventListener(
|
||||||
|
"load",
|
||||||
|
function () {
|
||||||
|
domWindow.removeEventListener("load", arguments.callee, false);
|
||||||
|
if (domWindow.Zotero) {
|
||||||
|
Services.wm.removeListener(listener);
|
||||||
|
Zotero = domWindow.Zotero;
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Services.wm.addListener(listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await Zotero.initializationPromise;
|
||||||
|
}
|
||||||
|
|
||||||
function install(data, reason) {}
|
function install(data, reason) {}
|
||||||
|
|
||||||
function startup(data, reason) {
|
async function startup({ id, version, resourceURI, rootURI }, reason) {
|
||||||
// Load the addon to Zotero if window is ready
|
await waitForZotero();
|
||||||
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
|
// String 'rootURI' introduced in Zotero 7
|
||||||
var WindowListener = {
|
if (!rootURI) {
|
||||||
onOpenWindow: function (xulWindow) {
|
rootURI = resourceURI.spec;
|
||||||
loadAddon(
|
}
|
||||||
xulWindow
|
|
||||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Components.interfaces.nsIDOMWindow)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Services.wm.addListener(WindowListener);
|
|
||||||
|
|
||||||
// Scan current windows
|
Services.scriptloader.loadSubScript(
|
||||||
const windows = Services.wm.getEnumerator("navigator:browser");
|
`${rootURI}/chrome/content/scripts/index.js`
|
||||||
while (windows.hasMoreElements()) {
|
);
|
||||||
loadAddon(
|
|
||||||
windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow)
|
Zotero.AddonTemplate.rootURI = rootURI;
|
||||||
);
|
|
||||||
|
if (Zotero.platformMajorVersion >= 102) {
|
||||||
|
var aomStartup = Components.Cc[
|
||||||
|
"@mozilla.org/addons/addon-manager-startup;1"
|
||||||
|
].getService(Components.Ci.amIAddonManagerStartup);
|
||||||
|
var manifestURI = Services.io.newURI(rootURI + "manifest.json");
|
||||||
|
var chromeHandle = aomStartup.registerChrome(manifestURI, [
|
||||||
|
["content", "__addonRef__", "chrome/content/"],
|
||||||
|
["locale", "__addonRef__", "en-US", "chrome/locale/en-US/"],
|
||||||
|
["locale", "__addonRef__", "zh-CN", "chrome/locale/zh-CN/"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
Zotero.PreferencePanes.register({
|
||||||
|
pluginID: "__addonID__",
|
||||||
|
src: `${rootURI}/chrome/content/preferences.xhtml`,
|
||||||
|
extraDTD: [`chrome://__addonRef__/locale/overlay.dtd`],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shutdown(data, reason) {
|
function shutdown({ id, version, resourceURI, rootURI }, reason) {
|
||||||
if (reason === APP_SHUTDOWN) {
|
if (reason === APP_SHUTDOWN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var _Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
|
if (typeof Zotero === "undefined") {
|
||||||
Components.interfaces.nsISupports
|
Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
|
||||||
).wrappedJSObject;
|
Components.interfaces.nsISupports
|
||||||
_Zotero.AddonTemplate.events.onUnInit(_Zotero);
|
).wrappedJSObject;
|
||||||
|
}
|
||||||
|
Zotero.AddonTemplate.events.onUnInit(Zotero);
|
||||||
|
|
||||||
Cc["@mozilla.org/intl/stringbundle;1"]
|
Cc["@mozilla.org/intl/stringbundle;1"]
|
||||||
.getService(Components.interfaces.nsIStringBundleService)
|
.getService(Components.interfaces.nsIStringBundleService)
|
||||||
.flushBundles();
|
.flushBundles();
|
||||||
|
|
||||||
Cu.unload("chrome://_addonRef__/scripts/index.js");
|
Cu.unload(`${rootURI}/chrome/content/scripts/index.js`);
|
||||||
|
|
||||||
|
chromeHandle.destruct();
|
||||||
|
chromeHandle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function uninstall(data, reason) {}
|
function uninstall(data, reason) {}
|
||||||
|
13
addon/chrome/content/preferences.xhtml
Normal file
13
addon/chrome/content/preferences.xhtml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<xul:vbox
|
||||||
|
id="zotero-prefpane-__addonRef__"
|
||||||
|
onload="Zotero.AddonTemplate.prefs.initPreferences(window)"
|
||||||
|
>
|
||||||
|
<xul:groupbox>
|
||||||
|
<label><h2>Addon Template Example</h2></label>
|
||||||
|
<xul:checkbox
|
||||||
|
id="zotero-prefpane-__addonRef__-enable"
|
||||||
|
preference="pref-__addonRef__-enable"
|
||||||
|
label="&zotero.__addonRef__.pref.enable.label;"
|
||||||
|
/>
|
||||||
|
</xul:groupbox>
|
||||||
|
</xul:vbox>
|
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE prefwindow SYSTEM "chrome://__addonRef__/locale/overlay.dtd">
|
|
||||||
|
|
||||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
|
||||||
<?xml-stylesheet href="chrome://zotero-platform/content/preferences.css"?>
|
|
||||||
|
|
||||||
<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>
|
|
19
addon/manifest.json
Normal file
19
addon/manifest.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "__addonName__",
|
||||||
|
"version": "__buildVersion__",
|
||||||
|
"description": "__description__",
|
||||||
|
"author": "__author__",
|
||||||
|
"icons": {
|
||||||
|
"48": "chrome/skin/default/__addonRef__/favicon@0.5x.png",
|
||||||
|
"96": "chrome/skin/default/__addonRef__/favicon.png"
|
||||||
|
},
|
||||||
|
"applications": {
|
||||||
|
"zotero": {
|
||||||
|
"id": "__addonID__",
|
||||||
|
"update_url": "__updaterdf__",
|
||||||
|
"strict_min_version": "6.999",
|
||||||
|
"strict_max_version": "7.0.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
build.js
10
build.js
@ -96,6 +96,8 @@ async function main() {
|
|||||||
|
|
||||||
copyFolderRecursiveSync("addon", buildDir);
|
copyFolderRecursiveSync("addon", buildDir);
|
||||||
|
|
||||||
|
copyFileSync("update-template.json", "update.json");
|
||||||
|
|
||||||
await esbuild
|
await esbuild
|
||||||
.build({
|
.build({
|
||||||
entryPoints: ["src/index.ts"],
|
entryPoints: ["src/index.ts"],
|
||||||
@ -113,10 +115,12 @@ async function main() {
|
|||||||
path.join(buildDir, "**/*.rdf"),
|
path.join(buildDir, "**/*.rdf"),
|
||||||
path.join(buildDir, "**/*.dtd"),
|
path.join(buildDir, "**/*.dtd"),
|
||||||
path.join(buildDir, "**/*.xul"),
|
path.join(buildDir, "**/*.xul"),
|
||||||
path.join(buildDir, "**/*.manifest"),
|
path.join(buildDir, "**/*.xhtml"),
|
||||||
|
path.join(buildDir, "**/*.json"),
|
||||||
path.join(buildDir, "addon/defaults", "**/*.js"),
|
path.join(buildDir, "addon/defaults", "**/*.js"),
|
||||||
|
path.join(buildDir, "addon/chrome.manifest"),
|
||||||
path.join(buildDir, "addon/bootstrap.js"),
|
path.join(buildDir, "addon/bootstrap.js"),
|
||||||
"update.rdf",
|
"update.json",
|
||||||
],
|
],
|
||||||
from: [
|
from: [
|
||||||
/__author__/g,
|
/__author__/g,
|
||||||
@ -129,7 +133,6 @@ async function main() {
|
|||||||
/__addonRef__/g,
|
/__addonRef__/g,
|
||||||
/__buildVersion__/g,
|
/__buildVersion__/g,
|
||||||
/__buildTime__/g,
|
/__buildTime__/g,
|
||||||
/<em:version>\S*<\/em:version>/g,
|
|
||||||
],
|
],
|
||||||
to: [
|
to: [
|
||||||
author,
|
author,
|
||||||
@ -142,7 +145,6 @@ async function main() {
|
|||||||
addonRef,
|
addonRef,
|
||||||
version,
|
version,
|
||||||
buildTime,
|
buildTime,
|
||||||
`<em:version>${version}</em:version>`,
|
|
||||||
],
|
],
|
||||||
countMatches: true,
|
countMatches: true,
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,8 @@
|
|||||||
"replace-in-file": "^6.3.2"
|
"replace-in-file": "^6.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.7.20",
|
||||||
"release-it": "^14.14.0",
|
"release-it": "^14.14.0",
|
||||||
"zotero-types": "^0.0.4"
|
"zotero-types": "^0.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
src/addon.ts
29
src/addon.ts
@ -8,6 +8,8 @@ class Addon {
|
|||||||
public events: AddonEvents;
|
public events: AddonEvents;
|
||||||
public views: AddonViews;
|
public views: AddonViews;
|
||||||
public prefs: AddonPrefs;
|
public prefs: AddonPrefs;
|
||||||
|
// root path to access the resources
|
||||||
|
public rootURI: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.events = new AddonEvents(this);
|
this.events = new AddonEvents(this);
|
||||||
@ -16,4 +18,29 @@ class Addon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { addonName, Addon };
|
function getZotero(): _ZoteroConstructable {
|
||||||
|
if (typeof Zotero === "undefined") {
|
||||||
|
return Components.classes["@zotero.org/Zotero;1"].getService(
|
||||||
|
Components.interfaces.nsISupports
|
||||||
|
).wrappedJSObject;
|
||||||
|
}
|
||||||
|
return Zotero;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isZotero7(): boolean {
|
||||||
|
return Zotero.platformMajorVersion >= 102;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createXULElement(doc: Document, type: string): XUL.Element {
|
||||||
|
if (isZotero7()) {
|
||||||
|
// @ts-ignore
|
||||||
|
return doc.createXULElement(type);
|
||||||
|
} else {
|
||||||
|
return doc.createElementNS(
|
||||||
|
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||||
|
type
|
||||||
|
) as XUL.Element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { addonName, Addon, getZotero, isZotero7, createXULElement };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Addon, addonName } from "./addon";
|
import { Addon, addonName, getZotero } from "./addon";
|
||||||
import AddonModule from "./module";
|
import AddonModule from "./module";
|
||||||
|
|
||||||
class AddonEvents extends AddonModule {
|
class AddonEvents extends AddonModule {
|
||||||
@ -27,32 +27,33 @@ class AddonEvents extends AddonModule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onInit(_Zotero) {
|
public async onInit() {
|
||||||
|
const Zotero = getZotero();
|
||||||
// This function is the setup code of the addon
|
// This function is the setup code of the addon
|
||||||
console.log(`${addonName}: init called`);
|
Zotero.debug(`${addonName}: init called`);
|
||||||
_Zotero.debug(`${addonName}: init called`);
|
|
||||||
// alert(112233);
|
// alert(112233);
|
||||||
|
|
||||||
// Reset prefs
|
// Reset prefs
|
||||||
this.resetState();
|
this.resetState();
|
||||||
|
|
||||||
// Register the callback in Zotero as an item observer
|
// Register the callback in Zotero as an item observer
|
||||||
let notifierID = _Zotero.Notifier.registerObserver(this.notifierCallback, [
|
let notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, [
|
||||||
"tab",
|
"tab",
|
||||||
"item",
|
"item",
|
||||||
"file",
|
"file",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Unregister callback when the window closes (important to avoid a memory leak)
|
// Unregister callback when the window closes (important to avoid a memory leak)
|
||||||
_Zotero.getMainWindow().addEventListener(
|
Zotero.getMainWindow().addEventListener(
|
||||||
"unload",
|
"unload",
|
||||||
function (e) {
|
function (e) {
|
||||||
_Zotero.Notifier.unregisterObserver(notifierID);
|
Zotero.Notifier.unregisterObserver(notifierID);
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
this._Addon.views.initViews(_Zotero);
|
this._Addon.views.initViews();
|
||||||
|
this._Addon.views.initPrefs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetState(): void {
|
private resetState(): void {
|
||||||
@ -68,13 +69,13 @@ class AddonEvents extends AddonModule {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public onUnInit(_Zotero): void {
|
public onUnInit(): void {
|
||||||
console.log(`${addonName}: uninit called`);
|
const Zotero = getZotero();
|
||||||
_Zotero.debug(`${addonName}: uninit called`);
|
Zotero.debug(`${addonName}: uninit called`);
|
||||||
// Remove elements and do clean up
|
// Remove elements and do clean up
|
||||||
this._Addon.views.unInitViews(_Zotero);
|
this._Addon.views.unInitViews();
|
||||||
// Remove addon object
|
// Remove addon object
|
||||||
_Zotero.AddonTemplate = undefined;
|
Zotero.AddonTemplate = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
src/index.ts
13
src/index.ts
@ -1,9 +1,8 @@
|
|||||||
import { Addon } from "./addon";
|
import { Addon, getZotero } from "./addon";
|
||||||
|
|
||||||
var _Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
|
const Zotero = getZotero();
|
||||||
Components.interfaces.nsISupports
|
|
||||||
).wrappedJSObject;
|
if (!Zotero.AddonTemplate) {
|
||||||
if (!_Zotero.AddonTemplate) {
|
Zotero.AddonTemplate = new Addon();
|
||||||
_Zotero.AddonTemplate = new Addon();
|
Zotero.AddonTemplate.events.onInit();
|
||||||
_Zotero.AddonTemplate.events.onInit(_Zotero);
|
|
||||||
}
|
}
|
||||||
|
35
src/views.ts
35
src/views.ts
@ -1,6 +1,6 @@
|
|||||||
import { Addon } from "./addon";
|
import { Addon, getZotero, createXULElement } from "./addon";
|
||||||
import AddonModule from "./module";
|
import AddonModule from "./module";
|
||||||
const { addonRef } = require("../package.json");
|
const { addonRef, addonID } = require("../package.json");
|
||||||
|
|
||||||
class AddonViews extends AddonModule {
|
class AddonViews extends AddonModule {
|
||||||
// You can store some element in the object attributes
|
// You can store some element in the object attributes
|
||||||
@ -16,24 +16,35 @@ class AddonViews extends AddonModule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public initViews(_Zotero) {
|
public initViews() {
|
||||||
|
const Zotero = getZotero();
|
||||||
// You can init the UI elements that
|
// You can init the UI elements that
|
||||||
// cannot be initialized with overlay.xul
|
// cannot be initialized with overlay.xul
|
||||||
console.log("Initializing UI");
|
Zotero.debug("Initializing UI");
|
||||||
const _window: Window = _Zotero.getMainWindow();
|
const _window: Window = Zotero.getMainWindow();
|
||||||
const menuitem = _window.document.createElement("menuitem");
|
const menuitem = createXULElement(_window.document, "menuitem");
|
||||||
menuitem.id = "zotero-itemmenu-addontemplate-test";
|
menuitem.id = "zotero-itemmenu-addontemplate-test";
|
||||||
menuitem.setAttribute("label", "Addon Template");
|
menuitem.setAttribute("label", "Addon Template");
|
||||||
menuitem.setAttribute("oncommand", "alert('Hello World!')");
|
menuitem.setAttribute("oncommand", "alert('Hello World!')");
|
||||||
menuitem.className = "menuitem-iconic";
|
// menuitem.className = "menuitem-iconic";
|
||||||
menuitem.style["list-style-image"] =
|
// menuitem.style["list-style-image"] =
|
||||||
"url('chrome://addontemplate/skin/favicon@0.5x.png')";
|
// "url('chrome/skin/default/addontemplate/favicon@0.5x.png')";
|
||||||
_window.document.querySelector("#zotero-itemmenu").appendChild(menuitem);
|
_window.document.querySelector("#zotero-itemmenu").appendChild(menuitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unInitViews(_Zotero) {
|
public initPrefs() {
|
||||||
console.log("Uninitializing UI");
|
const Zotero = getZotero();
|
||||||
const _window: Window = _Zotero.getMainWindow();
|
Zotero.PreferencePanes.register({
|
||||||
|
pluginID: addonID,
|
||||||
|
src: `${this._Addon.rootURI}/chrome/content/preferences.xhtml`,
|
||||||
|
extraDTD: [`chrome://${addonRef}/locale/overlay.dtd`],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public unInitViews() {
|
||||||
|
const Zotero = getZotero();
|
||||||
|
Zotero.debug("Uninitializing UI");
|
||||||
|
const _window: Window = Zotero.getMainWindow();
|
||||||
_window.document
|
_window.document
|
||||||
.querySelector("#zotero-itemmenu-addontemplate-test")
|
.querySelector("#zotero-itemmenu-addontemplate-test")
|
||||||
?.remove();
|
?.remove();
|
||||||
|
26
update-template.json
Normal file
26
update-template.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"addons": {
|
||||||
|
"__addonID__": {
|
||||||
|
"updates": [
|
||||||
|
{
|
||||||
|
"version": "__buildVersion__",
|
||||||
|
"update_link": "__releasepage__",
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"strict_min_version": "60.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "__buildVersion__",
|
||||||
|
"update_link": "__releasepage__",
|
||||||
|
"applications": {
|
||||||
|
"zotero": {
|
||||||
|
"strict_min_version": "6.999"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
update.json
Normal file
26
update.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"addons": {
|
||||||
|
"addontemplate@euclpts.com": {
|
||||||
|
"updates": [
|
||||||
|
{
|
||||||
|
"version": "0.0.0",
|
||||||
|
"update_link": "https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi",
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"strict_min_version": "60.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "0.0.0",
|
||||||
|
"update_link": "https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi",
|
||||||
|
"applications": {
|
||||||
|
"zotero": {
|
||||||
|
"strict_min_version": "6.999"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user