diff --git a/src/hooks.ts b/src/hooks.ts index 5d8b1bb..1475f91 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -1,34 +1,36 @@ import { BasicExampleFactory, UIExampleFactory } from "./modules/examples"; -import { - changeProgressWindowLine, - isProgressWindow, - showProgressWindow, -} from "./modules/progressWindow"; +import { PopupWindow } from "./modules/popup"; import { config } from "../package.json"; import { getString, initLocale } from "./modules/locale"; import { registerPrefsScripts } from "./modules/preferenceScript"; async function onStartup() { + await Promise.all([ + Zotero.initializationPromise, + Zotero.unlockPromise, + Zotero.uiReadyPromise, + ]); initLocale(); - const progWin = showProgressWindow( - config.addonName, - getString("startup.begin"), - "default", - { - closeTime: -1, - } - ); - changeProgressWindowLine(progWin, { newProgress: 0 }); + const popupWin = new PopupWindow(config.addonName, { + closeOnClick: true, + closeTime: -1, + }) + .createLine({ + text: getString("startup.begin"), + type: "default", + progress: 0, + }) + .show(); BasicExampleFactory.registerPrefs(); BasicExampleFactory.registerNotifier(); await Zotero.Promise.delay(1000); - changeProgressWindowLine(progWin, { - newProgress: 30, - newText: `[30%] ${getString("startup.begin")}`, + popupWin.changeLine({ + progress: 30, + text: `[30%] ${getString("startup.begin")}`, }); UIExampleFactory.registerStyleSheet(); @@ -50,13 +52,12 @@ async function onStartup() { await UIExampleFactory.registerReaderTabPanel(); await Zotero.Promise.delay(1000); - changeProgressWindowLine(progWin, { - newProgress: 100, - newText: `[100%] ${getString("startup.finish")}`, + + popupWin.changeLine({ + progress: 100, + text: `[100%] ${getString("startup.finish")}`, }); - if (isProgressWindow(progWin)) { - (progWin as _ZoteroProgressWindow).startCloseTimer(5000); - } + popupWin.startCloseTimer(5000); } function onShutdown(): void { diff --git a/src/modules/examples.ts b/src/modules/examples.ts index d5de070..a90a3be 100644 --- a/src/modules/examples.ts +++ b/src/modules/examples.ts @@ -1,6 +1,6 @@ import { config } from "../../package.json"; import { getString } from "./locale"; -import { showProgressWindow } from "./progressWindow"; +import { PopupWindow } from "./popup"; function example( target: any, @@ -35,7 +35,7 @@ export class BasicExampleFactory { ids: Array, extraData: { [key: string]: any } ) => { - if (!addon.data.alive) { + if (!addon?.data.alive) { this.unregisterNotifier(notifierID); return; } @@ -62,7 +62,13 @@ export class BasicExampleFactory { @example static exampleNotifierCallback() { - showProgressWindow(config.addonName, "Open Tab Detected!", "success"); + new PopupWindow(config.addonName) + .createLine({ + text: "Open Tab Detected!", + type: "success", + progress: 100, + }) + .show(); } @example diff --git a/src/modules/popup.ts b/src/modules/popup.ts new file mode 100644 index 0000000..ffc07c6 --- /dev/null +++ b/src/modules/popup.ts @@ -0,0 +1,90 @@ +import { config } from "../../package.json"; + +const progressWindowIcon = { + success: "chrome://zotero/skin/tick.png", + fail: "chrome://zotero/skin/cross.png", + default: `chrome://${config.addonRef}/content/icons/favicon.png`, +}; + +interface LineOptions { + type?: keyof typeof progressWindowIcon; + icon?: string; + text?: string; + progress?: number; + idx?: number; +} + +// @ts-ignore +export class PopupWindow extends Zotero.ProgressWindow { + private lines: _ZoteroItemProgress[]; + private closeTime: number | undefined; + private originalShow: Function; + public show: typeof this.showWithTimer; + + constructor( + header: string, + options: { + window?: Window; + closeOnClick?: boolean; + closeTime?: number; + } = { + closeOnClick: true, + closeTime: 5000, + } + ) { + super(options); + this.lines = []; + this.closeTime = options.closeTime || 5000; + this.changeHeadline(header); + // @ts-ignore + this.originalShow = this.show; + this.show = this.showWithTimer; + } + + createLine(options: LineOptions) { + const icon = this.getIcon(options.type, options.icon); + const line = new this.ItemProgress( + icon || "", + options.text || "" + ) as _ZoteroItemProgress; + if (typeof options.progress === "number") { + line.setProgress(options.progress); + } + this.lines.push(line); + return this; + } + + changeLine(options: LineOptions) { + if (this.lines?.length === 0) { + return this; + } + const idx = + typeof options.idx !== "undefined" && + options.idx >= 0 && + options.idx < this.lines.length + ? options.idx + : 0; + const icon = this.getIcon(options.type, options.icon); + options.text && this.lines[idx].setText(options.text); + icon && this.lines[idx].setIcon(icon); + typeof options.progress === "number" && + this.lines[idx].setProgress(options.progress); + return this; + } + + protected showWithTimer(closeTime: number | undefined = undefined) { + this.originalShow(); + typeof closeTime !== "undefined" && (this.closeTime = closeTime); + if (this.closeTime && this.closeTime > 0) { + this.startCloseTimer(this.closeTime); + } + return this; + } + + protected getIcon( + type: keyof typeof progressWindowIcon | undefined, + defaulIcon?: string | undefined + ) { + return type ? progressWindowIcon[type] : defaulIcon; + } +} diff --git a/src/modules/progressWindow.ts b/src/modules/progressWindow.ts deleted file mode 100644 index feabd1a..0000000 --- a/src/modules/progressWindow.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { config } from "../../package.json"; - -const progressWindowIcon = { - success: "chrome://zotero/skin/tick.png", - fail: "chrome://zotero/skin/cross.png", - default: `chrome://${config.addonRef}/content/icons/favicon.png`, -}; - -export function showProgressWindow( - header: string, - context: string, - type: "success" | "fail" | "default" = "default", - options: { - closeTime?: number; - backend?: "Zotero" | "system"; - } = { - closeTime: 5000, - backend: "Zotero", - } -): _ZoteroProgressWindow | Notification { - // Currently Zotero 7 doesn't support progress window. - // Use system backend on Zotero 7. - if (options.backend === "system" || ztoolkit.Compat.isZotero7()) { - Zotero.Prefs.set("alerts.useSystemBackend", true, true); - const notification = new (ztoolkit.Compat.getGlobal( - "Notification" - ) as typeof Notification)(header, { - body: context, - icon: progressWindowIcon[type], - tag: config.addonName, - }); - if (options.closeTime) { - (ztoolkit.Compat.getGlobal("setTimeout") as typeof setTimeout)(() => { - notification.close(); - }, options.closeTime); - } - return notification; - } else { - // A simple wrapper of the Zotero ProgressWindow - const progressWindow = new Zotero.ProgressWindow({ - closeOnClick: true, - }) as _ZoteroProgressWindow; - progressWindow.changeHeadline(header); - // @ts-ignore - progressWindow.progress = new progressWindow.ItemProgress( - progressWindowIcon[type], - context - ); - progressWindow.show(); - if (options.closeTime) { - progressWindow.startCloseTimer(options.closeTime); - } - return progressWindow; - } -} - -export function changeProgressWindowLine( - progressWindow: _ZoteroProgressWindow | Notification, - options: { - newText?: string; - newIcon?: string; - newProgress?: number; - } -) { - if (!isProgressWindow(progressWindow)) { - return; - } - // @ts-ignore - const progress = progressWindow.progress as _ZoteroItemProgress; - if (!progress) { - return; - } - options.newText && progress.setText(options.newText); - options.newIcon && progress.setIcon(options.newIcon); - options.newProgress && progress.setProgress(options.newProgress); -} - -export function isProgressWindow( - progressWindow: _ZoteroProgressWindow | Notification -) { - return !(progressWindow as Notification).title; -}