Merge pull request #67 from windingwind/fixWindowLoad

add: window load hook
This commit is contained in:
windingwind 2023-07-26 21:33:19 +08:00 committed by GitHub
commit 3c780febc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 154 additions and 103 deletions

103
addon/bootstrap.js vendored
View File

@ -11,6 +11,8 @@ if (typeof Zotero == "undefined") {
var chromeHandle;
var windowListener;
// 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.
@ -18,53 +20,72 @@ var chromeHandle;
// 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;
await new Promise(async (resolve) => {
if (typeof Zotero != "undefined") {
resolve();
}
}
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;
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm",
);
const windows = Services.wm.getEnumerator("navigator:browser");
let found = false;
while (windows.hasMoreElements()) {
let win = windows.getNext();
if (win.Zotero) {
Zotero = win.Zotero;
found = true;
resolve();
break;
}
}
windowListener = {
onOpenWindow: function (aWindow) {
// Wait for the window to finish loading
const domWindow = aWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
domWindow.addEventListener(
"load",
async function () {
domWindow.removeEventListener("load", arguments.callee, false);
if (!found && domWindow.Zotero) {
Zotero = domWindow.Zotero;
resolve();
} else if (
domWindow.location.href ===
"chrome://zotero/content/zoteroPane.xhtml"
) {
// Call the hook for the main window load event
// Note that this is not called the first time the window is opened
// (when Zotero is initialized), but only when the window is re-opened
// after being closed
await Zotero.__addonInstance__?.hooks.onMainWindowLoad(domWindow);
}
},
false,
);
},
onCloseWindow: function (aWindow) {
const domWindow = aWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
if (
domWindow.location.href === "chrome://zotero/content/zoteroPane.xhtml"
) {
Zotero.__addonInstance__?.hooks.onMainWindowUnload(domWindow);
}
},
};
Services.wm.addListener(windowListener);
});
}
function install(data, reason) {}
async function startup({ id, version, resourceURI, rootURI }, reason) {
await waitForZotero();
await Zotero.initializationPromise;
// String 'rootURI' introduced in Zotero 7
if (!rootURI) {
@ -100,6 +121,8 @@ function shutdown({ id, version, resourceURI, rootURI }, reason) {
if (reason === APP_SHUTDOWN) {
return;
}
Services.wm.removeListener(windowListener);
if (typeof Zotero === "undefined") {
Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
Components.interfaces.nsISupports,

View File

@ -1,14 +1,14 @@
import ZoteroToolkit from "zotero-plugin-toolkit/dist/index";
import { ColumnOptions } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { DialogHelper } from "zotero-plugin-toolkit/dist/helpers/dialog";
import hooks from "./hooks";
import { createZToolkit } from "./utils/ztoolkit";
class Addon {
public data: {
alive: boolean;
// Env type, see build.js
env: "development" | "production";
// ztoolkit: MyToolkit;
ztoolkit: ZoteroToolkit;
ztoolkit: ZToolkit;
locale?: {
current: any;
};
@ -28,47 +28,11 @@ class Addon {
this.data = {
alive: true,
env: __env__,
// ztoolkit: new MyToolkit(),
ztoolkit: new ZoteroToolkit(),
ztoolkit: createZToolkit(),
};
this.hooks = hooks;
this.api = {};
}
}
/**
* Alternatively, import toolkit modules you use to minify the plugin size.
*
* Steps to replace the default `ztoolkit: ZoteroToolkit` with your `ztoolkit: MyToolkit`:
*
* 1. Uncomment this file's line 30: `ztoolkit: new MyToolkit(),`
* and comment line 31: `ztoolkit: new ZoteroToolkit(),`.
* 2. Uncomment this file's line 10: `ztoolkit: MyToolkit;` in this file
* and comment line 11: `ztoolkit: ZoteroToolkit;`.
* 3. Uncomment `../typings/global.d.ts` line 12: `declare const ztoolkit: import("../src/addon").MyToolkit;`
* and comment line 13: `declare const ztoolkit: import("zotero-plugin-toolkit").ZoteroToolkit;`.
*
* You can now add the modules under the `MyToolkit` class.
*/
import { BasicTool, unregister } from "zotero-plugin-toolkit/dist/basic";
import { UITool } from "zotero-plugin-toolkit/dist/tools/ui";
import { PreferencePaneManager } from "zotero-plugin-toolkit/dist/managers/preferencePane";
import { DialogHelper } from "zotero-plugin-toolkit/dist/helpers/dialog";
export class MyToolkit extends BasicTool {
UI: UITool;
PreferencePane: PreferencePaneManager;
constructor() {
super();
this.UI = new UITool(this);
this.PreferencePane = new PreferencePaneManager(this);
}
unregisterAll() {
unregister(this);
}
}
export default Addon;

View File

@ -8,6 +8,7 @@ import {
import { config } from "../package.json";
import { getString, initLocale } from "./utils/locale";
import { registerPrefsScripts } from "./modules/preferenceScript";
import { createZToolkit } from "./utils/ztoolkit";
async function onStartup() {
await Promise.all([
@ -16,10 +17,19 @@ async function onStartup() {
Zotero.uiReadyPromise,
]);
initLocale();
ztoolkit.ProgressWindow.setIconURI(
"default",
`chrome://${config.addonRef}/content/icons/favicon.png`,
);
BasicExampleFactory.registerPrefs();
BasicExampleFactory.registerNotifier();
await onMainWindowLoad(window);
}
async function onMainWindowLoad(win: Window): Promise<void> {
// Create ztoolkit for every window
const _ztoolkit = createZToolkit();
addon.data.ztoolkit = _ztoolkit;
_globalThis.ztoolkit = _ztoolkit;
const popupWin = new ztoolkit.ProgressWindow(config.addonName, {
closeOnClick: true,
@ -32,10 +42,6 @@ async function onStartup() {
})
.show();
BasicExampleFactory.registerPrefs();
BasicExampleFactory.registerNotifier();
KeyExampleFactory.registerShortcuts();
await Zotero.Promise.delay(1000);
@ -81,6 +87,11 @@ async function onStartup() {
addon.hooks.onDialogEvents("dialogExample");
}
async function onMainWindowUnload(win: Window): Promise<void> {
ztoolkit.unregisterAll();
addon.data.dialog?.window?.close();
}
function onShutdown(): void {
ztoolkit.unregisterAll();
addon.data.dialog?.window?.close();
@ -173,6 +184,8 @@ function onDialogEvents(type: string) {
export default {
onStartup,
onShutdown,
onMainWindowLoad,
onMainWindowUnload,
onNotify,
onPrefsEvent,
onShortcuts,

View File

@ -7,21 +7,21 @@ const basicTool = new BasicTool();
if (!basicTool.getGlobal("Zotero")[config.addonInstance]) {
// Set global variables
_globalThis.Zotero = basicTool.getGlobal("Zotero");
_globalThis.ZoteroPane = basicTool.getGlobal("ZoteroPane");
_globalThis.Zotero_Tabs = basicTool.getGlobal("Zotero_Tabs");
_globalThis.window = basicTool.getGlobal("window");
_globalThis.document = basicTool.getGlobal("document");
defineGlobal("window");
defineGlobal("document");
defineGlobal("ZoteroPane");
defineGlobal("Zotero_Tabs");
_globalThis.addon = new Addon();
_globalThis.ztoolkit = addon.data.ztoolkit;
ztoolkit.basicOptions.log.prefix = `[${config.addonName}]`;
ztoolkit.basicOptions.log.disableConsole = addon.data.env === "production";
ztoolkit.UI.basicOptions.ui.enableElementJSONLog =
addon.data.env === "development";
ztoolkit.UI.basicOptions.ui.enableElementDOMLog =
addon.data.env === "development";
ztoolkit.basicOptions.debug.disableDebugBridgePassword =
addon.data.env === "development";
Zotero[config.addonInstance] = addon;
// Trigger addon hook for initialization
addon.hooks.onStartup();
}
function defineGlobal(name: Parameters<BasicTool["getGlobal"]>[0]) {
Object.defineProperty(_globalThis, name, {
get() {
return basicTool.getGlobal(name);
},
});
}

48
src/utils/ztoolkit.ts Normal file
View File

@ -0,0 +1,48 @@
import ZoteroToolkit from "zotero-plugin-toolkit";
import { config } from "../../package.json";
export { createZToolkit };
function createZToolkit() {
const _ztoolkit = new ZoteroToolkit();
/**
* Alternatively, import toolkit modules you use to minify the plugin size.
* You can add the modules under the `MyToolkit` class below and uncomment the following line.
*/
// const _ztoolkit = new MyToolkit();
initZToolkit(_ztoolkit);
return _ztoolkit;
}
function initZToolkit(_ztoolkit: ReturnType<typeof createZToolkit>) {
const env = __env__;
_ztoolkit.basicOptions.log.prefix = `[${config.addonName}]`;
_ztoolkit.basicOptions.log.disableConsole = env === "production";
_ztoolkit.UI.basicOptions.ui.enableElementJSONLog = __env__ === "development";
_ztoolkit.UI.basicOptions.ui.enableElementDOMLog = __env__ === "development";
_ztoolkit.basicOptions.debug.disableDebugBridgePassword =
__env__ === "development";
_ztoolkit.ProgressWindow.setIconURI(
"default",
`chrome://${config.addonRef}/content/icons/favicon.png`,
);
}
import { BasicTool, unregister } from "zotero-plugin-toolkit/dist/basic";
import { UITool } from "zotero-plugin-toolkit/dist/tools/ui";
import { PreferencePaneManager } from "zotero-plugin-toolkit/dist/managers/preferencePane";
class MyToolkit extends BasicTool {
UI: UITool;
PreferencePane: PreferencePaneManager;
constructor() {
super();
this.UI = new UITool(this);
this.PreferencePane = new PreferencePaneManager(this);
}
unregisterAll() {
unregister(this);
}
}

9
typings/global.d.ts vendored
View File

@ -5,12 +5,15 @@ declare const _globalThis: {
Zotero_Tabs: typeof Zotero_Tabs;
window: Window;
document: Document;
ztoolkit: typeof ztoolkit;
ztoolkit: ZToolkit;
addon: typeof addon;
};
// declare const ztoolkit: import("../src/addon").MyToolkit;
declare const ztoolkit: import("zotero-plugin-toolkit").ZoteroToolkit;
declare type ZToolkit = ReturnType<
typeof import("../src/utils/ztoolkit").createZToolkit
>;
declare const ztoolkit: ZToolkit;
declare const rootURI: string;