Fix some typescript issues
This commit is contained in:
parent
6c197d8353
commit
1513f0b022
@ -51,7 +51,7 @@ export const DB = new class DB {
|
|||||||
const store = transaction.objectStore(STORE);
|
const store = transaction.objectStore(STORE);
|
||||||
const index = store.index("by_position");
|
const index = store.index("by_position");
|
||||||
index.openCursor().onsuccess = event => {
|
index.openCursor().onsuccess = event => {
|
||||||
const cursor = (<IDBRequest<IDBCursorWithValue>> event.target).result;
|
const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;
|
||||||
if (!cursor) {
|
if (!cursor) {
|
||||||
resolve(items);
|
resolve(items);
|
||||||
return;
|
return;
|
||||||
|
@ -78,7 +78,7 @@ const SIZE_SCALE = 875;
|
|||||||
const SIZE_KILO = 1024;
|
const SIZE_KILO = 1024;
|
||||||
|
|
||||||
export const formatSize = memoize(function formatSize(
|
export const formatSize = memoize(function formatSize(
|
||||||
size: number, fractions: boolean = true) {
|
size: number, fractions = true) {
|
||||||
const neg = size < 0;
|
const neg = size < 0;
|
||||||
size = Math.abs(size);
|
size = Math.abs(size);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
85
lib/i18n.ts
85
lib/i18n.ts
@ -3,6 +3,50 @@
|
|||||||
|
|
||||||
import {memoize} from "./memoize";
|
import {memoize} from "./memoize";
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const {i18n} = require("webextension-polyfill");
|
||||||
|
|
||||||
|
return i18n;
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
// We might be running under node for tests
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const messages = require("../_locales/en/messages.json");
|
||||||
|
|
||||||
|
const map = new Map();
|
||||||
|
for (const [k, v] of Object.entries<any>(messages)) {
|
||||||
|
const {placeholders = {}} = v;
|
||||||
|
let {message = ""} = v;
|
||||||
|
for (const [pname, pval] of Object.entries<any>(placeholders)) {
|
||||||
|
message = message.replace(`$${pname.toUpperCase()}$`, `${pval.content}$`);
|
||||||
|
}
|
||||||
|
map.set(k, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getMessage(id: string, subst: string[]) {
|
||||||
|
const m = map.get(id);
|
||||||
|
if (typeof subst === undefined) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(subst)) {
|
||||||
|
subst = [subst];
|
||||||
|
}
|
||||||
|
return m.replace(/\$\d+\$/g, (r: string) => {
|
||||||
|
const idx = parseInt(r.substr(1, r.length - 2), 10) - 1;
|
||||||
|
return subst[idx] || "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const i18n = load();
|
||||||
|
const memoGetMessage = memoize(i18n.getMessage, 10 * 1000, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Localize a message
|
* Localize a message
|
||||||
* @param {string} id Identifier of the string to localize
|
* @param {string} id Identifier of the string to localize
|
||||||
@ -58,46 +102,5 @@ function localize(elem: HTMLElement) {
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
function load() {
|
|
||||||
try {
|
|
||||||
const {i18n} = require("webextension-polyfill");
|
|
||||||
|
|
||||||
return i18n;
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
// We might be running under node for tests
|
|
||||||
|
|
||||||
const messages = require("../_locales/en/messages.json");
|
|
||||||
|
|
||||||
const map = new Map();
|
|
||||||
for (const [k, v] of Object.entries<any>(messages)) {
|
|
||||||
const {placeholders = {}} = v;
|
|
||||||
let {message = ""} = v;
|
|
||||||
for (const [pname, pval] of Object.entries<any>(placeholders)) {
|
|
||||||
message = message.replace(`$${pname.toUpperCase()}$`, `${pval.content}$`);
|
|
||||||
}
|
|
||||||
map.set(k, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
getMessage(id: string, subst: string[]) {
|
|
||||||
const m = map.get(id);
|
|
||||||
if (typeof subst === undefined) {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
if (!Array.isArray(subst)) {
|
|
||||||
subst = [subst];
|
|
||||||
}
|
|
||||||
return m.replace(/\$\d+\$/g, (r: string) => {
|
|
||||||
const idx = parseInt(r.substr(1, r.length - 2), 10) - 1;
|
|
||||||
return subst[idx] || "";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const i18n = load();
|
|
||||||
const memoGetMessage = memoize(i18n.getMessage, 10 * 1000, 0);
|
|
||||||
|
|
||||||
export {localize, _};
|
export {localize, _};
|
||||||
|
@ -95,14 +95,15 @@ export class BaseDownload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assign(options: any) {
|
assign(options: any) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
for (const prop of SAVEDPROPS) {
|
for (const prop of SAVEDPROPS) {
|
||||||
if (prop in options) {
|
if (prop in options) {
|
||||||
self[prop] = options[prop];
|
self[prop] = options[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.uURL = <URLd> new URL(this.url);
|
this.uURL = new URL(this.url) as URLd;
|
||||||
this.uReferrer = <URLd> (this.referrer && new URL(this.referrer));
|
this.uReferrer = (this.referrer && new URL(this.referrer)) as URLd;
|
||||||
this.startDate = new Date(options.startDate || Date.now());
|
this.startDate = new Date(options.startDate || Date.now());
|
||||||
if (options.paused) {
|
if (options.paused) {
|
||||||
this.state = PAUSED;
|
this.state = PAUSED;
|
||||||
@ -133,6 +134,7 @@ export class BaseDownload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
const rv: any = {};
|
const rv: any = {};
|
||||||
for (const prop of SAVEDPROPS) {
|
for (const prop of SAVEDPROPS) {
|
||||||
|
@ -74,7 +74,7 @@ export const Limits = new class Limits extends EventEmitter {
|
|||||||
this.concurrent = await Prefs.get("concurrent", this.concurrent);
|
this.concurrent = await Prefs.get("concurrent", this.concurrent);
|
||||||
const rawlimits = await Prefs.get("limits");
|
const rawlimits = await Prefs.get("limits");
|
||||||
this.limits = new Map(rawlimits.map((e: any) => [e.domain, new Limit(e)]));
|
this.limits = new Map(rawlimits.map((e: any) => [e.domain, new Limit(e)]));
|
||||||
this.load = <() => Promise<void>> <unknown> (() => {});
|
this.load = (() => {}) as unknown as () => Promise<void>;
|
||||||
this.emit("changed");
|
this.emit("changed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,10 @@ import { API } from "../api";
|
|||||||
import { BaseDownload } from "./basedownload";
|
import { BaseDownload } from "./basedownload";
|
||||||
|
|
||||||
type SID = {sid: number};
|
type SID = {sid: number};
|
||||||
type SIDS = {sids: number[], forced?: boolean};
|
type SIDS = {
|
||||||
|
sids: number[];
|
||||||
|
forced?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export class ManagerPort {
|
export class ManagerPort {
|
||||||
private manager: any;
|
private manager: any;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
"use strict";
|
"use strict";
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
@ -169,6 +170,7 @@ export default class Renamer {
|
|||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
const {mask} = this.d;
|
const {mask} = this.d;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
// XXX flat
|
// XXX flat
|
||||||
return sanitizePath(mask.replace(REPLACE_EXPR, function(type: string) {
|
return sanitizePath(mask.replace(REPLACE_EXPR, function(type: string) {
|
||||||
|
@ -31,14 +31,14 @@ type MemoizeFun<T> = (...args: any[]) => T;
|
|||||||
*
|
*
|
||||||
* @param {Function} func The function to be memoized
|
* @param {Function} func The function to be memoized
|
||||||
* @param {Number} [limit] Optional. Cache size (default: 3000)
|
* @param {Number} [limit] Optional. Cache size (default: 3000)
|
||||||
* @param {Number} [num_args] Options. Number of arguments the function expects
|
* @param {Number} [numArgs] Options. Number of arguments the function expects
|
||||||
* (default: func.length)
|
* (default: func.length)
|
||||||
* @returns {Function} Memoized function
|
* @returns {Function} Memoized function
|
||||||
*/
|
*/
|
||||||
export function memoize<T>(
|
export function memoize<T>(
|
||||||
func: MemoizeFun<T>, limit?: number, num_args?: number): MemoizeFun<T> {
|
func: MemoizeFun<T>, limit?: number, numArgs?: number): MemoizeFun<T> {
|
||||||
const climit = limit && limit > 0 ? limit : DEFAULT_LIMIT;
|
const climit = limit && limit > 0 ? limit : DEFAULT_LIMIT;
|
||||||
num_args = num_args || func.length;
|
numArgs = numArgs || func.length;
|
||||||
|
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
memoes.push(cache);
|
memoes.push(cache);
|
||||||
@ -46,12 +46,12 @@ export function memoize<T>(
|
|||||||
const args: any[] = [];
|
const args: any[] = [];
|
||||||
let key; let result;
|
let key; let result;
|
||||||
|
|
||||||
switch (num_args) {
|
switch (numArgs) {
|
||||||
case 0:
|
case 0:
|
||||||
throw new Error("memoize does not support functions without arguments");
|
throw new Error("memoize does not support functions without arguments");
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return function memoize_one_arg(a: any) {
|
return function memoizeOne(a: any) {
|
||||||
key = a.spec || a;
|
key = a.spec || a;
|
||||||
if (cache.has(key)) {
|
if (cache.has(key)) {
|
||||||
return cache.get(key);
|
return cache.get(key);
|
||||||
@ -66,7 +66,7 @@ export function memoize<T>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return function memoize_two_args(a: any, b: any) {
|
return function memoizeTwo(a: any, b: any) {
|
||||||
args[0] = a; args[1] = b;
|
args[0] = a; args[1] = b;
|
||||||
key = JSON.stringify(args);
|
key = JSON.stringify(args);
|
||||||
args.length = 0;
|
args.length = 0;
|
||||||
@ -84,7 +84,7 @@ export function memoize<T>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return function memoize_three_args(a: any, b: any, c: any) {
|
return function memoizeThree(a: any, b: any, c: any) {
|
||||||
args[0] = a; args[1] = b; args[2] = c;
|
args[0] = a; args[1] = b; args[2] = c;
|
||||||
key = JSON.stringify(args);
|
key = JSON.stringify(args);
|
||||||
args.length = 0;
|
args.length = 0;
|
||||||
@ -102,7 +102,7 @@ export function memoize<T>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
return function memoize_four_args(a: any, b: any, c: any, d: any) {
|
return function memoizeFour(a: any, b: any, c: any, d: any) {
|
||||||
args[0] = a; args[1] = b; args[2] = c; args[3] = d;
|
args[0] = a; args[1] = b; args[2] = c; args[3] = d;
|
||||||
key = JSON.stringify(args);
|
key = JSON.stringify(args);
|
||||||
args.length = 0;
|
args.length = 0;
|
||||||
|
@ -5,7 +5,7 @@ const RUNNING = Symbol();
|
|||||||
const LIMIT = Symbol();
|
const LIMIT = Symbol();
|
||||||
const ITEMS = Symbol();
|
const ITEMS = Symbol();
|
||||||
|
|
||||||
function nothing() {}
|
function nothing() { /* ignored */ }
|
||||||
|
|
||||||
type Wrapped<T> = (...args: any[]) => Promise<T>;
|
type Wrapped<T> = (...args: any[]) => Promise<T>;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
const re_tokenize = /(0x[0-9a-f]+|[+-]?[0-9]+(?:\.[0-9]*(?:e[+-]?[0-9]+)?)?|\d+)/i;
|
const RE_TOKENIZE = /(0x[0-9a-f]+|[+-]?[0-9]+(?:\.[0-9]*(?:e[+-]?[0-9]+)?)?|\d+)/i;
|
||||||
const re_hex = /^0x[0-9a-z]+$/i;
|
const RE_HEX = /^0x[0-9a-z]+$/i;
|
||||||
const re_trimmore = /\s+/g;
|
const RE_TRIMMORE = /\s+/g;
|
||||||
|
|
||||||
type KeyFunc<T> = (v: T) => any;
|
type KeyFunc<T> = (v: T) => any;
|
||||||
type CompareFunc<T> = (a: T, b: T) => number;
|
type CompareFunc<T> = (a: T, b: T) => number;
|
||||||
@ -14,31 +14,29 @@ type CompareFunc<T> = (a: T, b: T) => number;
|
|||||||
* @param {*} b Second value
|
* @param {*} b Second value
|
||||||
* @returns {number} Comparision result
|
* @returns {number} Comparision result
|
||||||
*/
|
*/
|
||||||
export function default_compare(a: any, b: any) {
|
export function defaultCompare(a: any, b: any) {
|
||||||
return a < b ? -1 : (a > b ? 1 : 0);
|
return a < b ? -1 : (a > b ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseToken(chunk: string) {
|
function parseToken(chunk: string) {
|
||||||
chunk = chunk.replace(re_trimmore, " ").trim();
|
chunk = chunk.replace(RE_TRIMMORE, " ").trim();
|
||||||
if (re_hex.test(chunk)) {
|
if (RE_HEX.test(chunk)) {
|
||||||
return parseInt(chunk.slice(2), 16);
|
return parseInt(chunk.slice(2), 16);
|
||||||
}
|
}
|
||||||
const val = parseFloat(chunk);
|
const val = parseFloat(chunk);
|
||||||
return Number.isNaN(val) ? chunk : val;
|
return Number.isNaN(val) ? chunk : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterTokens(str: string) {
|
||||||
function token_filter(str: string) {
|
|
||||||
return str && str.trim();
|
return str && str.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function tokenize(val: any) {
|
function tokenize(val: any) {
|
||||||
if (typeof val === "number") {
|
if (typeof val === "number") {
|
||||||
return [[`${val}`], [val]];
|
return [[`${val}`], [val]];
|
||||||
}
|
}
|
||||||
const tokens = `${val}`.split(re_tokenize).filter(token_filter);
|
const tokens = `${val}`.split(RE_TOKENIZE).filter(filterTokens);
|
||||||
const numeric = tokens.map(parseToken);
|
const numeric = tokens.map(parseToken);
|
||||||
return [tokens, numeric];
|
return [tokens, numeric];
|
||||||
}
|
}
|
||||||
@ -76,8 +74,8 @@ export function naturalCompare(a: any, b: any): number {
|
|||||||
if (xisnum) {
|
if (xisnum) {
|
||||||
// both are numbers
|
// both are numbers
|
||||||
// Compare the numbers and if they are the same, the tokens too
|
// Compare the numbers and if they are the same, the tokens too
|
||||||
const res = default_compare(xnum, ynum) ||
|
const res = defaultCompare(xnum, ynum) ||
|
||||||
default_compare(xTokens[i], yTokens[i]);
|
defaultCompare(xTokens[i], yTokens[i]);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -86,13 +84,13 @@ export function naturalCompare(a: any, b: any): number {
|
|||||||
|
|
||||||
// both must be stringey
|
// both must be stringey
|
||||||
// Compare the actual tokens.
|
// Compare the actual tokens.
|
||||||
const res = default_compare(xTokens[i], yTokens[i]);
|
const res = defaultCompare(xTokens[i], yTokens[i]);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return default_compare(xTokenLen, yTokenLen);
|
return defaultCompare(xTokenLen, yTokenLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,19 +112,19 @@ export function naturalCaseCompare(a: any, b: any) {
|
|||||||
* @param {cmpf} [cmp] Compare function or default_compare
|
* @param {cmpf} [cmp] Compare function or default_compare
|
||||||
* @returns {number} Comparison result
|
* @returns {number} Comparison result
|
||||||
*/
|
*/
|
||||||
export function array_compare(a: any, b: any, cmp: CompareFunc<any>): number {
|
export function arrayCompare(a: any, b: any, cmp: CompareFunc<any>): number {
|
||||||
cmp = cmp || default_compare;
|
cmp = cmp || defaultCompare;
|
||||||
if (Array.isArray(a) && Array.isArray(b)) {
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||||||
const {length: alen} = a;
|
const {length: alen} = a;
|
||||||
const {length: blen} = b;
|
const {length: blen} = b;
|
||||||
const len = Math.min(alen, blen);
|
const len = Math.min(alen, blen);
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
const rv = array_compare(a[i], b[i], cmp);
|
const rv = arrayCompare(a[i], b[i], cmp);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default_compare(alen, blen);
|
return defaultCompare(alen, blen);
|
||||||
}
|
}
|
||||||
return cmp(a, b);
|
return cmp(a, b);
|
||||||
}
|
}
|
||||||
@ -137,12 +135,12 @@ interface MapValue {
|
|||||||
value: any;
|
value: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapped_compare(
|
function mappedCompare(
|
||||||
fn: CompareFunc<any>, a: MapValue, b: MapValue): number {
|
fn: CompareFunc<any>, a: MapValue, b: MapValue): number {
|
||||||
const {key: ka} = a;
|
const {key: ka} = a;
|
||||||
const {key: kb} = b;
|
const {key: kb} = b;
|
||||||
return array_compare(ka, kb, fn) ||
|
return arrayCompare(ka, kb, fn) ||
|
||||||
/* stable */ default_compare(a.index, b.index);
|
/* stable */ defaultCompare(a.index, b.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,8 +167,8 @@ function mapped_compare(
|
|||||||
* @returns {*[]} New sorted array
|
* @returns {*[]} New sorted array
|
||||||
*/
|
*/
|
||||||
export function sort<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
export function sort<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
||||||
cmp = cmp || default_compare;
|
cmp = cmp || defaultCompare;
|
||||||
const carr = <MapValue[]> <unknown> arr;
|
const carr = arr as unknown as MapValue[];
|
||||||
if (key) {
|
if (key) {
|
||||||
arr.forEach((value, index) => {
|
arr.forEach((value, index) => {
|
||||||
carr[index] = {value, key: key(value), index};
|
carr[index] = {value, key: key(value), index};
|
||||||
@ -181,7 +179,7 @@ export function sort<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
|||||||
carr[index] = {value, key: value, index};
|
carr[index] = {value, key: value, index};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
arr.sort(mapped_compare.bind(null, cmp));
|
arr.sort(mappedCompare.bind(null, cmp));
|
||||||
carr.forEach((i, idx) => {
|
carr.forEach((i, idx) => {
|
||||||
arr[idx] = i.value;
|
arr[idx] = i.value;
|
||||||
});
|
});
|
||||||
@ -198,7 +196,7 @@ export function sort<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
|||||||
* @returns {*[]} New sorted array
|
* @returns {*[]} New sorted array
|
||||||
*/
|
*/
|
||||||
export function sorted<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
export function sorted<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
||||||
cmp = cmp || default_compare;
|
cmp = cmp || defaultCompare;
|
||||||
let carr: MapValue[];
|
let carr: MapValue[];
|
||||||
if (key) {
|
if (key) {
|
||||||
carr = arr.map((value, index) => {
|
carr = arr.map((value, index) => {
|
||||||
@ -210,6 +208,6 @@ export function sorted<T>(arr: T[], key?: KeyFunc<T>, cmp?: CompareFunc<T>) {
|
|||||||
return {value, key: value, index};
|
return {value, key: value, index};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
carr.sort(mapped_compare.bind(null, cmp));
|
carr.sort(mappedCompare.bind(null, cmp));
|
||||||
return carr.map(v => v.value);
|
return carr.map(v => v.value);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ export class FakeLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAttribute(attr: string) {
|
getAttribute(attr: string) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
return (attr in self) ? self[attr] : null;
|
return (attr in self) ? self[attr] : null;
|
||||||
}
|
}
|
||||||
|
40
lib/util.ts
40
lib/util.ts
@ -47,7 +47,21 @@ export function lazy<T>(object: any, name: string, fun: (...any: any[]) => T) {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function none() { }
|
export function none() { /* ignored */ }
|
||||||
|
|
||||||
|
export const sanitizePath = identity(function sanitizePath(path: string) {
|
||||||
|
return path.
|
||||||
|
replace(/:+/g, "ː").
|
||||||
|
replace(/\?+/g, "_").
|
||||||
|
replace(/\*+/g, "_").
|
||||||
|
replace(/<+/g, "◄").
|
||||||
|
replace(/>+/g, "▶").
|
||||||
|
replace(/"+/g, "'").
|
||||||
|
replace(/\|+/g, "¦").
|
||||||
|
replace(/#+/g, "♯").
|
||||||
|
replace(/[.\s]+$/g, "").
|
||||||
|
trim();
|
||||||
|
});
|
||||||
|
|
||||||
// XXX cleanup + test
|
// XXX cleanup + test
|
||||||
export const parsePath = memoize(function parsePath(path: string | URL) {
|
export const parsePath = memoize(function parsePath(path: string | URL) {
|
||||||
@ -89,21 +103,6 @@ export const parsePath = memoize(function parsePath(path: string | URL) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const sanitizePath = identity(function sanitizePath(path: string) {
|
|
||||||
return path.
|
|
||||||
replace(/:+/g, "ː").
|
|
||||||
replace(/\?+/g, "_").
|
|
||||||
replace(/\*+/g, "_").
|
|
||||||
replace(/<+/g, "◄").
|
|
||||||
replace(/>+/g, "▶").
|
|
||||||
replace(/"+/g, "'").
|
|
||||||
replace(/\|+/g, "¦").
|
|
||||||
replace(/#+/g, "♯").
|
|
||||||
replace(/[.\s]+$/g, "").
|
|
||||||
trim();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
export class CoalescedUpdate<T> extends Set<T> {
|
export class CoalescedUpdate<T> extends Set<T> {
|
||||||
private readonly to: number;
|
private readonly to: number;
|
||||||
|
|
||||||
@ -141,7 +140,7 @@ export class CoalescedUpdate<T> extends Set<T> {
|
|||||||
export const hostToDomain = memoize(psl.get, 1000);
|
export const hostToDomain = memoize(psl.get, 1000);
|
||||||
|
|
||||||
export interface URLd extends URL {
|
export interface URLd extends URL {
|
||||||
domain: string
|
domain: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(URL.prototype, "domain", {
|
Object.defineProperty(URL.prototype, "domain", {
|
||||||
@ -188,7 +187,8 @@ export function filterInSitu<T>(arr: T[], cb: (value: T) => boolean, tp?: any) {
|
|||||||
*/
|
*/
|
||||||
export function mapInSitu<TRes, T>(arr: T[], cb: (value: T) => TRes, tp?: any) {
|
export function mapInSitu<TRes, T>(arr: T[], cb: (value: T) => TRes, tp?: any) {
|
||||||
tp = tp || null;
|
tp = tp || null;
|
||||||
const carr = <TRes[]> <unknown> arr;
|
const carr = arr as unknown as TRes[];
|
||||||
|
|
||||||
for (let i = 0, e = arr.length; i < e; i++) {
|
for (let i = 0, e = arr.length; i < e; i++) {
|
||||||
carr[i] = cb.call(tp, arr[i], i, arr);
|
carr[i] = cb.call(tp, arr[i], i, arr);
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ export function filterMapInSitu<TRes, T>(
|
|||||||
mapStep: (value: T) => TRes,
|
mapStep: (value: T) => TRes,
|
||||||
tp?: any) {
|
tp?: any) {
|
||||||
tp = tp || null;
|
tp = tp || null;
|
||||||
const carr = <TRes[]> <unknown> arr;
|
const carr = arr as unknown as TRes[];
|
||||||
|
|
||||||
let i; let k; let e;
|
let i; let k; let e;
|
||||||
for (i = 0, k = 0, e = arr.length; i < e; i++) {
|
for (i = 0, k = 0, e = arr.length; i < e; i++) {
|
||||||
@ -238,7 +238,7 @@ export function mapFilterInSitu<TRes, T>(
|
|||||||
filterStep: (value: T) => boolean,
|
filterStep: (value: T) => boolean,
|
||||||
tp?: any) {
|
tp?: any) {
|
||||||
tp = tp || null;
|
tp = tp || null;
|
||||||
const carr = <TRes[]> <unknown> arr;
|
const carr = arr as unknown as TRes[];
|
||||||
|
|
||||||
let i; let k; let e;
|
let i; let k; let e;
|
||||||
for (i = 0, k = 0, e = arr.length; i < e; i++) {
|
for (i = 0, k = 0, e = arr.length; i < e; i++) {
|
||||||
|
@ -12,6 +12,7 @@ try {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const cr = require("crypto");
|
const cr = require("crypto");
|
||||||
|
|
||||||
return function(size: number) {
|
return function(size: number) {
|
||||||
|
@ -67,6 +67,7 @@ export class AbstractTable extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
setCellCheck(rowid: number, colid: number, value: boolean) {
|
setCellCheck(rowid: number, colid: number, value: boolean) {
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,6 +113,7 @@ export class AnimationPool {
|
|||||||
* Your newly bound function.
|
* Your newly bound function.
|
||||||
*/
|
*/
|
||||||
wrap(fn: Function) {
|
wrap(fn: Function) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self = this;
|
const self = this;
|
||||||
return function wrapped(...args: any[]) {
|
return function wrapped(...args: any[]) {
|
||||||
return self.schedule(this, fn, ...args);
|
return self.schedule(this, fn, ...args);
|
||||||
|
@ -168,6 +168,7 @@ export class BaseTable extends AbstractTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do not override unless you know what you're doing */
|
/* do not override unless you know what you're doing */
|
||||||
@ -471,7 +472,7 @@ export class BaseTable extends AbstractTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isCheckClick(evt: MouseEvent) {
|
isCheckClick(evt: MouseEvent) {
|
||||||
return /virtualtable-check/.test((<HTMLElement> evt.target).className) &&
|
return /virtualtable-check/.test((evt.target as HTMLElement).className) &&
|
||||||
!evt.ctrlKey && !evt.shiftKey && !evt.metaKey;
|
!evt.ctrlKey && !evt.shiftKey && !evt.metaKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ function toKeyText(key: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuPosition {
|
export interface MenuPosition {
|
||||||
clientX: number,
|
clientX: number;
|
||||||
clientY: number,
|
clientY: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MenuItemBase {
|
export class MenuItemBase {
|
||||||
@ -137,6 +137,7 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
this.elem.setAttribute("aria-role", "menuitem");
|
this.elem.setAttribute("aria-role", "menuitem");
|
||||||
this.elem.setAttribute("aria-haspopup", "true");
|
this.elem.setAttribute("aria-haspopup", "true");
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
this.menu = new ContextMenu();
|
this.menu = new ContextMenu();
|
||||||
|
|
||||||
this.expandElem = document.createElement("span");
|
this.expandElem = document.createElement("span");
|
||||||
@ -177,7 +178,7 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
|
|
||||||
entered(event: MouseEvent) {
|
entered(event: MouseEvent) {
|
||||||
const {target} = event;
|
const {target} = event;
|
||||||
const htarget = <HTMLElement> target;
|
const htarget = target as HTMLElement;
|
||||||
if (htarget.classList.contains("context-menu")) {
|
if (htarget.classList.contains("context-menu")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -307,7 +308,7 @@ export class ContextMenu extends EventEmitter {
|
|||||||
Math.abs(event.clientY - origEvent.clientY) < CLICK_DIFF) {
|
Math.abs(event.clientY - origEvent.clientY) < CLICK_DIFF) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let el = <HTMLElement> event.target;
|
let el = event.target as HTMLElement;
|
||||||
while (el) {
|
while (el) {
|
||||||
if (el.classList.contains("context-menu")) {
|
if (el.classList.contains("context-menu")) {
|
||||||
return;
|
return;
|
||||||
@ -386,7 +387,7 @@ export class ContextMenu extends EventEmitter {
|
|||||||
el.parentElement.removeChild(el);
|
el.parentElement.removeChild(el);
|
||||||
}
|
}
|
||||||
if (el.localName === "template") {
|
if (el.localName === "template") {
|
||||||
el = <HTMLElement> (<HTMLTemplateElement> el).content.firstElementChild;
|
el = (el as HTMLTemplateElement).content.firstElementChild as HTMLElement;
|
||||||
}
|
}
|
||||||
if (el.className) {
|
if (el.className) {
|
||||||
this.elem.className = el.className;
|
this.elem.className = el.className;
|
||||||
@ -408,24 +409,24 @@ export class ContextMenu extends EventEmitter {
|
|||||||
if (sub) {
|
if (sub) {
|
||||||
throw new Error("Already has a submenu");
|
throw new Error("Already has a submenu");
|
||||||
}
|
}
|
||||||
if ((<HTMLElement> sc).localName !== "ul") {
|
if ((sc as HTMLElement).localName !== "ul") {
|
||||||
throw new Error("Not a valid submenu");
|
throw new Error("Not a valid submenu");
|
||||||
}
|
}
|
||||||
sub = sc;
|
sub = sc;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid node: ${(<HTMLElement> sc).localName}`);
|
throw new Error(`Invalid node: ${(sc as HTMLElement).localName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const joined = text.join(" ").trim();
|
const joined = text.join(" ").trim();
|
||||||
let item = null;
|
let item = null;
|
||||||
const ce = <HTMLElement> child;
|
const ce = child as HTMLElement;
|
||||||
if (joined === "-") {
|
if (joined === "-") {
|
||||||
item = new MenuSeperatorItem(this, child.id);
|
item = new MenuSeperatorItem(this, child.id);
|
||||||
}
|
}
|
||||||
else if (sub) {
|
else if (sub) {
|
||||||
item = new SubMenuItem(this, child.id, joined, ce.dataset);
|
item = new SubMenuItem(this, child.id, joined, ce.dataset);
|
||||||
item.constructFromTemplate(<HTMLElement> sub);
|
item.constructFromTemplate(sub as HTMLElement);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
item = new MenuItem(this, child.id, joined, ce.dataset);
|
item = new MenuItem(this, child.id, joined, ce.dataset);
|
||||||
|
@ -63,6 +63,7 @@ export class EventEmitter {
|
|||||||
once(event: string, cb: (...args: any[]) => any) {
|
once(event: string, cb: (...args: any[]) => any) {
|
||||||
const wrapped = (...args: any[]) => {
|
const wrapped = (...args: any[]) => {
|
||||||
try {
|
try {
|
||||||
|
// eslint-disable-next-line prefer-spread
|
||||||
return cb.apply(null, args);
|
return cb.apply(null, args);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -102,6 +103,7 @@ export class EventEmitter {
|
|||||||
}
|
}
|
||||||
for (const e of Array.from(handlers)) {
|
for (const e of Array.from(handlers)) {
|
||||||
try {
|
try {
|
||||||
|
// eslint-disable-next-line prefer-spread
|
||||||
handled = handled || !!e.apply(null, args);
|
handled = handled || !!e.apply(null, args);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
|
@ -119,6 +119,7 @@ export default class ModalDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shown() {
|
shown() {
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
focusDefault() {
|
focusDefault() {
|
||||||
@ -148,7 +149,7 @@ export default class ModalDialog {
|
|||||||
if (e.key !== "Enter") {
|
if (e.key !== "Enter") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const {localName} = <HTMLElement> e.target;
|
const {localName} = e.target as HTMLElement;
|
||||||
if (localName === "textarea" && !e.metaKey) {
|
if (localName === "textarea" && !e.metaKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ export class TableSelection extends EventEmitter {
|
|||||||
newSelection._add(pos, r.end + offset);
|
newSelection._add(pos, r.end + offset);
|
||||||
}
|
}
|
||||||
this.ranges.length = 0;
|
this.ranges.length = 0;
|
||||||
this.ranges.push.apply(this.ranges, newSelection.ranges);
|
this.ranges.push(...newSelection.ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
@ -38,7 +38,7 @@ export class Broadcaster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onkey(evt: KeyboardEvent) {
|
onkey(evt: KeyboardEvent) {
|
||||||
const {localName} = <HTMLElement> evt.target;
|
const {localName} = evt.target as HTMLElement;
|
||||||
if (localName === "input" || localName === "textarea") {
|
if (localName === "input" || localName === "textarea") {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ export class Dropdown extends EventEmitter {
|
|||||||
this.container.classList.add("dropdown");
|
this.container.classList.add("dropdown");
|
||||||
|
|
||||||
input = input.parentElement.replaceChild(this.container, input);
|
input = input.parentElement.replaceChild(this.container, input);
|
||||||
this.input = <HTMLInputElement> input;
|
this.input = input as HTMLInputElement;
|
||||||
this.container.appendChild(this.input);
|
this.container.appendChild(this.input);
|
||||||
|
|
||||||
this.select = document.createElement("select");
|
this.select = document.createElement("select");
|
||||||
|
@ -8,7 +8,7 @@ export class Icons extends Map {
|
|||||||
|
|
||||||
constructor(el: HTMLStyleElement) {
|
constructor(el: HTMLStyleElement) {
|
||||||
super();
|
super();
|
||||||
this.sheet = <CSSStyleSheet> el.sheet;
|
this.sheet = el.sheet as CSSStyleSheet;
|
||||||
this.running = 0;
|
this.running = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export class Buttons extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clicked(evt: MouseEvent) {
|
clicked(evt: MouseEvent) {
|
||||||
let target = <HTMLElement | null> evt.target;
|
let target = evt.target as HTMLElement | null;
|
||||||
while (target && target !== this.parent) {
|
while (target && target !== this.parent) {
|
||||||
if (target.classList.contains("button")) {
|
if (target.classList.contains("button")) {
|
||||||
const {id} = target;
|
const {id} = target;
|
||||||
|
@ -12,8 +12,9 @@ import {
|
|||||||
MenuPosition,
|
MenuPosition,
|
||||||
} from "../../uikit/lib/contextmenu";
|
} from "../../uikit/lib/contextmenu";
|
||||||
import {EventEmitter} from "../../lib/events";
|
import {EventEmitter} from "../../lib/events";
|
||||||
import {filters, Matcher} from "../../lib/filters";
|
// eslint-disable-next-line no-unused-vars
|
||||||
import {sort, default_compare, naturalCaseCompare} from "../../lib/sorting";
|
import {filters, Matcher, Filter} from "../../lib/filters";
|
||||||
|
import {sort, defaultCompare, naturalCaseCompare} from "../../lib/sorting";
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import {DownloadItem, DownloadTable} from "./table";
|
import {DownloadItem, DownloadTable} from "./table";
|
||||||
import {formatSize} from "../../lib/formatters";
|
import {formatSize} from "../../lib/formatters";
|
||||||
@ -162,7 +163,10 @@ export class MenuFilter extends ItemFilter {
|
|||||||
if (!callback) {
|
if (!callback) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this.toggleItem(<MenuItem> item);
|
if (!(item instanceof MenuItem)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.toggleItem(item);
|
||||||
callback.apply(this);
|
callback.apply(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +192,10 @@ export class MenuFilter extends ItemFilter {
|
|||||||
if (!item) {
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.toggleItem(<MenuItem> item);
|
if (!(item instanceof MenuItem)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.toggleItem(item);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback.call(this);
|
callback.call(this);
|
||||||
}
|
}
|
||||||
@ -300,7 +307,7 @@ export class SizeMenuFilter extends FixedMenuFilter {
|
|||||||
export class UrlMenuFilter extends MenuFilter {
|
export class UrlMenuFilter extends MenuFilter {
|
||||||
collection: FilteredCollection;
|
collection: FilteredCollection;
|
||||||
|
|
||||||
filters: Set<any>;
|
filters: Set<Filter>;
|
||||||
|
|
||||||
domains: Set<string>;
|
domains: Set<string>;
|
||||||
|
|
||||||
@ -364,7 +371,7 @@ export class UrlMenuFilter extends MenuFilter {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const exprs = Array.from(this.filters).map(f => Array.from(f)).flat();
|
const exprs = Array.from(this.filters).map(f => Array.from(f)).flat();
|
||||||
this.matcher = new Matcher(<RegExp[]> exprs);
|
this.matcher = new Matcher(exprs);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collection.addFilter(this);
|
this.collection.addFilter(this);
|
||||||
@ -570,7 +577,7 @@ export class FilteredCollection extends EventEmitter {
|
|||||||
* @param {boolean} [natural] Sort naturally
|
* @param {boolean} [natural] Sort naturally
|
||||||
*/
|
*/
|
||||||
sort(keyfn: (i: DownloadItem) => any, descending = false, natural = false) {
|
sort(keyfn: (i: DownloadItem) => any, descending = false, natural = false) {
|
||||||
const cmp = natural ? naturalCaseCompare : default_compare;
|
const cmp = natural ? naturalCaseCompare : defaultCompare;
|
||||||
let cmpfn = cmp;
|
let cmpfn = cmp;
|
||||||
if (descending) {
|
if (descending) {
|
||||||
cmpfn = (a, b) => -cmp(a, b);
|
cmpfn = (a, b) => -cmp(a, b);
|
||||||
|
@ -147,7 +147,10 @@ export class Tooltip {
|
|||||||
this.update = this.update.bind(this);
|
this.update = this.update.bind(this);
|
||||||
this.item = item;
|
this.item = item;
|
||||||
const tmpl = (
|
const tmpl = (
|
||||||
<HTMLTemplateElement> document.querySelector("#tooltip-template"));
|
document.querySelector<HTMLTemplateElement>("#tooltip-template"));
|
||||||
|
if (!tmpl) {
|
||||||
|
throw new Error("template failed");
|
||||||
|
}
|
||||||
const el = tmpl.content.firstElementChild;
|
const el = tmpl.content.firstElementChild;
|
||||||
if (!el) {
|
if (!el) {
|
||||||
throw new Error("invalid template");
|
throw new Error("invalid template");
|
||||||
@ -155,8 +158,9 @@ export class Tooltip {
|
|||||||
this.elem = localize(el.cloneNode(true) as HTMLElement);
|
this.elem = localize(el.cloneNode(true) as HTMLElement);
|
||||||
this.adjust(pos);
|
this.adjust(pos);
|
||||||
|
|
||||||
ELEMS.forEach(e => {
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
|
ELEMS.forEach(e => {
|
||||||
self[e] = this.elem.querySelector(`#tooltip-${e}`);
|
self[e] = this.elem.querySelector(`#tooltip-${e}`);
|
||||||
});
|
});
|
||||||
document.body.appendChild(this.elem);
|
document.body.appendChild(this.elem);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user