add: useful utils

This commit is contained in:
windingwind 2023-05-07 11:27:15 +08:00
parent 98a1c7770b
commit 1c43ef671a
9 changed files with 170 additions and 16 deletions

View File

@ -1,2 +1,3 @@
pref("extensions.zotero.__addonRef__.enable", true);
pref("extensions.zotero.__addonRef__.input", "This is input");
/* eslint-disable no-undef */
pref("__prefsPrefix__.enable", true);
pref("__prefsPrefix__.input", "This is input");

View File

@ -7,6 +7,7 @@
"addonID": "addontemplate@euclpts.com",
"addonRef": "addontemplate",
"addonInstance": "AddonTemplate",
"prefsPrefix": "extensions.zotero.addontemplate",
"releasepage": "https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi",
"updaterdf": "https://raw.githubusercontent.com/windingwind/zotero-addon-template/bootstrap/update.json"
},
@ -39,26 +40,26 @@
},
"homepage": "https://github.com/windingwind/zotero-addon-template#readme",
"dependencies": {
"zotero-plugin-toolkit": "^2.0.1"
"zotero-plugin-toolkit": "^2.1.3"
},
"devDependencies": {
"@types/node": "^18.11.17",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "^5.59.1",
"compressing": "^1.6.3",
"@types/node": "^18.16.5",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"compressing": "^1.9.0",
"concurrently": "^8.0.1",
"cross-env": "^7.0.3",
"esbuild": "^0.17.4",
"eslint": "^8.39.0",
"esbuild": "^0.17.18",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"minimist": "^1.2.7",
"minimist": "^1.2.8",
"prettier": "2.8.8",
"release-it": "^15.6.0",
"release-it": "^15.10.3",
"replace-in-file": "^6.3.5",
"typescript": "^5.0.4",
"zotero-types": "^1.0.12"
"zotero-types": "^1.0.14"
},
"prettier": {
"tabWidth": 2
}
}
}

View File

@ -6,7 +6,7 @@ import {
UIExampleFactory,
} from "./modules/examples";
import { config } from "../package.json";
import { getString, initLocale } from "./modules/locale";
import { getString, initLocale } from "./utils/locale";
import { registerPrefsScripts } from "./modules/preferenceScript";
async function onStartup() {

View File

@ -1,5 +1,5 @@
import { config } from "../../package.json";
import { getString } from "./locale";
import { getString } from "../utils/locale";
function example(
target: any,

View File

@ -1,5 +1,5 @@
import { config } from "../../package.json";
import { getString } from "./locale";
import { getString } from "../utils/locale";
export function registerPrefsScripts(_window: Window) {
// This function is called when the prefs window is opened

View File

@ -1,5 +1,8 @@
import { config } from "../../package.json";
/**
* Initialize locale data
*/
export function initLocale() {
addon.data.locale = {
stringBundle: Components.classes["@mozilla.org/intl/stringbundle;1"]
@ -8,6 +11,11 @@ export function initLocale() {
};
}
/**
* Get locale string
* @param localString
* @param noReload
*/
export function getString(localString: string, noReload = false): string {
try {
return addon.data.locale?.stringBundle.GetStringFromName(localString);

29
src/utils/prefs.ts Normal file
View File

@ -0,0 +1,29 @@
import { config } from "../../package.json";
/**
* Get preference value.
* Wrapper of `Zotero.Prefs.get`.
* @param key
*/
export function getPref(key: string) {
return Zotero.Prefs.get(`${config.prefsPrefix}.${key}`, true);
}
/**
* Set preference value.
* Wrapper of `Zotero.Prefs.set`.
* @param key
* @param value
*/
export function setPref(key: string, value: string | number | boolean) {
return Zotero.Prefs.set(`${config.prefsPrefix}.${key}`, value, true);
}
/**
* Clear preference value.
* Wrapper of `Zotero.Prefs.clear`.
* @param key
*/
export function clearPref(key: string) {
return Zotero.Prefs.clear(`${config.prefsPrefix}.${key}`, true);
}

49
src/utils/wait.ts Normal file
View File

@ -0,0 +1,49 @@
/**
* Wait until the condition is `true` or timeout.
* The callback is triggered if condition returns `true`.
* @param condition
* @param callback
* @param interval
* @param timeout
*/
export function waitUntil(
condition: () => boolean,
callback: () => void,
interval = 100,
timeout = 10000
) {
const start = Date.now();
const intervalId = ztoolkit.getGlobal("setInterval")(() => {
if (condition()) {
ztoolkit.getGlobal("clearInterval")(intervalId);
callback();
} else if (Date.now() - start > timeout) {
ztoolkit.getGlobal("clearInterval")(intervalId);
}
}, interval);
}
/**
* Wait async until the condition is `true` or timeout.
* @param condition
* @param interval
* @param timeout
*/
export function waitUtilAsync(
condition: () => boolean,
interval = 100,
timeout = 10000
) {
return new Promise<void>((resolve, reject) => {
const start = Date.now();
const intervalId = ztoolkit.getGlobal("setInterval")(() => {
if (condition()) {
ztoolkit.getGlobal("clearInterval")(intervalId);
resolve();
} else if (Date.now() - start > timeout) {
ztoolkit.getGlobal("clearInterval")(intervalId);
reject();
}
}, interval);
});
}

66
src/utils/window.ts Normal file
View File

@ -0,0 +1,66 @@
import { getString } from "./locale";
export { isWindowAlive, localeWindow };
/**
* Check if the window is alive.
* Useful to prevent opening duplicate windows.
* @param win
*/
function isWindowAlive(win?: Window) {
return win && !Components.utils.isDeadWrapper(win) && !win.closed;
}
/**
* Locale the elements in window with the locale-target attribute.
* Useful when the window is created dynamically.
* @example
* In HTML:
* ```html
* <div locale-target="innerHTML,title" title="elem.title">elem.text</div>
* ```
* In `addon/chrome/locale/en-US/addon.properties`:
* ```properties
* elem.text=Hello World
* elem.title=Locale example
* ```
* In `addon/chrome/locale/zh-CN/addon.properties`:
* ```properties
* elem.text=
* elem.title=
* ```
* After locale:
*
* if locale is "en-US"
* ```html
* <div locale-target="innerHTML,title" title="Locale example">Hello World</div>
* ```
* else if locale is "zh-CN"
* ```html
* <div locale-target="innerHTML,title" title="多语言样例"></div>
* ```
* @param win
*/
function localeWindow(win: Window) {
Array.from(win.document.querySelectorAll("*[locale-target]")).forEach(
(elem) => {
const errorInfo = "Locale Error";
const locales = elem.getAttribute("locale-target")?.split(",");
locales?.forEach((key) => {
const isProp = key in elem;
try {
const localeString = getString(
(isProp ? (elem as any)[key] : elem.getAttribute(key)).trim() || ""
);
isProp
? ((elem as any)[key] = localeString)
: elem.setAttribute(key, localeString);
} catch (error) {
isProp
? ((elem as any)[key] = errorInfo)
: elem.setAttribute(key, errorInfo);
}
});
}
);
}