Proper types for localize and $

This commit is contained in:
Nils Maier 2019-08-25 22:15:56 +02:00
parent 70c7e0b0f3
commit a89acad0c9
10 changed files with 65 additions and 57 deletions

View File

@ -61,7 +61,7 @@ const memoGetMessage = memoize(i18n.getMessage, 10 * 1000, 10);
* @param {string[]} [subst] Message substituations * @param {string[]} [subst] Message substituations
* @returns {string} Localized message * @returns {string} Localized message
*/ */
function _(id: string, ...subst: any[]) { export function _(id: string, ...subst: any[]) {
if (!subst.length) { if (!subst.length) {
return memoGetMessage(id); return memoGetMessage(id);
} }
@ -76,7 +76,7 @@ function _(id: string, ...subst: any[]) {
* @param {Element} elem DOM to localize * @param {Element} elem DOM to localize
* @returns {Element} Passed in element (fluent) * @returns {Element} Passed in element (fluent)
*/ */
function localize(elem: HTMLElement) { export function localize<T extends HTMLElement | DocumentFragment>(elem: T): T {
for (const el of elem.querySelectorAll<HTMLElement>("*[data-i18n]")) { for (const el of elem.querySelectorAll<HTMLElement>("*[data-i18n]")) {
const {i18n: i} = el.dataset; const {i18n: i} = el.dataset;
if (!i) { if (!i) {
@ -107,8 +107,5 @@ function localize(elem: HTMLElement) {
for (const el of document.querySelectorAll("*[data-l18n]")) { for (const el of document.querySelectorAll("*[data-l18n]")) {
console.error("wrong!", el); console.error("wrong!", el);
} }
return elem; return elem as T;
} }
export {localize, _};

View File

@ -2,8 +2,7 @@
// License: MIT // License: MIT
import { Keys } from "./keys"; import { Keys } from "./keys";
import { $ } from "./winutil";
const $ = document.querySelector.bind(document);
export class Broadcaster { export class Broadcaster {
private readonly els: HTMLElement[]; private readonly els: HTMLElement[];

View File

@ -2,8 +2,7 @@
// License: MIT // License: MIT
import { EventEmitter } from "../../lib/events"; import { EventEmitter } from "../../lib/events";
import { $ } from "../winutil";
const $ = document.querySelector.bind(document);
export class Buttons extends EventEmitter { export class Buttons extends EventEmitter {
private readonly parent: HTMLElement; private readonly parent: HTMLElement;

View File

@ -19,12 +19,11 @@ import {sort, defaultCompare, naturalCaseCompare} from "../../lib/sorting";
import {DownloadItem, DownloadTable} from "./table"; import {DownloadItem, DownloadTable} from "./table";
import {formatSize} from "../../lib/formatters"; import {formatSize} from "../../lib/formatters";
import {_} from "../../lib/i18n"; import {_} from "../../lib/i18n";
import {$} from "../winutil";
import {StateTexts} from "./state"; import {StateTexts} from "./state";
const TIMEOUT_SEARCH = 750; const TIMEOUT_SEARCH = 750;
const $ = document.querySelector.bind(document);
class ItemFilter { class ItemFilter {
public readonly id: string; public readonly id: string;
@ -119,8 +118,10 @@ export class MenuFilter extends ItemFilter {
constructor(id: string) { constructor(id: string) {
super(id); super(id);
this.items = new Map(); this.items = new Map();
const tmpl = $<HTMLTemplateElement>("#menufilter-template").
content.cloneNode(true);
this.menu = new ContextMenu( 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("clicked", this.onclicked.bind(this));
this.menu.on("ctx-menufilter-invert", () => this.invert()); this.menu.on("ctx-menufilter-invert", () => this.invert());
this.menu.on("ctx-menufilter-clear", () => this.clear()); this.menu.on("ctx-menufilter-clear", () => this.clear());

View File

@ -5,8 +5,7 @@ import ModalDialog from "../../uikit/lib/modal";
import { _, localize } from "../../lib/i18n"; import { _, localize } from "../../lib/i18n";
import { Prefs } from "../../lib/prefs"; import { Prefs } from "../../lib/prefs";
import { Keys } from "../keys"; import { Keys } from "../keys";
import { $ } from "../winutil";
const $ = document.querySelector.bind(document);
export default class RemovalModalDialog extends ModalDialog { export default class RemovalModalDialog extends ModalDialog {
private readonly text: string; private readonly text: string;
@ -23,10 +22,11 @@ export default class RemovalModalDialog extends ModalDialog {
} }
get content() { get content() {
const content = $("#removal-template").content.cloneNode(true); const content = $<HTMLTemplateElement>("#removal-template").
content.cloneNode(true) as DocumentFragment;
localize(content); localize(content);
this.check = content.querySelector(".removal-remember"); this.check = content.querySelector(".removal-remember");
content.querySelector(".removal-text").textContent = this.text; $(".removal-text", content).textContent = this.text;
return content; return content;
} }

View File

@ -34,6 +34,7 @@ import { Tooltip } from "./tooltip";
import "../../lib/util"; import "../../lib/util";
import { CellTypes } from "../../uikit/lib/constants"; import { CellTypes } from "../../uikit/lib/constants";
import { downloads } from "../../lib/browser"; import { downloads } from "../../lib/browser";
import { $ } from "../winutil";
const TREE_CONFIG_VERSION = 2; const TREE_CONFIG_VERSION = 2;
const RUNNING_TIMEOUT = 1000; const RUNNING_TIMEOUT = 1000;
@ -53,8 +54,6 @@ const ICON_BASE_SIZE = 16;
const TEXT_SIZE_UNKNOWM = _("size-unknown"); const TEXT_SIZE_UNKNOWM = _("size-unknown");
const $ = document.querySelector.bind(document);
const prettyNumber = (function() { const prettyNumber = (function() {
const rv = new Intl.NumberFormat(undefined, { const rv = new Intl.NumberFormat(undefined, {
style: "decimal", style: "decimal",
@ -403,7 +402,7 @@ export class DownloadTable extends VirtualTable {
this.sids = new Map<number, DownloadItem>(); this.sids = new Map<number, DownloadItem>();
this.icons = new Icons($("#icons")); this.icons = new Icons($("#icons"));
localize($("#table-context").content); localize($<HTMLTemplateElement>("#table-context").content);
const ctx = this.contextMenu = new ContextMenu("#table-context"); const ctx = this.contextMenu = new ContextMenu("#table-context");
Keys.adoptContext(ctx); Keys.adoptContext(ctx);
Keys.adoptButtons($("#toolbar")); Keys.adoptButtons($("#toolbar"));

View File

@ -11,12 +11,12 @@ import { TYPE_LINK, TYPE_MEDIA } from "../lib/constants";
import { iconForPath, visible } from "../lib/windowutils"; import { iconForPath, visible } from "../lib/windowutils";
import { VirtualTable } from "../uikit/lib/table"; import { VirtualTable } from "../uikit/lib/table";
import { Icons } from "./icons"; import { Icons } from "./icons";
import { $ } from "./winutil";
const ICON_BASE_SIZE = 16; const ICON_BASE_SIZE = 16;
const $ = document.querySelector.bind(document);
class UIPref<T> extends PrefWatcher { class UIPref<T extends HTMLElement> extends PrefWatcher {
id: string; id: string;
pref: string; pref: string;
@ -101,20 +101,22 @@ class OptionPref extends UIPref<HTMLElement> {
} }
class CreateFilterDialog extends ModalDialog { class CreateFilterDialog extends ModalDialog {
label: any; label: HTMLInputElement;
expr: any; expr: HTMLInputElement;
link: any; link: HTMLInputElement;
media: any; media: HTMLInputElement;
get content() { get content() {
const rv = localize($("#create-filter-template").content.cloneNode(true)); const tmpl = $<HTMLTemplateElement>("#create-filter-template").
this.label = rv.querySelector("#filter-create-label"); content.cloneNode(true) as DocumentFragment;
this.expr = rv.querySelector("#filter-create-expr"); const rv = localize(tmpl);
this.link = rv.querySelector("#filter-create-type-link"); this.label = $("#filter-create-label", rv);
this.media = rv.querySelector("#filter-create-type-media"); this.expr = $("#filter-create-expr", rv);
this.link = $("#filter-create-type-link", rv);
this.media = $("#filter-create-type-media", rv);
return rv; return rv;
} }

View File

@ -16,9 +16,9 @@ import { sort, naturalCaseCompare } from "../lib/sorting";
import { hookButton } from "../lib/manager/renamer"; import { hookButton } from "../lib/manager/renamer";
import { CellTypes } from "../uikit/lib/constants"; import { CellTypes } from "../uikit/lib/constants";
import { runtime } from "../lib/browser"; import { runtime } from "../lib/browser";
import { $ } from "./winutil";
const PORT = runtime.connect(null, { name: "select" }); const PORT = runtime.connect(null, { name: "select" });
const $ = document.querySelector.bind(document);
const TREE_CONFIG_VERSION = 1; const TREE_CONFIG_VERSION = 1;
@ -52,7 +52,8 @@ function matched(item: any) {
class PausedModalDialog extends ModalDialog { class PausedModalDialog extends ModalDialog {
get content() { get content() {
const content = $("#paused-template").content.cloneNode(true); const tmpl = $<HTMLTemplateElement>("#paused-template");
const content = tmpl.content.cloneNode(true) as DocumentFragment;
localize(content); localize(content);
return content; return content;
} }
@ -154,7 +155,7 @@ class SelectionTable extends VirtualTable {
super("#items", treeConfig, TREE_CONFIG_VERSION); super("#items", treeConfig, TREE_CONFIG_VERSION);
this.checkClasser = new CheckClasser(NUM_FILTER_CLASSES); this.checkClasser = new CheckClasser(NUM_FILTER_CLASSES);
this.icons = new Icons($("#icons")); this.icons = new Icons($("#icons") as HTMLStyleElement);
this.links = links; this.links = links;
this.media = media; this.media = media;
this.type = type; this.type = type;
@ -181,7 +182,7 @@ class SelectionTable extends VirtualTable {
this.linksFilters = $("#linksFilters"); this.linksFilters = $("#linksFilters");
this.mediaFilters = $("#mediaFilters"); this.mediaFilters = $("#mediaFilters");
localize($("#table-context").content); localize(($("#table-context") as HTMLTemplateElement).content);
this.contextMenu = new ContextMenu("#table-context"); this.contextMenu = new ContextMenu("#table-context");
Keys.adoptContext(this.contextMenu); Keys.adoptContext(this.contextMenu);
@ -553,9 +554,9 @@ async function download(paused = false) {
items, items,
paused, paused,
mask, mask,
maskOnce: $("#maskOnceCheck").checked, maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
fast: FastFilter.value, fast: FastFilter.value,
fastOnce: $("#fastOnceCheck").checked, fastOnce: $<HTMLInputElement>("#fastOnceCheck").checked,
}); });
} }
catch (ex) { catch (ex) {
@ -670,7 +671,7 @@ addEventListener("DOMContentLoaded", function dom() {
$("#fastDisableOthers").addEventListener("change", () => { $("#fastDisableOthers").addEventListener("change", () => {
PORT.postMessage({ PORT.postMessage({
msg: "onlyfast", msg: "onlyfast",
fast: $("#fastDisableOthers").checked fast: $<HTMLInputElement>("#fastDisableOthers").checked
}); });
}); });

View File

@ -12,9 +12,9 @@ import { Dropdown } from "./dropdown";
import { Keys } from "./keys"; import { Keys } from "./keys";
import { hookButton } from "../lib/manager/renamer"; import { hookButton } from "../lib/manager/renamer";
import { runtime } from "../lib/browser"; import { runtime } from "../lib/browser";
import { $ } from "./winutil";
const PORT = runtime.connect(null, { name: "single" }); const PORT = runtime.connect(null, { name: "single" });
const $ = document.querySelector.bind(document);
let ITEM: any; let ITEM: any;
let Mask: Dropdown; let Mask: Dropdown;
@ -28,11 +28,11 @@ class BatchModalDialog extends ModalDialog {
} }
get content() { 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); localize(content);
const $$ = content.querySelector.bind(content); $(".batch-items", content).textContent = this.gen.length.toLocaleString();
$$(".batch-items").textContent = this.gen.length.toLocaleString(); $(".batch-preview", content).textContent = this.gen.preview;
$$(".batch-preview").textContent = this.gen.preview;
return content; return content;
} }
@ -73,11 +73,11 @@ function setItem(item: any) {
usableReferrer = "", usableReferrer = "",
mask = "" mask = ""
} = item; } = item;
$("#URL").value = usable; $<HTMLInputElement>("#URL").value = usable;
$("#filename").value = fileName; $<HTMLInputElement>("#filename").value = fileName;
$("#title").value = title; $<HTMLInputElement>("#title").value = title;
$("#description").value = description; $<HTMLInputElement>("#description").value = description;
$("#referrer").value = usableReferrer; $<HTMLInputElement>("#referrer").value = usableReferrer;
if (mask) { if (mask) {
Mask.value = mask; Mask.value = mask;
} }
@ -90,7 +90,7 @@ function displayError(err: string) {
} }
async function downloadInternal(paused: boolean) { async function downloadInternal(paused: boolean) {
let usable = $("#URL").value.trim(); let usable = $<HTMLInputElement>("#URL").value.trim();
let url; let url;
try { try {
url = new URL(usable).toString(); url = new URL(usable).toString();
@ -98,7 +98,7 @@ async function downloadInternal(paused: boolean) {
catch (ex) { catch (ex) {
try { try {
url = new URL(`https://${usable}`).toString(); url = new URL(`https://${usable}`).toString();
$("#URL").value = usable = `https://${usable}`; $<HTMLInputElement>("#URL").value = usable = `https://${usable}`;
} }
catch (ex) { catch (ex) {
return displayError("error.invalidURL"); return displayError("error.invalidURL");
@ -107,7 +107,7 @@ async function downloadInternal(paused: boolean) {
const gen = new BatchGenerator(usable); const gen = new BatchGenerator(usable);
const usableReferrer = $("#referrer").value.trim(); const usableReferrer = $<HTMLInputElement>("#referrer").value.trim();
let referrer; let referrer;
try { try {
referrer = usableReferrer ? new URL(usableReferrer).toString() : ""; referrer = usableReferrer ? new URL(usableReferrer).toString() : "";
@ -116,9 +116,9 @@ async function downloadInternal(paused: boolean) {
return displayError("error.invalidReferrer"); return displayError("error.invalidReferrer");
} }
const fileName = $("#filename").value.trim(); const fileName = $<HTMLInputElement>("#filename").value.trim();
const title = $("#title").value.trim(); const title = $<HTMLInputElement>("#title").value.trim();
const description = $("#description").value.trim(); const description = $<HTMLInputElement>("#description").value.trim();
const mask = Mask.value.trim(); const mask = Mask.value.trim();
if (!mask) { if (!mask) {
return displayError("error.invalidMask"); return displayError("error.invalidMask");
@ -183,7 +183,7 @@ async function downloadInternal(paused: boolean) {
paused, paused,
items, items,
mask, mask,
maskOnce: $("#maskOnceCheck").checked, maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
}); });
return null; return null;
} }

10
windows/winutil.ts Normal file
View File

@ -0,0 +1,10 @@
"use strict";
// License: MIT
export function $<T extends HTMLElement>(
q: string, el?: HTMLElement | DocumentFragment): T {
if (!el) {
el = document;
}
return el.querySelector<T>(q) as T;
}