add: useful utils
This commit is contained in:
		
							parent
							
								
									98a1c7770b
								
							
						
					
					
						commit
						1c43ef671a
					
				@ -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");
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								package.json
									
									
									
									
									
								
							@ -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
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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() {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { config } from "../../package.json";
 | 
			
		||||
import { getString } from "./locale";
 | 
			
		||||
import { getString } from "../utils/locale";
 | 
			
		||||
 | 
			
		||||
function example(
 | 
			
		||||
  target: any,
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
									
								
							
							
						
						
									
										29
									
								
								src/utils/prefs.ts
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										49
									
								
								src/utils/wait.ts
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										66
									
								
								src/utils/window.ts
									
									
									
									
									
										Normal 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);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user