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
* @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<T extends HTMLElement | DocumentFragment>(elem: T): T {
for (const el of elem.querySelectorAll<HTMLElement>("*[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, _};

View File

@ -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;
}

View File

@ -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;

View File

@ -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 = $<HTMLTemplateElement>("#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());

View File

@ -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 = $<HTMLTemplateElement>("#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;
}

View File

@ -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<number, DownloadItem>();
this.icons = new Icons($("#icons"));
localize($("#table-context").content);
localize($<HTMLTemplateElement>("#table-context").content);
const ctx = this.contextMenu = new ContextMenu("#table-context");
Keys.adoptContext(ctx);
Keys.adoptButtons($("#toolbar"));

View File

@ -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<T> extends PrefWatcher {
class UIPref<T extends HTMLElement> extends PrefWatcher {
id: string;
pref: string;
@ -101,20 +101,22 @@ class OptionPref extends UIPref<HTMLElement> {
}
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 = $<HTMLTemplateElement>("#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;
}

View File

@ -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 = $<HTMLTemplateElement>("#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: $<HTMLInputElement>("#maskOnceCheck").checked,
fast: FastFilter.value,
fastOnce: $("#fastOnceCheck").checked,
fastOnce: $<HTMLInputElement>("#fastOnceCheck").checked,
});
}
catch (ex) {
@ -670,7 +671,7 @@ addEventListener("DOMContentLoaded", function dom() {
$("#fastDisableOthers").addEventListener("change", () => {
PORT.postMessage({
msg: "onlyfast",
fast: $("#fastDisableOthers").checked
fast: $<HTMLInputElement>("#fastDisableOthers").checked
});
});

View File

@ -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;
$<HTMLInputElement>("#URL").value = usable;
$<HTMLInputElement>("#filename").value = fileName;
$<HTMLInputElement>("#title").value = title;
$<HTMLInputElement>("#description").value = description;
$<HTMLInputElement>("#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 = $<HTMLInputElement>("#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}`;
$<HTMLInputElement>("#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 = $<HTMLInputElement>("#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 = $<HTMLInputElement>("#filename").value.trim();
const title = $<HTMLInputElement>("#title").value.trim();
const description = $<HTMLInputElement>("#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: $<HTMLInputElement>("#maskOnceCheck").checked,
});
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;
}