diff --git a/lib/i18n.ts b/lib/i18n.ts index af0c4fb..e88874d 100644 --- a/lib/i18n.ts +++ b/lib/i18n.ts @@ -61,7 +61,7 @@ const memoGetMessage = memoize(i18n.getMessage, 10 * 1000, 10); * @param {string[]} [subst] Message substituations * @returns {string} Localized message */ -function _(id: string, ...subst: any[]) { +export function _(id: string, ...subst: any[]) { if (!subst.length) { return memoGetMessage(id); } @@ -76,7 +76,7 @@ function _(id: string, ...subst: any[]) { * @param {Element} elem DOM to localize * @returns {Element} Passed in element (fluent) */ -function localize(elem: HTMLElement) { +export function localize(elem: T): T { for (const el of elem.querySelectorAll("*[data-i18n]")) { const {i18n: i} = el.dataset; if (!i) { @@ -107,8 +107,5 @@ function localize(elem: HTMLElement) { for (const el of document.querySelectorAll("*[data-l18n]")) { console.error("wrong!", el); } - return elem; + return elem as T; } - - -export {localize, _}; diff --git a/windows/broadcaster.ts b/windows/broadcaster.ts index b6832c6..cc2752d 100644 --- a/windows/broadcaster.ts +++ b/windows/broadcaster.ts @@ -1,9 +1,8 @@ "use strict"; // License: MIT -import {Keys} from "./keys"; - -const $ = document.querySelector.bind(document); +import { Keys } from "./keys"; +import { $ } from "./winutil"; export class Broadcaster { private readonly els: HTMLElement[]; @@ -38,7 +37,7 @@ export class Broadcaster { } onkey(evt: KeyboardEvent) { - const {localName} = evt.target as HTMLElement; + const { localName } = evt.target as HTMLElement; if (localName === "input" || localName === "textarea") { return undefined; } diff --git a/windows/manager/buttons.ts b/windows/manager/buttons.ts index eccb6cd..869ec9b 100644 --- a/windows/manager/buttons.ts +++ b/windows/manager/buttons.ts @@ -2,8 +2,7 @@ // License: MIT import { EventEmitter } from "../../lib/events"; - -const $ = document.querySelector.bind(document); +import { $ } from "../winutil"; export class Buttons extends EventEmitter { private readonly parent: HTMLElement; diff --git a/windows/manager/itemfilters.ts b/windows/manager/itemfilters.ts index ecae749..c4b316a 100644 --- a/windows/manager/itemfilters.ts +++ b/windows/manager/itemfilters.ts @@ -19,12 +19,11 @@ import {sort, defaultCompare, naturalCaseCompare} from "../../lib/sorting"; import {DownloadItem, DownloadTable} from "./table"; import {formatSize} from "../../lib/formatters"; import {_} from "../../lib/i18n"; +import {$} from "../winutil"; import {StateTexts} from "./state"; const TIMEOUT_SEARCH = 750; -const $ = document.querySelector.bind(document); - class ItemFilter { public readonly id: string; @@ -119,8 +118,10 @@ export class MenuFilter extends ItemFilter { constructor(id: string) { super(id); this.items = new Map(); + const tmpl = $("#menufilter-template"). + content.cloneNode(true); this.menu = new ContextMenu( - $("#menufilter-template").content.cloneNode(true).firstElementChild); + (tmpl as HTMLElement).firstElementChild); this.menu.on("clicked", this.onclicked.bind(this)); this.menu.on("ctx-menufilter-invert", () => this.invert()); this.menu.on("ctx-menufilter-clear", () => this.clear()); diff --git a/windows/manager/removaldlg.ts b/windows/manager/removaldlg.ts index 69c158e..80a3eeb 100644 --- a/windows/manager/removaldlg.ts +++ b/windows/manager/removaldlg.ts @@ -5,8 +5,7 @@ import ModalDialog from "../../uikit/lib/modal"; import { _, localize } from "../../lib/i18n"; import { Prefs } from "../../lib/prefs"; import { Keys } from "../keys"; - -const $ = document.querySelector.bind(document); +import { $ } from "../winutil"; export default class RemovalModalDialog extends ModalDialog { private readonly text: string; @@ -23,10 +22,11 @@ export default class RemovalModalDialog extends ModalDialog { } get content() { - const content = $("#removal-template").content.cloneNode(true); + const content = $("#removal-template"). + content.cloneNode(true) as DocumentFragment; localize(content); this.check = content.querySelector(".removal-remember"); - content.querySelector(".removal-text").textContent = this.text; + $(".removal-text", content).textContent = this.text; return content; } diff --git a/windows/manager/table.ts b/windows/manager/table.ts index a4e21e1..51cc626 100644 --- a/windows/manager/table.ts +++ b/windows/manager/table.ts @@ -34,6 +34,7 @@ import { Tooltip } from "./tooltip"; import "../../lib/util"; import { CellTypes } from "../../uikit/lib/constants"; import { downloads } from "../../lib/browser"; +import { $ } from "../winutil"; const TREE_CONFIG_VERSION = 2; const RUNNING_TIMEOUT = 1000; @@ -53,8 +54,6 @@ const ICON_BASE_SIZE = 16; const TEXT_SIZE_UNKNOWM = _("size-unknown"); -const $ = document.querySelector.bind(document); - const prettyNumber = (function() { const rv = new Intl.NumberFormat(undefined, { style: "decimal", @@ -403,7 +402,7 @@ export class DownloadTable extends VirtualTable { this.sids = new Map(); this.icons = new Icons($("#icons")); - localize($("#table-context").content); + localize($("#table-context").content); const ctx = this.contextMenu = new ContextMenu("#table-context"); Keys.adoptContext(ctx); Keys.adoptButtons($("#toolbar")); diff --git a/windows/prefs.ts b/windows/prefs.ts index 027e586..abe2dbe 100644 --- a/windows/prefs.ts +++ b/windows/prefs.ts @@ -11,12 +11,12 @@ import { TYPE_LINK, TYPE_MEDIA } from "../lib/constants"; import { iconForPath, visible } from "../lib/windowutils"; import { VirtualTable } from "../uikit/lib/table"; import { Icons } from "./icons"; +import { $ } from "./winutil"; const ICON_BASE_SIZE = 16; -const $ = document.querySelector.bind(document); -class UIPref extends PrefWatcher { +class UIPref extends PrefWatcher { id: string; pref: string; @@ -101,20 +101,22 @@ class OptionPref extends UIPref { } class CreateFilterDialog extends ModalDialog { - label: any; + label: HTMLInputElement; - expr: any; + expr: HTMLInputElement; - link: any; + link: HTMLInputElement; - media: any; + media: HTMLInputElement; get content() { - const rv = localize($("#create-filter-template").content.cloneNode(true)); - this.label = rv.querySelector("#filter-create-label"); - this.expr = rv.querySelector("#filter-create-expr"); - this.link = rv.querySelector("#filter-create-type-link"); - this.media = rv.querySelector("#filter-create-type-media"); + const tmpl = $("#create-filter-template"). + content.cloneNode(true) as DocumentFragment; + const rv = localize(tmpl); + this.label = $("#filter-create-label", rv); + this.expr = $("#filter-create-expr", rv); + this.link = $("#filter-create-type-link", rv); + this.media = $("#filter-create-type-media", rv); return rv; } diff --git a/windows/select.ts b/windows/select.ts index cc75f45..8f0fda6 100644 --- a/windows/select.ts +++ b/windows/select.ts @@ -16,9 +16,9 @@ import { sort, naturalCaseCompare } from "../lib/sorting"; import { hookButton } from "../lib/manager/renamer"; import { CellTypes } from "../uikit/lib/constants"; import { runtime } from "../lib/browser"; +import { $ } from "./winutil"; const PORT = runtime.connect(null, { name: "select" }); -const $ = document.querySelector.bind(document); const TREE_CONFIG_VERSION = 1; @@ -52,7 +52,8 @@ function matched(item: any) { class PausedModalDialog extends ModalDialog { get content() { - const content = $("#paused-template").content.cloneNode(true); + const tmpl = $("#paused-template"); + const content = tmpl.content.cloneNode(true) as DocumentFragment; localize(content); return content; } @@ -154,7 +155,7 @@ class SelectionTable extends VirtualTable { super("#items", treeConfig, TREE_CONFIG_VERSION); this.checkClasser = new CheckClasser(NUM_FILTER_CLASSES); - this.icons = new Icons($("#icons")); + this.icons = new Icons($("#icons") as HTMLStyleElement); this.links = links; this.media = media; this.type = type; @@ -181,7 +182,7 @@ class SelectionTable extends VirtualTable { this.linksFilters = $("#linksFilters"); this.mediaFilters = $("#mediaFilters"); - localize($("#table-context").content); + localize(($("#table-context") as HTMLTemplateElement).content); this.contextMenu = new ContextMenu("#table-context"); Keys.adoptContext(this.contextMenu); @@ -553,9 +554,9 @@ async function download(paused = false) { items, paused, mask, - maskOnce: $("#maskOnceCheck").checked, + maskOnce: $("#maskOnceCheck").checked, fast: FastFilter.value, - fastOnce: $("#fastOnceCheck").checked, + fastOnce: $("#fastOnceCheck").checked, }); } catch (ex) { @@ -670,7 +671,7 @@ addEventListener("DOMContentLoaded", function dom() { $("#fastDisableOthers").addEventListener("change", () => { PORT.postMessage({ msg: "onlyfast", - fast: $("#fastDisableOthers").checked + fast: $("#fastDisableOthers").checked }); }); diff --git a/windows/single.ts b/windows/single.ts index f05826f..644da96 100644 --- a/windows/single.ts +++ b/windows/single.ts @@ -12,9 +12,9 @@ import { Dropdown } from "./dropdown"; import { Keys } from "./keys"; import { hookButton } from "../lib/manager/renamer"; import { runtime } from "../lib/browser"; +import { $ } from "./winutil"; const PORT = runtime.connect(null, { name: "single" }); -const $ = document.querySelector.bind(document); let ITEM: any; let Mask: Dropdown; @@ -28,11 +28,11 @@ class BatchModalDialog extends ModalDialog { } get content() { - const content = $("#batch-template").content.cloneNode(true); + const tmpl = $("#batch-template") as HTMLTemplateElement; + const content = tmpl.content.cloneNode(true) as DocumentFragment; localize(content); - const $$ = content.querySelector.bind(content); - $$(".batch-items").textContent = this.gen.length.toLocaleString(); - $$(".batch-preview").textContent = this.gen.preview; + $(".batch-items", content).textContent = this.gen.length.toLocaleString(); + $(".batch-preview", content).textContent = this.gen.preview; return content; } @@ -73,11 +73,11 @@ function setItem(item: any) { usableReferrer = "", mask = "" } = item; - $("#URL").value = usable; - $("#filename").value = fileName; - $("#title").value = title; - $("#description").value = description; - $("#referrer").value = usableReferrer; + $("#URL").value = usable; + $("#filename").value = fileName; + $("#title").value = title; + $("#description").value = description; + $("#referrer").value = usableReferrer; if (mask) { Mask.value = mask; } @@ -90,7 +90,7 @@ function displayError(err: string) { } async function downloadInternal(paused: boolean) { - let usable = $("#URL").value.trim(); + let usable = $("#URL").value.trim(); let url; try { url = new URL(usable).toString(); @@ -98,7 +98,7 @@ async function downloadInternal(paused: boolean) { catch (ex) { try { url = new URL(`https://${usable}`).toString(); - $("#URL").value = usable = `https://${usable}`; + $("#URL").value = usable = `https://${usable}`; } catch (ex) { return displayError("error.invalidURL"); @@ -107,7 +107,7 @@ async function downloadInternal(paused: boolean) { const gen = new BatchGenerator(usable); - const usableReferrer = $("#referrer").value.trim(); + const usableReferrer = $("#referrer").value.trim(); let referrer; try { referrer = usableReferrer ? new URL(usableReferrer).toString() : ""; @@ -116,9 +116,9 @@ async function downloadInternal(paused: boolean) { return displayError("error.invalidReferrer"); } - const fileName = $("#filename").value.trim(); - const title = $("#title").value.trim(); - const description = $("#description").value.trim(); + const fileName = $("#filename").value.trim(); + const title = $("#title").value.trim(); + const description = $("#description").value.trim(); const mask = Mask.value.trim(); if (!mask) { return displayError("error.invalidMask"); @@ -183,7 +183,7 @@ async function downloadInternal(paused: boolean) { paused, items, mask, - maskOnce: $("#maskOnceCheck").checked, + maskOnce: $("#maskOnceCheck").checked, }); return null; } diff --git a/windows/winutil.ts b/windows/winutil.ts new file mode 100644 index 0000000..797605b --- /dev/null +++ b/windows/winutil.ts @@ -0,0 +1,10 @@ +"use strict"; +// License: MIT + +export function $( + q: string, el?: HTMLElement | DocumentFragment): T { + if (!el) { + el = document; + } + return el.querySelector(q) as T; +}