less of any
This commit is contained in:
parent
116d5b9b00
commit
544b7d522c
54
lib/api.ts
54
lib/api.ts
@ -5,7 +5,8 @@ import { TYPE_LINK, TYPE_MEDIA } from "./constants";
|
|||||||
import { filters } from "./filters";
|
import { filters } from "./filters";
|
||||||
import { Prefs } from "./prefs";
|
import { Prefs } from "./prefs";
|
||||||
import { lazy } from "./util";
|
import { lazy } from "./util";
|
||||||
import { Item, makeUniqueItems } from "./item";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { Item, makeUniqueItems, BaseItem } from "./item";
|
||||||
import { getManager } from "./manager/man";
|
import { getManager } from "./manager/man";
|
||||||
import { select } from "./select";
|
import { select } from "./select";
|
||||||
import { single } from "./single";
|
import { single } from "./single";
|
||||||
@ -16,12 +17,17 @@ import { _ } from "./i18n";
|
|||||||
|
|
||||||
const MAX_BATCH = 10000;
|
const MAX_BATCH = 10000;
|
||||||
|
|
||||||
|
export interface QueueOptions {
|
||||||
|
mask?: string;
|
||||||
|
paused?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export const API = new class APIImpl {
|
export const API = new class APIImpl {
|
||||||
async filter(arr: any, type: number) {
|
async filter(arr: BaseItem[], type: number) {
|
||||||
return await (await filters()).filterItemsByType(arr, type);
|
return await (await filters()).filterItemsByType(arr, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
async queue(items: any, options: any) {
|
async queue(items: BaseItem[], options: QueueOptions) {
|
||||||
await MASK.init();
|
await MASK.init();
|
||||||
const {mask = MASK.current} = options;
|
const {mask = MASK.current} = options;
|
||||||
|
|
||||||
@ -36,12 +42,9 @@ export const API = new class APIImpl {
|
|||||||
fileName: null,
|
fileName: null,
|
||||||
title: "",
|
title: "",
|
||||||
description: "",
|
description: "",
|
||||||
fromMetalink: false,
|
|
||||||
startDate: new Date(),
|
startDate: new Date(),
|
||||||
hashes: [],
|
|
||||||
private: false,
|
private: false,
|
||||||
postData: null,
|
postData: null,
|
||||||
cleanRequest: false,
|
|
||||||
mask,
|
mask,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
paused
|
paused
|
||||||
@ -54,7 +57,7 @@ export const API = new class APIImpl {
|
|||||||
}
|
}
|
||||||
return currentBatch;
|
return currentBatch;
|
||||||
});
|
});
|
||||||
items = items.map((i: any) => {
|
items = items.map(i => {
|
||||||
delete i.idx;
|
delete i.idx;
|
||||||
return new Item(i, defaults);
|
return new Item(i, defaults);
|
||||||
});
|
});
|
||||||
@ -79,7 +82,7 @@ export const API = new class APIImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sanity(links: any[], media: any[]) {
|
sanity(links: BaseItem[], media: BaseItem[]) {
|
||||||
if (!links.length && !media.length) {
|
if (!links.length && !media.length) {
|
||||||
new Notification(null, _("no-links"));
|
new Notification(null, _("no-links"));
|
||||||
return false;
|
return false;
|
||||||
@ -87,7 +90,7 @@ export const API = new class APIImpl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async turbo(links: any[], media: any[]) {
|
async turbo(links: BaseItem[], media: BaseItem[]) {
|
||||||
if (!this.sanity(links, media)) {
|
if (!this.sanity(links, media)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -105,37 +108,36 @@ export const API = new class APIImpl {
|
|||||||
return await this.queue(selected, {paused: await Prefs.get("add-paused")});
|
return await this.queue(selected, {paused: await Prefs.get("add-paused")});
|
||||||
}
|
}
|
||||||
|
|
||||||
async regularInternal(selected: any) {
|
async regularInternal(selected: BaseItem[], options: any) {
|
||||||
if (selected.mask && !selected.maskOnce) {
|
if (options.mask && !options.maskOnce) {
|
||||||
await MASK.init();
|
await MASK.init();
|
||||||
await MASK.push(selected.mask);
|
await MASK.push(options.mask);
|
||||||
}
|
}
|
||||||
if (typeof selected.fast === "string" && !selected.fastOnce) {
|
if (typeof options.fast === "string" && !options.fastOnce) {
|
||||||
await FASTFILTER.init();
|
await FASTFILTER.init();
|
||||||
await FASTFILTER.push(selected.fast);
|
await FASTFILTER.push(options.fast);
|
||||||
}
|
}
|
||||||
if (typeof selected.type === "string") {
|
if (typeof options.type === "string") {
|
||||||
await Prefs.set("last-type", selected.type);
|
await Prefs.set("last-type", options.type);
|
||||||
}
|
}
|
||||||
const {items} = selected;
|
return await this.queue(selected, options);
|
||||||
delete selected.items;
|
|
||||||
return await this.queue(items, selected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async regular(links: any[], media: any[]) {
|
async regular(links: BaseItem[], media: BaseItem[]) {
|
||||||
if (!this.sanity(links, media)) {
|
if (!this.sanity(links, media)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const selected = await select(links, media);
|
const {items, options} = await select(links, media);
|
||||||
return this.regularInternal(selected);
|
console.log(items, options);
|
||||||
|
return this.regularInternal(items, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async singleTurbo(item: any) {
|
async singleTurbo(item: BaseItem) {
|
||||||
return await this.queue([item], {paused: await Prefs.get("add-paused")});
|
return await this.queue([item], {paused: await Prefs.get("add-paused")});
|
||||||
}
|
}
|
||||||
|
|
||||||
async singleRegular(item: any) {
|
async singleRegular(item: BaseItem | null) {
|
||||||
const selected = await single(item);
|
const {items, options} = await single(item);
|
||||||
return this.regularInternal(selected);
|
return this.regularInternal(items, options);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
@ -13,9 +13,14 @@ import {
|
|||||||
browserAction as action,
|
browserAction as action,
|
||||||
menus as _menus, contextMenus as _cmenus,
|
menus as _menus, contextMenus as _cmenus,
|
||||||
tabs,
|
tabs,
|
||||||
webNavigation as nav
|
webNavigation as nav,
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
Tab,
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
MenuClickInfo
|
||||||
} from "./browser";
|
} from "./browser";
|
||||||
import { Bus } from "./bus";
|
import { Bus } from "./bus";
|
||||||
|
import { filterInSitu } from "./util";
|
||||||
|
|
||||||
|
|
||||||
const menus = typeof (_menus) !== "undefined" && _menus || _cmenus;
|
const menus = typeof (_menus) !== "undefined" && _menus || _cmenus;
|
||||||
@ -23,7 +28,7 @@ const menus = typeof (_menus) !== "undefined" && _menus || _cmenus;
|
|||||||
const GATHER = "/bundles/content-gather.js";
|
const GATHER = "/bundles/content-gather.js";
|
||||||
|
|
||||||
|
|
||||||
async function runContentJob(tab: any, file: string, msg: any) {
|
async function runContentJob(tab: Tab, file: string, msg: any) {
|
||||||
try {
|
try {
|
||||||
const res = await tabs.executeScript(tab.id, {
|
const res = await tabs.executeScript(tab.id, {
|
||||||
file,
|
file,
|
||||||
@ -56,7 +61,7 @@ type SelectionOptions = {
|
|||||||
selectionOnly: boolean;
|
selectionOnly: boolean;
|
||||||
allTabs: boolean;
|
allTabs: boolean;
|
||||||
turbo: boolean;
|
turbo: boolean;
|
||||||
tab: any;
|
tab: Tab;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -71,9 +76,8 @@ class Handler {
|
|||||||
return makeUniqueItems(
|
return makeUniqueItems(
|
||||||
results.filter(e => e[what]).map(e => {
|
results.filter(e => e[what]).map(e => {
|
||||||
const finisher = new Finisher(e);
|
const finisher = new Finisher(e);
|
||||||
return e[what].
|
return filterInSitu(e[what].
|
||||||
map((item: any) => finisher.finish(item)).
|
map((item: any) => finisher.finish(item)), e => !!e);
|
||||||
filter((i: any) => i);
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +352,7 @@ locale.then(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async findSingleItem(tab: any, url: string, turbo = false) {
|
async findSingleItem(tab: Tab, url: string, turbo = false) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -368,7 +372,7 @@ locale.then(() => {
|
|||||||
API[turbo ? "singleTurbo" : "singleRegular"](item);
|
API[turbo ? "singleTurbo" : "singleRegular"](item);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked(info: any, tab: any) {
|
onClicked(info: MenuClickInfo, tab: Tab) {
|
||||||
if (!tab.id) {
|
if (!tab.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -378,7 +382,7 @@ locale.then(() => {
|
|||||||
console.error("Invalid Handler for", menuItemId);
|
console.error("Invalid Handler for", menuItemId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rv = handler.call(this, info, tab);
|
const rv: Promise<void> | void = handler.call(this, info, tab);
|
||||||
if (rv && rv.catch) {
|
if (rv && rv.catch) {
|
||||||
rv.catch(console.error);
|
rv.catch(console.error);
|
||||||
}
|
}
|
||||||
@ -394,7 +398,7 @@ locale.then(() => {
|
|||||||
}, tab[0]);
|
}, tab[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegular(info: any, tab: any) {
|
async onClickedDTARegular(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: false,
|
selectionOnly: false,
|
||||||
allTabs: false,
|
allTabs: false,
|
||||||
@ -403,7 +407,7 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegularAll(info: any, tab: any) {
|
async onClickedDTARegularAll(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: false,
|
selectionOnly: false,
|
||||||
allTabs: true,
|
allTabs: true,
|
||||||
@ -412,7 +416,7 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegularSelection(info: any, tab: any) {
|
async onClickedDTARegularSelection(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: true,
|
selectionOnly: true,
|
||||||
allTabs: false,
|
allTabs: false,
|
||||||
@ -421,7 +425,7 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurbo(info: any, tab: any) {
|
async onClickedDTATurbo(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: false,
|
selectionOnly: false,
|
||||||
allTabs: false,
|
allTabs: false,
|
||||||
@ -430,7 +434,7 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurboAll(info: any, tab: any) {
|
async onClickedDTATurboAll(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: false,
|
selectionOnly: false,
|
||||||
allTabs: true,
|
allTabs: true,
|
||||||
@ -439,7 +443,7 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurboSelection(info: any, tab: any) {
|
async onClickedDTATurboSelection(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.performSelection({
|
return await this.performSelection({
|
||||||
selectionOnly: true,
|
selectionOnly: true,
|
||||||
allTabs: false,
|
allTabs: false,
|
||||||
@ -448,28 +452,46 @@ locale.then(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegularLink(info: any, tab: any) {
|
async onClickedDTARegularLink(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.linkUrl, false);
|
if (!info.linkUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.linkUrl, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurboLink(info: any, tab: any) {
|
async onClickedDTATurboLink(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.linkUrl, true);
|
if (!info.linkUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.linkUrl, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegularImage(info: any, tab: any) {
|
async onClickedDTARegularImage(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.srcUrl, false);
|
if (!info.srcUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.srcUrl, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurboImage(info: any, tab: any) {
|
async onClickedDTATurboImage(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.srcUrl, true);
|
if (!info.srcUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.srcUrl, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTARegularMedia(info: any, tab: any) {
|
async onClickedDTARegularMedia(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.srcUrl, false);
|
if (!info.srcUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.srcUrl, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onClickedDTATurboMedia(info: any, tab: any) {
|
async onClickedDTATurboMedia(info: MenuClickInfo, tab: Tab) {
|
||||||
return await this.findSingleItem(tab, info.srcUrl, true);
|
if (!info.srcUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.findSingleItem(tab, info.srcUrl, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickedDTAAdd() {
|
onClickedDTAAdd() {
|
||||||
|
@ -98,9 +98,9 @@ export class BatchGenerator implements Generator {
|
|||||||
|
|
||||||
public readonly hasInvalid: boolean;
|
public readonly hasInvalid: boolean;
|
||||||
|
|
||||||
public readonly length: any;
|
public readonly length: number;
|
||||||
|
|
||||||
public readonly preview: any;
|
public readonly preview: string;
|
||||||
|
|
||||||
constructor(str: string) {
|
constructor(str: string) {
|
||||||
this.gens = [];
|
this.gens = [];
|
||||||
|
@ -3,6 +3,42 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const polyfill = require("webextension-polyfill");
|
const polyfill = require("webextension-polyfill");
|
||||||
|
|
||||||
|
interface ExtensionListener {
|
||||||
|
addListener: (listener: Function) => void;
|
||||||
|
removeListener: (listener: Function) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageSender {
|
||||||
|
tab?: Tab;
|
||||||
|
frameId?: number;
|
||||||
|
id?: number;
|
||||||
|
url?: string;
|
||||||
|
tlsChannelId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface Tab {
|
||||||
|
id?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuClickInfo {
|
||||||
|
menuItemId: string | number;
|
||||||
|
button?: number;
|
||||||
|
linkUrl?: string;
|
||||||
|
srcUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RawPort {
|
||||||
|
error: any;
|
||||||
|
name: string;
|
||||||
|
onDisconnect: ExtensionListener;
|
||||||
|
onMessage: ExtensionListener;
|
||||||
|
sender?: MessageSender;
|
||||||
|
disconnect: () => void;
|
||||||
|
postMessage: (message: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export const {extension} = polyfill;
|
export const {extension} = polyfill;
|
||||||
export const {notifications} = polyfill;
|
export const {notifications} = polyfill;
|
||||||
export const {browserAction} = polyfill;
|
export const {browserAction} = polyfill;
|
||||||
|
35
lib/bus.ts
35
lib/bus.ts
@ -2,22 +2,18 @@
|
|||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
import { EventEmitter } from "./events";
|
import { EventEmitter } from "./events";
|
||||||
import {runtime, tabs} from "./browser";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import {runtime, tabs, RawPort, MessageSender} from "./browser";
|
||||||
|
|
||||||
export class Port extends EventEmitter {
|
export class Port extends EventEmitter {
|
||||||
private port: any;
|
private port: RawPort | null;
|
||||||
|
|
||||||
constructor(port: any) {
|
constructor(port: RawPort) {
|
||||||
super();
|
super();
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
|
||||||
let disconnected = false;
|
let disconnected = false;
|
||||||
let tabListener: any;
|
|
||||||
const disconnect = () => {
|
const disconnect = () => {
|
||||||
if (tabListener) {
|
|
||||||
tabs.onRemoved.removeListener(tabListener);
|
|
||||||
tabListener = null;
|
|
||||||
}
|
|
||||||
if (disconnected) {
|
if (disconnected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -41,12 +37,17 @@ export class Port extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
|
if (!this.port) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return this.port.name;
|
return this.port.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
get id() {
|
get id() {
|
||||||
return this.port.sender && (
|
if (!this.port || !this.port.sender) {
|
||||||
this.port.sender.id || this.port.sender.extensionId);
|
return null;
|
||||||
|
}
|
||||||
|
return this.port.sender.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSelf() {
|
get isSelf() {
|
||||||
@ -54,6 +55,9 @@ export class Port extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post(msg: string, ...data: any[]) {
|
post(msg: string, ...data: any[]) {
|
||||||
|
if (!this.port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.port.postMessage({msg});
|
this.port.postMessage({msg});
|
||||||
return;
|
return;
|
||||||
@ -65,14 +69,17 @@ export class Port extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMessage(message: any) {
|
onMessage(message: any) {
|
||||||
if (Object.keys(message).includes("msg")) {
|
if (!this.port) {
|
||||||
this.emit(message.msg, message);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Array.isArray(message)) {
|
if (Array.isArray(message)) {
|
||||||
message.forEach(this.onMessage, this);
|
message.forEach(this.onMessage, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Object.keys(message).includes("msg")) {
|
||||||
|
this.emit(message.msg, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (typeof message === "string") {
|
if (typeof message === "string") {
|
||||||
this.emit(message);
|
this.emit(message);
|
||||||
return;
|
return;
|
||||||
@ -100,7 +107,7 @@ export const Bus = new class extends EventEmitter {
|
|||||||
runtime.onConnect.addListener(this.onConnect.bind(this));
|
runtime.onConnect.addListener(this.onConnect.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage(msg: any, sender: any, callback: any) {
|
onMessage(msg: any, sender: MessageSender, callback: any) {
|
||||||
let {type = null} = msg;
|
let {type = null} = msg;
|
||||||
if (!type) {
|
if (!type) {
|
||||||
type = msg;
|
type = msg;
|
||||||
@ -108,7 +115,7 @@ export const Bus = new class extends EventEmitter {
|
|||||||
this.emit(type, msg, callback);
|
this.emit(type, msg, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
onConnect(port: any) {
|
onConnect(port: RawPort) {
|
||||||
if (!port.name) {
|
if (!port.name) {
|
||||||
port.disconnect();
|
port.disconnect();
|
||||||
return;
|
return;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseItem } from "./item";
|
||||||
|
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
const VERSION = 1;
|
const VERSION = 1;
|
||||||
@ -40,12 +43,12 @@ export const DB = new class DB {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllInternal(resolve: (items: any[]) => void, reject: Function) {
|
getAllInternal(resolve: (items: BaseItem[]) => void, reject: Function) {
|
||||||
if (!this.db) {
|
if (!this.db) {
|
||||||
reject(new Error("db closed"));
|
reject(new Error("db closed"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const items: any[] = [];
|
const items: BaseItem[] = [];
|
||||||
const transaction = this.db.transaction(STORE, "readonly");
|
const transaction = this.db.transaction(STORE, "readonly");
|
||||||
transaction.onerror = ex => reject(ex);
|
transaction.onerror = ex => reject(ex);
|
||||||
const store = transaction.objectStore(STORE);
|
const store = transaction.objectStore(STORE);
|
||||||
|
@ -12,6 +12,8 @@ import { Overlayable } from "./objectoverlay";
|
|||||||
import * as DEFAULT_FILTERS from "../data/filters.json";
|
import * as DEFAULT_FILTERS from "../data/filters.json";
|
||||||
import { FASTFILTER } from "./recentlist";
|
import { FASTFILTER } from "./recentlist";
|
||||||
import { _, locale } from "./i18n";
|
import { _, locale } from "./i18n";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseItem } from "./item";
|
||||||
|
|
||||||
const REG_ESCAPE = /[{}()[\]\\^$.]/g;
|
const REG_ESCAPE = /[{}()[\]\\^$.]/g;
|
||||||
const REG_FNMATCH = /[*?]/;
|
const REG_FNMATCH = /[*?]/;
|
||||||
@ -174,25 +176,37 @@ export class Matcher {
|
|||||||
}
|
}
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
matchItem(item: any) {
|
matchItem(item: BaseItem) {
|
||||||
const {usable = "", title = "", description = "", fileName = ""} = item;
|
const {usable = "", title = "", description = "", fileName = ""} = item;
|
||||||
return this.match(usable) || this.match(title) ||
|
return this.match(usable) || this.match(title) ||
|
||||||
this.match(description) || this.match(fileName);
|
this.match(description) || this.match(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RawFilter extends Object {
|
||||||
|
active: boolean;
|
||||||
|
type: number;
|
||||||
|
label: string;
|
||||||
|
expr: string;
|
||||||
|
icon?: string;
|
||||||
|
custom?: boolean;
|
||||||
|
isOverridden?: (prop: string) => boolean;
|
||||||
|
reset?: () => void;
|
||||||
|
toJSON?: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
export class Filter {
|
export class Filter {
|
||||||
private readonly owner: Filters;
|
private readonly owner: Filters;
|
||||||
|
|
||||||
public readonly id: any;
|
public readonly id: string | symbol;
|
||||||
|
|
||||||
private readonly raw: any;
|
private readonly raw: RawFilter;
|
||||||
|
|
||||||
private _label: string;
|
private _label: string;
|
||||||
|
|
||||||
private _reg: Matcher;
|
private _reg: Matcher;
|
||||||
|
|
||||||
constructor(owner: Filters, id: any, raw: any) {
|
constructor(owner: Filters, id: string | symbol, raw: RawFilter) {
|
||||||
if (!owner || !id || !raw) {
|
if (!owner || !id || !raw) {
|
||||||
throw new Error("null argument");
|
throw new Error("null argument");
|
||||||
}
|
}
|
||||||
@ -204,9 +218,11 @@ export class Filter {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._label = this.raw.label;
|
this._label = this.raw.label;
|
||||||
if (this.id !== FAST && this.id.startsWith("deffilter-") &&
|
if (typeof this.raw.isOverridden !== "undefined" &&
|
||||||
!this.raw.isOverridden("label")) {
|
typeof this.id === "string") {
|
||||||
this._label = _(this.id) || this._label;
|
if (this.id.startsWith("deffilter-") && !this.raw.isOverridden("label")) {
|
||||||
|
this._label = _(this.id) || this._label;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._reg = Matcher.fromExpression(this.expr);
|
this._reg = Matcher.fromExpression(this.expr);
|
||||||
Object.seal(this);
|
Object.seal(this);
|
||||||
@ -282,7 +298,7 @@ export class Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reset() {
|
async reset() {
|
||||||
if (this.raw.custom) {
|
if (!this.raw.reset) {
|
||||||
throw Error("Cannot reset non-default filter");
|
throw Error("Cannot reset non-default filter");
|
||||||
}
|
}
|
||||||
this.raw.reset();
|
this.raw.reset();
|
||||||
@ -292,7 +308,10 @@ export class Filter {
|
|||||||
|
|
||||||
async "delete"() {
|
async "delete"() {
|
||||||
if (!this.raw.custom) {
|
if (!this.raw.custom) {
|
||||||
throw Error("Cannot delete default filter");
|
throw new Error("Cannot delete default filter");
|
||||||
|
}
|
||||||
|
if (typeof this.id !== "string") {
|
||||||
|
throw new Error("Cannot delete symbolized");
|
||||||
}
|
}
|
||||||
await this.owner.delete(this.id);
|
await this.owner.delete(this.id);
|
||||||
}
|
}
|
||||||
@ -301,7 +320,7 @@ export class Filter {
|
|||||||
return this._reg.match(str);
|
return this._reg.match(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
matchItem(item: any) {
|
matchItem(item: BaseItem) {
|
||||||
return this._reg.matchItem(item);
|
return this._reg.matchItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,8 +335,7 @@ class FastFilter extends Filter {
|
|||||||
throw new Error("Invalid fast filter value");
|
throw new Error("Invalid fast filter value");
|
||||||
}
|
}
|
||||||
super(owner, FAST, {
|
super(owner, FAST, {
|
||||||
id: FAST,
|
label: "fast",
|
||||||
label: FAST,
|
|
||||||
type: TYPE_ALL,
|
type: TYPE_ALL,
|
||||||
active: true,
|
active: true,
|
||||||
expr: value,
|
expr: value,
|
||||||
@ -409,11 +427,11 @@ class Filters extends EventEmitter {
|
|||||||
await this.save();
|
await this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
"get"(id: any) {
|
"get"(id: string | symbol) {
|
||||||
return this.filters.find(e => e.id === id);
|
return this.filters.find(e => e.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async "delete"(id: any) {
|
async "delete"(id: string) {
|
||||||
const idx = this.filters.findIndex(e => e.id === id);
|
const idx = this.filters.findIndex(e => e.id === id);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
return;
|
return;
|
||||||
@ -517,7 +535,7 @@ class Filters extends EventEmitter {
|
|||||||
this.regenerate();
|
this.regenerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
async filterItemsByType(items: any[], type: number) {
|
async filterItemsByType(items: BaseItem[], type: number) {
|
||||||
const matcher = this.typeMatchers.get(type);
|
const matcher = this.typeMatchers.get(type);
|
||||||
const fast = await this.getFastFilter();
|
const fast = await this.getFastFilter();
|
||||||
return items.filter(function(item) {
|
return items.filter(function(item) {
|
||||||
@ -544,12 +562,14 @@ class Filters extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _filters: any;
|
let _filters: Filters;
|
||||||
|
let _loader: Promise<void>;
|
||||||
|
|
||||||
export async function filters(): Promise<Filters> {
|
export async function filters(): Promise<Filters> {
|
||||||
if (!_filters) {
|
if (!_loader) {
|
||||||
_filters = new Filters();
|
_filters = new Filters();
|
||||||
await _filters.load();
|
_loader = _filters.load();
|
||||||
}
|
}
|
||||||
|
await _loader;
|
||||||
return _filters;
|
return _filters;
|
||||||
}
|
}
|
||||||
|
24
lib/item.ts
24
lib/item.ts
@ -4,18 +4,32 @@
|
|||||||
import { ALLOWED_SCHEMES } from "./constants";
|
import { ALLOWED_SCHEMES } from "./constants";
|
||||||
import { TRANSFERABLE_PROPERTIES } from "./constants";
|
import { TRANSFERABLE_PROPERTIES } from "./constants";
|
||||||
|
|
||||||
|
export interface BaseItem {
|
||||||
|
url: string;
|
||||||
|
usable: string;
|
||||||
|
referrer?: string;
|
||||||
|
usableReferrer?: string;
|
||||||
|
description?: string;
|
||||||
|
title?: string;
|
||||||
|
fileName?: string;
|
||||||
|
batch?: number;
|
||||||
|
idx: number;
|
||||||
|
mask?: string;
|
||||||
|
startDate?: number;
|
||||||
|
private?: boolean;
|
||||||
|
postData?: string;
|
||||||
|
paused?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const OPTIONPROPS = Object.freeze([
|
const OPTIONPROPS = Object.freeze([
|
||||||
"referrer", "usableReferrer",
|
"referrer", "usableReferrer",
|
||||||
"description", "title",
|
"description", "title",
|
||||||
"fileName",
|
"fileName",
|
||||||
"batch", "idx",
|
"batch", "idx",
|
||||||
"mask",
|
"mask",
|
||||||
"fromMetalink",
|
|
||||||
"startDate",
|
"startDate",
|
||||||
"hashes",
|
|
||||||
"private",
|
"private",
|
||||||
"postData",
|
"postData",
|
||||||
"cleanRequest",
|
|
||||||
"paused"
|
"paused"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -34,7 +48,7 @@ function maybeAssign(options: any, what: any) {
|
|||||||
this[what] = val;
|
this[what] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Item {
|
export class Item implements BaseItem {
|
||||||
public url: string;
|
public url: string;
|
||||||
|
|
||||||
public usable: string;
|
public usable: string;
|
||||||
@ -43,6 +57,8 @@ export class Item {
|
|||||||
|
|
||||||
public usableReferrer: string;
|
public usableReferrer: string;
|
||||||
|
|
||||||
|
public idx: number;
|
||||||
|
|
||||||
constructor(raw: any, options?: any) {
|
constructor(raw: any, options?: any) {
|
||||||
Object.assign(this, raw);
|
Object.assign(this, raw);
|
||||||
OPTIONPROPS.forEach(maybeAssign.bind(this, options || {}));
|
OPTIONPROPS.forEach(maybeAssign.bind(this, options || {}));
|
||||||
|
@ -29,8 +29,6 @@ const SAVEDPROPS = [
|
|||||||
"serverName",
|
"serverName",
|
||||||
// other options
|
// other options
|
||||||
"private",
|
"private",
|
||||||
"fromMetalink",
|
|
||||||
"cleanRequest",
|
|
||||||
// db
|
// db
|
||||||
"manId",
|
"manId",
|
||||||
"dbId",
|
"dbId",
|
||||||
|
@ -10,10 +10,24 @@ import { donate, openPrefs, openUrls } from "./windowutils";
|
|||||||
import { filters, FAST, Filter } from "./filters";
|
import { filters, FAST, Filter } from "./filters";
|
||||||
import { WindowStateTracker } from "./windowstatetracker";
|
import { WindowStateTracker } from "./windowstatetracker";
|
||||||
import { windows } from "./browser";
|
import { windows } from "./browser";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseItem } from "./item";
|
||||||
|
|
||||||
|
interface BaseMatchedItem extends BaseItem {
|
||||||
|
matched?: string | null;
|
||||||
|
prevMatched?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
function computeSelection(filters: any[], items: any[], onlyFast: boolean) {
|
export interface ItemDelta {
|
||||||
let ws = items.map((item: any, idx: number) => {
|
idx: number;
|
||||||
|
matched?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeSelection(
|
||||||
|
filters: Filter[],
|
||||||
|
items: BaseMatchedItem[],
|
||||||
|
onlyFast: boolean): ItemDelta[] {
|
||||||
|
let ws = items.map((item, idx: number) => {
|
||||||
item.idx = idx;
|
item.idx = idx;
|
||||||
const {matched = null} = item;
|
const {matched = null} = item;
|
||||||
item.prevMatched = matched;
|
item.prevMatched = matched;
|
||||||
@ -23,9 +37,15 @@ function computeSelection(filters: any[], items: any[], onlyFast: boolean) {
|
|||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
ws = ws.filter(item => {
|
ws = ws.filter(item => {
|
||||||
if (filter.matchItem(item)) {
|
if (filter.matchItem(item)) {
|
||||||
item.matched = filter.id === FAST ?
|
if (filter.id === FAST) {
|
||||||
"fast" :
|
item.matched = "fast";
|
||||||
(onlyFast ? null : filter.id);
|
}
|
||||||
|
else if (!onlyFast && typeof filter.id === "string") {
|
||||||
|
item.matched = filter.id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.matched = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return !item.matched;
|
return !item.matched;
|
||||||
});
|
});
|
||||||
@ -41,6 +61,9 @@ function computeSelection(filters: any[], items: any[], onlyFast: boolean) {
|
|||||||
function *computeActiveFiltersGen(
|
function *computeActiveFiltersGen(
|
||||||
filters: Filter[], activeOverrides: Map<string, boolean>) {
|
filters: Filter[], activeOverrides: Map<string, boolean>) {
|
||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
|
if (typeof filter.id !== "string") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const override = activeOverrides.get(filter.id);
|
const override = activeOverrides.get(filter.id);
|
||||||
if (typeof override === "boolean") {
|
if (typeof override === "boolean") {
|
||||||
if (override) {
|
if (override) {
|
||||||
@ -59,11 +82,11 @@ function computeActiveFilters(
|
|||||||
return Array.from(computeActiveFiltersGen(filters, activeOverrides));
|
return Array.from(computeActiveFiltersGen(filters, activeOverrides));
|
||||||
}
|
}
|
||||||
|
|
||||||
function filtersToDescs(filters: any[]) {
|
function filtersToDescs(filters: Filter[]) {
|
||||||
return filters.map(f => f.descriptor);
|
return filters.map(f => f.descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function select(links: any[], media: any[]) {
|
export async function select(links: BaseItem[], media: BaseItem[]) {
|
||||||
const fm = await filters();
|
const fm = await filters();
|
||||||
const tracker = new WindowStateTracker("select", {
|
const tracker = new WindowStateTracker("select", {
|
||||||
minWidth: 700,
|
minWidth: 700,
|
||||||
@ -85,7 +108,7 @@ export async function select(links: any[], media: any[]) {
|
|||||||
tracker.track(window.id, port);
|
tracker.track(window.id, port);
|
||||||
|
|
||||||
const overrides = new Map();
|
const overrides = new Map();
|
||||||
let fast: any = null;
|
let fast: Filter | null = null;
|
||||||
let onlyFast: false;
|
let onlyFast: false;
|
||||||
try {
|
try {
|
||||||
fast = await fm.getFastFilter();
|
fast = await fm.getFastFilter();
|
||||||
@ -95,16 +118,16 @@ export async function select(links: any[], media: any[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sendFilters = function(delta = false) {
|
const sendFilters = function(delta = false) {
|
||||||
let {linkFilters, mediaFilters} = fm;
|
const {linkFilters, mediaFilters} = fm;
|
||||||
const alink = computeActiveFilters(linkFilters, overrides);
|
const alink = computeActiveFilters(linkFilters, overrides);
|
||||||
const amedia = computeActiveFilters(mediaFilters, overrides);
|
const amedia = computeActiveFilters(mediaFilters, overrides);
|
||||||
const sactiveFilters = new Set<any>();
|
const sactiveFilters = new Set<any>();
|
||||||
[alink, amedia].forEach(
|
[alink, amedia].forEach(
|
||||||
a => a.forEach(filter => sactiveFilters.add(filter.id)));
|
a => a.forEach(filter => sactiveFilters.add(filter.id)));
|
||||||
const activeFilters = Array.from(sactiveFilters);
|
const activeFilters = Array.from(sactiveFilters);
|
||||||
linkFilters = filtersToDescs(linkFilters);
|
const linkFilterDescs = filtersToDescs(linkFilters);
|
||||||
mediaFilters = filtersToDescs(mediaFilters);
|
const mediaFilterDescs = filtersToDescs(mediaFilters);
|
||||||
port.post("filters", {linkFilters, mediaFilters, activeFilters});
|
port.post("filters", {linkFilterDescs, mediaFilterDescs, activeFilters});
|
||||||
|
|
||||||
if (fast) {
|
if (fast) {
|
||||||
alink.unshift(fast);
|
alink.unshift(fast);
|
||||||
@ -128,9 +151,6 @@ export async function select(links: any[], media: any[]) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
port.on("queue", (msg: any) => {
|
port.on("queue", (msg: any) => {
|
||||||
const selected = new Set<number>(msg.items);
|
|
||||||
const items = (msg.type === "links" ? links : media);
|
|
||||||
msg.items = items.filter((item: any, idx: number) => selected.has(idx));
|
|
||||||
done.resolve(msg);
|
done.resolve(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,7 +195,11 @@ export async function select(links: any[], media: any[]) {
|
|||||||
sendFilters(false);
|
sendFilters(false);
|
||||||
const type = await Prefs.get("last-type", "links");
|
const type = await Prefs.get("last-type", "links");
|
||||||
port.post("items", {type, links, media});
|
port.post("items", {type, links, media});
|
||||||
const result = await done;
|
const {items, options} = await done;
|
||||||
|
const selectedIndexes = new Set<number>(items);
|
||||||
|
const selectedList = (options.type === "links" ? links : media);
|
||||||
|
const selectedItems = selectedList.filter(
|
||||||
|
(item: BaseItem, idx: number) => selectedIndexes.has(idx));
|
||||||
for (const [filter, override] of overrides) {
|
for (const [filter, override] of overrides) {
|
||||||
const f = fm.get(filter);
|
const f = fm.get(filter);
|
||||||
if (f) {
|
if (f) {
|
||||||
@ -183,7 +207,7 @@ export async function select(links: any[], media: any[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fm.save();
|
await fm.save();
|
||||||
return result;
|
return {items: selectedItems, options};
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
fm.off("changed", sendFilters);
|
fm.off("changed", sendFilters);
|
||||||
|
@ -7,8 +7,10 @@ import { WindowStateTracker } from "./windowstatetracker";
|
|||||||
import { Promised, timeout } from "./util";
|
import { Promised, timeout } from "./util";
|
||||||
import { donate } from "./windowutils";
|
import { donate } from "./windowutils";
|
||||||
import { windows } from "./browser";
|
import { windows } from "./browser";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseItem } from "./item";
|
||||||
|
|
||||||
export async function single(item: any) {
|
export async function single(item: BaseItem | null) {
|
||||||
const tracker = new WindowStateTracker("single", {
|
const tracker = new WindowStateTracker("single", {
|
||||||
minWidth: 700,
|
minWidth: 700,
|
||||||
minHeight: 460
|
minHeight: 460
|
||||||
@ -46,7 +48,9 @@ export async function single(item: any) {
|
|||||||
donate();
|
donate();
|
||||||
});
|
});
|
||||||
|
|
||||||
port.post("item", item);
|
if (item) {
|
||||||
|
port.post("item", {item});
|
||||||
|
}
|
||||||
return await done;
|
return await done;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -14,6 +14,8 @@ import {
|
|||||||
} from "./tablesymbols";
|
} from "./tablesymbols";
|
||||||
import { InvalidatedSet, UpdateRecord } from "./tableutil";
|
import { InvalidatedSet, UpdateRecord } from "./tableutil";
|
||||||
import { addClass, clampUInt, IS_MAC } from "./util";
|
import { addClass, clampUInt, IS_MAC } from "./util";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { TableConfig } from "./config";
|
||||||
|
|
||||||
const ROWS_SMALL_UPDATE = 5;
|
const ROWS_SMALL_UPDATE = 5;
|
||||||
const PIXEL_PREC = 5;
|
const PIXEL_PREC = 5;
|
||||||
@ -79,7 +81,7 @@ export class BaseTable extends AbstractTable {
|
|||||||
|
|
||||||
[COLS]: Columns;
|
[COLS]: Columns;
|
||||||
|
|
||||||
constructor(elem: any, config: any, version?: number) {
|
constructor(elem: any, config: TableConfig | null, version?: number) {
|
||||||
config = (config && config.version === version && config) || {};
|
config = (config && config.version === version && config) || {};
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -121,9 +123,9 @@ export class BaseTable extends AbstractTable {
|
|||||||
this.makeDOM(config);
|
this.makeDOM(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeDOM(config: any) {
|
makeDOM(config: TableConfig) {
|
||||||
const configColumns = "columns" in config ? config.columns : null;
|
const configColumns = "columns" in config ? config.columns : null;
|
||||||
const cols = this[COLS] = new Columns(this, configColumns);
|
const cols = this[COLS] = new Columns(this, configColumns || null);
|
||||||
|
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
const thead = document.createElement("div");
|
const thead = document.createElement("div");
|
||||||
@ -241,7 +243,7 @@ export class BaseTable extends AbstractTable {
|
|||||||
return new SelectionRange(firstIdx, lastIdx);
|
return new SelectionRange(firstIdx, lastIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config(): TableConfig {
|
||||||
return {
|
return {
|
||||||
version: this.version,
|
version: this.version,
|
||||||
columns: this.columnConfig
|
columns: this.columnConfig
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
// License: MIT
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
import { TableEvents } from "./tableevents";
|
import { TableEvents } from "./tableevents";
|
||||||
import {addClass, debounce, sum} from "./util";
|
import {addClass, debounce, sum} from "./util";
|
||||||
import {EventEmitter} from "./events";
|
import {EventEmitter} from "./events";
|
||||||
import {APOOL} from "./animationpool";
|
import {APOOL} from "./animationpool";
|
||||||
|
import { ColumnConfig, ColumnConfigs } from "./config";
|
||||||
/* eslint-enable no-unused-vars */
|
|
||||||
|
|
||||||
// License: MIT
|
|
||||||
|
|
||||||
const PIXLIT_WIDTH = 2;
|
const PIXLIT_WIDTH = 2;
|
||||||
const MIN_COL_WIDTH = 16;
|
const MIN_COL_WIDTH = 16;
|
||||||
@ -55,8 +53,7 @@ export class Column extends EventEmitter {
|
|||||||
columns: Columns,
|
columns: Columns,
|
||||||
col: HTMLTableHeaderCellElement,
|
col: HTMLTableHeaderCellElement,
|
||||||
id: number,
|
id: number,
|
||||||
config: any) {
|
config: ColumnConfig | null) {
|
||||||
config = config || {};
|
|
||||||
super();
|
super();
|
||||||
this.columns = columns;
|
this.columns = columns;
|
||||||
this.elem = col;
|
this.elem = col;
|
||||||
@ -89,7 +86,7 @@ export class Column extends EventEmitter {
|
|||||||
|
|
||||||
this.elem.appendChild(containerElem);
|
this.elem.appendChild(containerElem);
|
||||||
|
|
||||||
if ("visible" in config) {
|
if (config) {
|
||||||
this.visible = config.visible;
|
this.visible = config.visible;
|
||||||
}
|
}
|
||||||
this.initWidths(config);
|
this.initWidths(config);
|
||||||
@ -148,18 +145,18 @@ export class Column extends EventEmitter {
|
|||||||
return Math.max(0, this.currentWidth - this.minWidth);
|
return Math.max(0, this.currentWidth - this.minWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config(): ColumnConfig {
|
||||||
return {
|
return {
|
||||||
visible: this.visible,
|
visible: this.visible,
|
||||||
width: this.currentWidth,
|
width: this.currentWidth,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
initWidths(config: any) {
|
initWidths(config: ColumnConfig | null) {
|
||||||
const style = getComputedStyle(this.elem, null);
|
const style = getComputedStyle(this.elem, null);
|
||||||
this.minWidth = toPixel(style.getPropertyValue("min-width"), MIN_COL_WIDTH);
|
this.minWidth = toPixel(style.getPropertyValue("min-width"), MIN_COL_WIDTH);
|
||||||
this.maxWidth = toPixel(style.getPropertyValue("max-width"), 0);
|
this.maxWidth = toPixel(style.getPropertyValue("max-width"), 0);
|
||||||
const width = config.width || this.baseWidth;
|
const width = (config && config.width) || this.baseWidth;
|
||||||
this.setWidth(width);
|
this.setWidth(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +233,7 @@ export class Columns extends EventEmitter {
|
|||||||
|
|
||||||
public visible: Column[];
|
public visible: Column[];
|
||||||
|
|
||||||
constructor(table: any, config: any) {
|
constructor(table: any, config: ColumnConfigs | null) {
|
||||||
config = config || {};
|
config = config || {};
|
||||||
super();
|
super();
|
||||||
this.table = table;
|
this.table = table;
|
||||||
@ -247,7 +244,9 @@ export class Columns extends EventEmitter {
|
|||||||
this.named = new Map<string, Column>();
|
this.named = new Map<string, Column>();
|
||||||
this.cols = Array.from(table.elem.querySelectorAll("th")).
|
this.cols = Array.from(table.elem.querySelectorAll("th")).
|
||||||
map((colEl: HTMLTableHeaderCellElement, colid: number) => {
|
map((colEl: HTMLTableHeaderCellElement, colid: number) => {
|
||||||
const columnConfig = colEl.id in config ? config[colEl.id] : null;
|
const columnConfig = config && colEl.id in config ?
|
||||||
|
config[colEl.id] :
|
||||||
|
null;
|
||||||
const col = new Column(this, colEl, colid, columnConfig);
|
const col = new Column(this, colEl, colid, columnConfig);
|
||||||
col.on("gripmoved", this.gripmoved);
|
col.on("gripmoved", this.gripmoved);
|
||||||
this.named.set(colEl.id, col);
|
this.named.set(colEl.id, col);
|
||||||
@ -261,7 +260,7 @@ export class Columns extends EventEmitter {
|
|||||||
Object.seal(this);
|
Object.seal(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config(): ColumnConfigs {
|
||||||
const rv: any = {};
|
const rv: any = {};
|
||||||
for (const c of this.cols) {
|
for (const c of this.cols) {
|
||||||
rv[c.elem.id] = c.config;
|
rv[c.elem.id] = c.config;
|
||||||
|
13
uikit/lib/config.ts
Normal file
13
uikit/lib/config.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
// License: MIT
|
||||||
|
|
||||||
|
export interface ColumnConfig {
|
||||||
|
visible: boolean;
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
export type ColumnConfigs ={ [name: string]: ColumnConfig };
|
||||||
|
|
||||||
|
export interface TableConfig {
|
||||||
|
version?: number;
|
||||||
|
columns?: ColumnConfigs;
|
||||||
|
}
|
@ -33,6 +33,14 @@ export interface MenuPosition {
|
|||||||
clientY: number;
|
clientY: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MenuOptions {
|
||||||
|
disabled?: string;
|
||||||
|
allowClick?: string;
|
||||||
|
icon?: string;
|
||||||
|
key?: string;
|
||||||
|
autoHide?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class MenuItemBase {
|
export class MenuItemBase {
|
||||||
public readonly owner: ContextMenu;
|
public readonly owner: ContextMenu;
|
||||||
|
|
||||||
@ -44,7 +52,7 @@ export class MenuItemBase {
|
|||||||
|
|
||||||
public readonly key: string;
|
public readonly key: string;
|
||||||
|
|
||||||
public readonly autohide: boolean;
|
public readonly autoHide: boolean;
|
||||||
|
|
||||||
public readonly elem: HTMLLIElement;
|
public readonly elem: HTMLLIElement;
|
||||||
|
|
||||||
@ -54,18 +62,16 @@ export class MenuItemBase {
|
|||||||
|
|
||||||
public readonly keyElem: HTMLSpanElement;
|
public readonly keyElem: HTMLSpanElement;
|
||||||
|
|
||||||
constructor(owner: ContextMenu, id = "", text = "", {
|
constructor(owner: ContextMenu, id = "", text = "", options: MenuOptions) {
|
||||||
key = "", icon = "", autohide = Object()
|
|
||||||
}) {
|
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
id = `contextmenu-${++ids}`;
|
id = `contextmenu-${++ids}`;
|
||||||
}
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.text = text || "";
|
this.text = text || "";
|
||||||
this.icon = icon || "";
|
this.icon = options.icon || "";
|
||||||
this.key = key || "";
|
this.key = options.key || "";
|
||||||
this.autohide = autohide !== "false" && autohide !== false;
|
this.autoHide = options.autoHide !== "false";
|
||||||
|
|
||||||
this.elem = document.createElement("li");
|
this.elem = document.createElement("li");
|
||||||
this.elem.id = this.id;
|
this.elem.id = this.id;
|
||||||
@ -96,13 +102,14 @@ export class MenuItemBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MenuItem extends MenuItemBase {
|
export class MenuItem extends MenuItemBase {
|
||||||
constructor(owner: ContextMenu, id = "", text = "", options: any = {}) {
|
constructor(
|
||||||
|
owner: ContextMenu, id = "", text = "", options: MenuOptions = {}) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
super(owner, id, text, options);
|
super(owner, id, text, options);
|
||||||
this.disabled = !!options.disabled;
|
this.disabled = options.disabled === "true";
|
||||||
this.elem.setAttribute("aria-role", "menuitem");
|
this.elem.setAttribute("aria-role", "menuitem");
|
||||||
this.elem.addEventListener(
|
this.elem.addEventListener(
|
||||||
"click", () => this.owner.emit("clicked", this.id, this.autohide));
|
"click", () => this.owner.emit("clicked", this.id, this.autoHide));
|
||||||
}
|
}
|
||||||
|
|
||||||
get disabled() {
|
get disabled() {
|
||||||
@ -132,7 +139,8 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
|
|
||||||
public readonly expandElem: HTMLSpanElement;
|
public readonly expandElem: HTMLSpanElement;
|
||||||
|
|
||||||
constructor(owner: ContextMenu, id = "", text = "", options: any = {}) {
|
constructor(
|
||||||
|
owner: ContextMenu, id = "", text = "", options: MenuOptions = {}) {
|
||||||
super(owner, id, text, options);
|
super(owner, id, text, options);
|
||||||
this.elem.setAttribute("aria-role", "menuitem");
|
this.elem.setAttribute("aria-role", "menuitem");
|
||||||
this.elem.setAttribute("aria-haspopup", "true");
|
this.elem.setAttribute("aria-haspopup", "true");
|
||||||
@ -145,8 +153,8 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
this.expandElem.textContent = "►";
|
this.expandElem.textContent = "►";
|
||||||
this.elem.appendChild(this.expandElem);
|
this.elem.appendChild(this.expandElem);
|
||||||
this.elem.addEventListener("click", event => {
|
this.elem.addEventListener("click", event => {
|
||||||
if (options.allowClick) {
|
if (options.allowClick === "true") {
|
||||||
this.owner.emit("clicked", this.id, this.autohide);
|
this.owner.emit("clicked", this.id, this.autoHide);
|
||||||
}
|
}
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -160,7 +168,7 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
this.owner.on("showing", () => {
|
this.owner.on("showing", () => {
|
||||||
this.menu.dismiss();
|
this.menu.dismiss();
|
||||||
});
|
});
|
||||||
this.menu.on("clicked", (...args: any) => {
|
this.menu.on("clicked", (...args: any[]) => {
|
||||||
this.owner.emit("clicked", ...args);
|
this.owner.emit("clicked", ...args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -215,7 +223,7 @@ export class SubMenuItem extends MenuItemBase {
|
|||||||
export class ContextMenu extends EventEmitter {
|
export class ContextMenu extends EventEmitter {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
items: any[];
|
items: MenuItemBase[];
|
||||||
|
|
||||||
itemMap: Map<string, MenuItemBase>;
|
itemMap: Map<string, MenuItemBase>;
|
||||||
|
|
||||||
@ -223,7 +231,7 @@ export class ContextMenu extends EventEmitter {
|
|||||||
|
|
||||||
showing: boolean;
|
showing: boolean;
|
||||||
|
|
||||||
_maybeDismiss: any;
|
_maybeDismiss: (this: Window, ev: MouseEvent) => any;
|
||||||
|
|
||||||
constructor(el?: any) {
|
constructor(el?: any) {
|
||||||
super();
|
super();
|
||||||
@ -348,10 +356,12 @@ export class ContextMenu extends EventEmitter {
|
|||||||
return this.itemMap.get(id);
|
return this.itemMap.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
add(item: MenuItemBase, before: any = "") {
|
add(item: MenuItemBase, before: MenuItemBase | string = "") {
|
||||||
let idx = this.items.length;
|
let idx = this.items.length;
|
||||||
if (before) {
|
if (before) {
|
||||||
before = before.id || before;
|
if (typeof before !== "string") {
|
||||||
|
before = before.id;
|
||||||
|
}
|
||||||
const ni = this.items.findIndex(i => i.id === before);
|
const ni = this.items.findIndex(i => i.id === before);
|
||||||
if (ni >= 0) {
|
if (ni >= 0) {
|
||||||
idx = ni;
|
idx = ni;
|
||||||
@ -366,8 +376,8 @@ export class ContextMenu extends EventEmitter {
|
|||||||
this.itemMap.set(item.id, item);
|
this.itemMap.set(item.id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(item: any) {
|
remove(item: MenuItemBase | string) {
|
||||||
const id = item.id || item;
|
const id = typeof item === "string" ? item : item.id;
|
||||||
const idx = this.items.findIndex(i => i.id === id);
|
const idx = this.items.findIndex(i => i.id === id);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
this.items.splice(idx, 1);
|
this.items.splice(idx, 1);
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
interface ModalButton {
|
export interface ModalButton {
|
||||||
title: string;
|
title: string;
|
||||||
value: string;
|
value: string;
|
||||||
default?: boolean;
|
default?: boolean;
|
||||||
dismiss?: boolean;
|
dismiss?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Promised {
|
||||||
|
resolve: Function;
|
||||||
|
reject: Function;
|
||||||
|
}
|
||||||
|
|
||||||
export default abstract class ModalDialog {
|
export default abstract class ModalDialog {
|
||||||
private _showing: any;
|
private _showing: Promised | null;
|
||||||
|
|
||||||
private _dismiss: HTMLButtonElement | null;
|
private _dismiss: HTMLButtonElement | null;
|
||||||
|
|
||||||
@ -107,7 +112,10 @@ export default abstract class ModalDialog {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
done(button: any) {
|
done(button: ModalButton) {
|
||||||
|
if (!this._showing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const value = this.convertValue(button.value);
|
const value = this.convertValue(button.value);
|
||||||
if (button.dismiss) {
|
if (button.dismiss) {
|
||||||
this._showing.reject(new Error(value));
|
this._showing.reject(new Error(value));
|
||||||
@ -130,7 +138,7 @@ export default abstract class ModalDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async show() {
|
async show(): Promise<any> {
|
||||||
if (this._showing) {
|
if (this._showing) {
|
||||||
throw new Error("Double show");
|
throw new Error("Double show");
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class Hover {
|
|||||||
|
|
||||||
private hovering: boolean;
|
private hovering: boolean;
|
||||||
|
|
||||||
private timer: any;
|
private timer: number | null;
|
||||||
|
|
||||||
constructor(row: Row) {
|
constructor(row: Row) {
|
||||||
this.row = row;
|
this.row = row;
|
||||||
@ -62,7 +62,7 @@ class Hover {
|
|||||||
this.elem.addEventListener("mousemove", this.onmove, {passive: true});
|
this.elem.addEventListener("mousemove", this.onmove, {passive: true});
|
||||||
this.x = evt.clientX;
|
this.x = evt.clientX;
|
||||||
this.y = evt.clientY;
|
this.y = evt.clientY;
|
||||||
this.timer = setTimeout(this.onhover, HOVER_TIME);
|
this.timer = window.setTimeout(this.onhover, HOVER_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
onleave() {
|
onleave() {
|
||||||
@ -93,7 +93,7 @@ class Hover {
|
|||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
}
|
}
|
||||||
this.timer = setTimeout(this.onhover, HOVER_TIME);
|
this.timer = window.setTimeout(this.onhover, HOVER_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ import {Row} from "./row";
|
|||||||
import {APOOL} from "./animationpool";
|
import {APOOL} from "./animationpool";
|
||||||
import {COLS, ROWCACHE, VISIBLE} from "./tablesymbols";
|
import {COLS, ROWCACHE, VISIBLE} from "./tablesymbols";
|
||||||
import {ContextMenu, MenuItem} from "./contextmenu";
|
import {ContextMenu, MenuItem} from "./contextmenu";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { TableConfig } from "./config";
|
||||||
|
|
||||||
const RESIZE_DEBOUNCE = 500;
|
const RESIZE_DEBOUNCE = 500;
|
||||||
const SCROLL_DEBOUNCE = 250;
|
const SCROLL_DEBOUNCE = 250;
|
||||||
@ -19,7 +21,7 @@ const SCROLL_DEBOUNCE = 250;
|
|||||||
export class TableEvents extends BaseTable {
|
export class TableEvents extends BaseTable {
|
||||||
private oldVisibleTop: number;
|
private oldVisibleTop: number;
|
||||||
|
|
||||||
constructor(elem: any, config?: any, version?: number) {
|
constructor(elem: any, config: TableConfig | null, version?: number) {
|
||||||
super(elem, config, version);
|
super(elem, config, version);
|
||||||
const {selection} = this;
|
const {selection} = this;
|
||||||
selection.on("selection-added", this.selectionAdded.bind(this));
|
selection.on("selection-added", this.selectionAdded.bind(this));
|
||||||
@ -172,7 +174,7 @@ export class TableEvents extends BaseTable {
|
|||||||
ctx,
|
ctx,
|
||||||
id,
|
id,
|
||||||
col.spanElem.textContent || "",
|
col.spanElem.textContent || "",
|
||||||
{autohide: "false"});
|
{autoHide: "false"});
|
||||||
ctx.add(item);
|
ctx.add(item);
|
||||||
item.iconElem.textContent = col.visible ? "✓" : " ";
|
item.iconElem.textContent = col.visible ? "✓" : " ";
|
||||||
ctx.on(id, async () => {
|
ctx.on(id, async () => {
|
||||||
|
@ -8,6 +8,8 @@ import { Row } from "./row";
|
|||||||
import {APOOL} from "./animationpool";
|
import {APOOL} from "./animationpool";
|
||||||
import {ROW_CACHE_SIZE, ROW_REUSE_SIZE} from "./constants";
|
import {ROW_CACHE_SIZE, ROW_REUSE_SIZE} from "./constants";
|
||||||
import {clampUInt} from "./util";
|
import {clampUInt} from "./util";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseTable } from "./basetable";
|
||||||
|
|
||||||
|
|
||||||
export class InvalidatedSet<T> extends Set<T> {
|
export class InvalidatedSet<T> extends Set<T> {
|
||||||
@ -70,7 +72,7 @@ export class UpdateRecord {
|
|||||||
|
|
||||||
bottom: number;
|
bottom: number;
|
||||||
|
|
||||||
constructor(table: any, cols: Column[]) {
|
constructor(table: BaseTable, cols: Column[]) {
|
||||||
this.rowCount = table.rowCount;
|
this.rowCount = table.rowCount;
|
||||||
this.scrollTop = table.visibleTop;
|
this.scrollTop = table.visibleTop;
|
||||||
this.rowHeight = table.rowHeight;
|
this.rowHeight = table.rowHeight;
|
||||||
|
@ -13,14 +13,21 @@ export function addClass(elem: HTMLElement, ...cls: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Timer {
|
||||||
|
args: any[];
|
||||||
|
}
|
||||||
|
|
||||||
export function debounce(fn: Function, to: number) {
|
export function debounce(fn: Function, to: number) {
|
||||||
let timer: any;
|
let timer: Timer | null;
|
||||||
return function(...args: any[]) {
|
return function(...args: any[]) {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
timer.args = args;
|
timer.args = args;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
|
if (!timer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const {args} = timer;
|
const {args} = timer;
|
||||||
timer = null;
|
timer = null;
|
||||||
try {
|
try {
|
||||||
@ -38,7 +45,7 @@ function sumreduce(p: number, c: number) {
|
|||||||
return p + c;
|
return p + c;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sum(arr: any[]) {
|
export function sum(arr: number[]) {
|
||||||
return arr.reduce(sumreduce, 0);
|
return arr.reduce(sumreduce, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ export class Dropdown extends EventEmitter {
|
|||||||
|
|
||||||
select: HTMLSelectElement;
|
select: HTMLSelectElement;
|
||||||
|
|
||||||
constructor(el: string, options: any[] = []) {
|
constructor(el: string, options: string[] = []) {
|
||||||
super();
|
super();
|
||||||
let input = document.querySelector(el);
|
let input = document.querySelector(el);
|
||||||
if (!input || !input.parentElement) {
|
if (!input || !input.parentElement) {
|
||||||
|
@ -128,8 +128,8 @@
|
|||||||
<template id="menufilter-template">
|
<template id="menufilter-template">
|
||||||
<ul>
|
<ul>
|
||||||
<li id="ctx-menufilter-seperator">-</li>
|
<li id="ctx-menufilter-seperator">-</li>
|
||||||
<li id="ctx-menufilter-invert" data-autohide="false">Invert</li>
|
<li id="ctx-menufilter-invert" data-autoHide="false">Invert</li>
|
||||||
<li id="ctx-menufilter-clear" data-autohide="false">Clear</li>
|
<li id="ctx-menufilter-clear" data-autoHide="false">Clear</li>
|
||||||
<li>-</li>
|
<li>-</li>
|
||||||
<li id="ctx-menufilter-sort-ascending" data-icon="icon-sort-asc">Sort ascending</li>
|
<li id="ctx-menufilter-sort-ascending" data-icon="icon-sort-asc">Sort ascending</li>
|
||||||
<li id="ctx-menufilter-sort-descending" data-icon="icon-sort-desc">Sort descending</li>
|
<li id="ctx-menufilter-sort-descending" data-icon="icon-sort-desc">Sort descending</li>
|
||||||
|
@ -41,7 +41,7 @@ export class TextFilter extends ItemFilter {
|
|||||||
|
|
||||||
private box: HTMLInputElement;
|
private box: HTMLInputElement;
|
||||||
|
|
||||||
private timer: any;
|
private timer: number | null;
|
||||||
|
|
||||||
private current: string;
|
private current: string;
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export class TextFilter extends ItemFilter {
|
|||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.timer = setTimeout(() => this.update(), TIMEOUT_SEARCH);
|
this.timer = window.setTimeout(() => this.update(), TIMEOUT_SEARCH);
|
||||||
});
|
});
|
||||||
this.box.addEventListener("keydown", e => {
|
this.box.addEventListener("keydown", e => {
|
||||||
if (e.key !== "Escape") {
|
if (e.key !== "Escape") {
|
||||||
@ -152,7 +152,7 @@ export class MenuFilter extends ItemFilter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const item = new MenuItem(this.menu, id, text, {
|
const item = new MenuItem(this.menu, id, text, {
|
||||||
autohide: false,
|
autoHide: "false",
|
||||||
});
|
});
|
||||||
item.iconElem.textContent = checked ? "✓" : "";
|
item.iconElem.textContent = checked ? "✓" : "";
|
||||||
this.items.set(id, {item, callback});
|
this.items.set(id, {item, callback});
|
||||||
@ -202,16 +202,24 @@ export class MenuFilter extends ItemFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChainedFunction = (item: DownloadItem) => boolean;
|
||||||
|
|
||||||
|
interface ChainedItem {
|
||||||
|
text: string;
|
||||||
|
fn: ChainedFunction;
|
||||||
|
}
|
||||||
|
|
||||||
class FixedMenuFilter extends MenuFilter {
|
class FixedMenuFilter extends MenuFilter {
|
||||||
collection: FilteredCollection;
|
collection: FilteredCollection;
|
||||||
|
|
||||||
selected: Set<any>;
|
selected: Set<ChainedItem>;
|
||||||
|
|
||||||
fixed: Set<any>;
|
fixed: Set<ChainedItem>;
|
||||||
|
|
||||||
chain: any;
|
chain: ChainedFunction | null;
|
||||||
|
|
||||||
constructor(id: string, collection: FilteredCollection, items: any[]) {
|
constructor(
|
||||||
|
id: string, collection: FilteredCollection, items: ChainedItem[]) {
|
||||||
super(id);
|
super(id);
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
this.selected = new Set();
|
this.selected = new Set();
|
||||||
@ -226,7 +234,7 @@ class FixedMenuFilter extends MenuFilter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(item: MenuItem) {
|
toggle(item: ChainedItem) {
|
||||||
if (this.selected.has(item)) {
|
if (this.selected.has(item)) {
|
||||||
this.selected.delete(item);
|
this.selected.delete(item);
|
||||||
}
|
}
|
||||||
@ -241,14 +249,18 @@ class FixedMenuFilter extends MenuFilter {
|
|||||||
this.collection.removeFilter(this);
|
this.collection.removeFilter(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.chain = Array.from(this.selected).reduce((prev, curr) => {
|
this.chain = null;
|
||||||
return (item: DownloadItem) => curr.fn(item) || (prev && prev(item));
|
this.chain = Array.from(this.selected).reduce(
|
||||||
}, null);
|
(prev: ChainedFunction | null, curr) => {
|
||||||
|
return (item: DownloadItem) => {
|
||||||
|
return curr.fn(item) || (prev !== null && prev(item));
|
||||||
|
};
|
||||||
|
}, this.chain);
|
||||||
this.collection.addFilter(this);
|
this.collection.addFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
allow(item: DownloadItem) {
|
allow(item: DownloadItem) {
|
||||||
return this.chain(item);
|
return this.chain !== null && this.chain(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
@ -341,7 +353,7 @@ export class UrlMenuFilter extends MenuFilter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleRegularFilter(filter: any) {
|
toggleRegularFilter(filter: Filter) {
|
||||||
if (this.filters.has(filter)) {
|
if (this.filters.has(filter)) {
|
||||||
this.filters.delete(filter);
|
this.filters.delete(filter);
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,18 @@
|
|||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
import { EventEmitter } from "../../lib/events";
|
import { EventEmitter } from "../../lib/events";
|
||||||
import { runtime } from "../../lib/browser";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { runtime, RawPort } from "../../lib/browser";
|
||||||
|
|
||||||
const PORT = new class Port extends EventEmitter {
|
const PORT = new class Port extends EventEmitter {
|
||||||
port: any;
|
port: RawPort | null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.port = runtime.connect(null, { name: "manager" });
|
this.port = runtime.connect(null, { name: "manager" });
|
||||||
|
if (!this.port) {
|
||||||
|
throw new Error("Could not connect");
|
||||||
|
}
|
||||||
this.port.onMessage.addListener((msg: any) => {
|
this.port.onMessage.addListener((msg: any) => {
|
||||||
if (typeof msg === "string") {
|
if (typeof msg === "string") {
|
||||||
this.emit(msg);
|
this.emit(msg);
|
||||||
@ -23,10 +27,16 @@ const PORT = new class Port extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post(msg: string, data?: any) {
|
post(msg: string, data?: any) {
|
||||||
|
if (!this.port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.port.postMessage(Object.assign({msg}, data));
|
this.port.postMessage(Object.assign({msg}, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect() {
|
disconnect() {
|
||||||
|
if (!this.port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.port.disconnect();
|
this.port.disconnect();
|
||||||
this.port = null;
|
this.port = null;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ 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";
|
import { $ } from "../winutil";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { TableConfig } from "../../uikit/lib/config";
|
||||||
|
|
||||||
const TREE_CONFIG_VERSION = 2;
|
const TREE_CONFIG_VERSION = 2;
|
||||||
const RUNNING_TIMEOUT = 1000;
|
const RUNNING_TIMEOUT = 1000;
|
||||||
@ -311,9 +313,9 @@ export class DownloadTable extends VirtualTable {
|
|||||||
|
|
||||||
public readonly showUrls: ShowUrlsWatcher;
|
public readonly showUrls: ShowUrlsWatcher;
|
||||||
|
|
||||||
private runningTimer: any;
|
private runningTimer: number | null;
|
||||||
|
|
||||||
private sizesTimer: any;
|
private sizesTimer: number | null;
|
||||||
|
|
||||||
private readonly globalStats: Stats;
|
private readonly globalStats: Stats;
|
||||||
|
|
||||||
@ -329,7 +331,7 @@ export class DownloadTable extends VirtualTable {
|
|||||||
|
|
||||||
private readonly openFileAction: Broadcaster;
|
private readonly openFileAction: Broadcaster;
|
||||||
|
|
||||||
private readonly openDirectoryAction: any;
|
private readonly openDirectoryAction: Broadcaster;
|
||||||
|
|
||||||
private readonly moveTopAction: Broadcaster;
|
private readonly moveTopAction: Broadcaster;
|
||||||
|
|
||||||
@ -339,11 +341,11 @@ export class DownloadTable extends VirtualTable {
|
|||||||
|
|
||||||
private readonly moveBottomAction: Broadcaster;
|
private readonly moveBottomAction: Broadcaster;
|
||||||
|
|
||||||
private readonly disableSet: Set<any>;
|
private readonly disableSet: Set<Broadcaster>;
|
||||||
|
|
||||||
private tooltip: Tooltip | null;
|
private tooltip: Tooltip | null;
|
||||||
|
|
||||||
constructor(treeConfig: any) {
|
constructor(treeConfig: TableConfig | null) {
|
||||||
super("#items", treeConfig, TREE_CONFIG_VERSION);
|
super("#items", treeConfig, TREE_CONFIG_VERSION);
|
||||||
|
|
||||||
TEXT_SIZE_UNKNOWM = _("size-unknown");
|
TEXT_SIZE_UNKNOWM = _("size-unknown");
|
||||||
@ -621,7 +623,7 @@ export class DownloadTable extends VirtualTable {
|
|||||||
filter(e => e.startsWith(prefix)).
|
filter(e => e.startsWith(prefix)).
|
||||||
forEach(e => rem.remove(e));
|
forEach(e => rem.remove(e));
|
||||||
for (const filt of filts.all) {
|
for (const filt of filts.all) {
|
||||||
if (filt.id === "deffilter-all") {
|
if (typeof filt.id !== "string" || filt.id === "deffilter-all") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const mi = new MenuItem(rem, `${prefix}-${filt.id}`, filt.label, {
|
const mi = new MenuItem(rem, `${prefix}-${filt.id}`, filt.label, {
|
||||||
@ -918,7 +920,7 @@ export class DownloadTable extends VirtualTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filter = (await filters()).get(id);
|
const filter = (await filters()).get(id);
|
||||||
if (!filter) {
|
if (!filter || typeof filter.id !== "string") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await new RemovalModalDialog(
|
await new RemovalModalDialog(
|
||||||
@ -966,7 +968,7 @@ export class DownloadTable extends VirtualTable {
|
|||||||
switch (oldState) {
|
switch (oldState) {
|
||||||
case DownloadState.RUNNING:
|
case DownloadState.RUNNING:
|
||||||
this.running.delete(item);
|
this.running.delete(item);
|
||||||
if (!this.running.size && this.runningTimer) {
|
if (!this.running.size && this.runningTimer && this.sizesTimer) {
|
||||||
clearInterval(this.runningTimer);
|
clearInterval(this.runningTimer);
|
||||||
this.runningTimer = null;
|
this.runningTimer = null;
|
||||||
clearInterval(this.sizesTimer);
|
clearInterval(this.sizesTimer);
|
||||||
@ -983,9 +985,9 @@ export class DownloadTable extends VirtualTable {
|
|||||||
case DownloadState.RUNNING:
|
case DownloadState.RUNNING:
|
||||||
this.running.add(item);
|
this.running.add(item);
|
||||||
if (!this.runningTimer) {
|
if (!this.runningTimer) {
|
||||||
this.runningTimer = setInterval(
|
this.runningTimer = window.setInterval(
|
||||||
this.updateRunning.bind(this), RUNNING_TIMEOUT);
|
this.updateRunning.bind(this), RUNNING_TIMEOUT);
|
||||||
this.sizesTimer = setInterval(
|
this.sizesTimer = window.setInterval(
|
||||||
this.updateSizes.bind(this), SIZES_TIMEOUT);
|
this.updateSizes.bind(this), SIZES_TIMEOUT);
|
||||||
this.updateRunning();
|
this.updateRunning();
|
||||||
this.updateSizes();
|
this.updateSizes();
|
||||||
|
@ -6,7 +6,8 @@ import { Prefs, PrefWatcher } from "../lib/prefs";
|
|||||||
import { hostToDomain } from "../lib/util";
|
import { hostToDomain } from "../lib/util";
|
||||||
import { filters } from "../lib/filters";
|
import { filters } from "../lib/filters";
|
||||||
import {Limits} from "../lib/manager/limits";
|
import {Limits} from "../lib/manager/limits";
|
||||||
import ModalDialog from "../uikit/lib/modal";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import ModalDialog, { ModalButton } from "../uikit/lib/modal";
|
||||||
import { TYPE_LINK, TYPE_MEDIA } from "../lib/constants";
|
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";
|
||||||
@ -138,7 +139,7 @@ class CreateFilterDialog extends ModalDialog {
|
|||||||
this.label.focus();
|
this.label.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
done(b: any) {
|
done(b: ModalButton) {
|
||||||
if (!b || !b.default) {
|
if (!b || !b.default) {
|
||||||
return super.done(b);
|
return super.done(b);
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ class FiltersUI extends VirtualTable {
|
|||||||
ignoreNext: boolean;
|
ignoreNext: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("#filters");
|
super("#filters", null);
|
||||||
this.filters = [];
|
this.filters = [];
|
||||||
this.icons = new Icons($("#icons"));
|
this.icons = new Icons($("#icons"));
|
||||||
const filter: any = null;
|
const filter: any = null;
|
||||||
@ -403,7 +404,7 @@ class LimitsUI extends VirtualTable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("#limits");
|
super("#limits", null);
|
||||||
this.limits = [];
|
this.limits = [];
|
||||||
Limits.on("changed", () => {
|
Limits.on("changed", () => {
|
||||||
this.limits = Array.from(Limits);
|
this.limits = Array.from(Limits);
|
||||||
|
@ -15,10 +15,17 @@ import { Icons } from "./icons";
|
|||||||
import { sort, naturalCaseCompare } from "../lib/sorting";
|
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";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { runtime, RawPort } from "../lib/browser";
|
||||||
import { $ } from "./winutil";
|
import { $ } from "./winutil";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { BaseItem } from "../lib/item";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { ItemDelta } from "../lib/select";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { TableConfig } from "../uikit/lib/config";
|
||||||
|
|
||||||
const PORT = runtime.connect(null, { name: "select" });
|
const PORT: RawPort = runtime.connect(null, { name: "select" });
|
||||||
|
|
||||||
const TREE_CONFIG_VERSION = 1;
|
const TREE_CONFIG_VERSION = 1;
|
||||||
|
|
||||||
@ -37,7 +44,11 @@ let Mask: Dropdown;
|
|||||||
let FastFilter: Dropdown;
|
let FastFilter: Dropdown;
|
||||||
|
|
||||||
|
|
||||||
type DELTAS = {deltaLinks: any[]; deltaMedia: any[]};
|
type DELTAS = {deltaLinks: ItemDelta[]; deltaMedia: ItemDelta[]};
|
||||||
|
|
||||||
|
interface BaseMatchedItem extends BaseItem {
|
||||||
|
matched?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
function cleaErrors() {
|
function cleaErrors() {
|
||||||
const not = $("#notification");
|
const not = $("#notification");
|
||||||
@ -46,7 +57,7 @@ function cleaErrors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function matched(item: any) {
|
function matched(item: BaseMatchedItem) {
|
||||||
return item && item.matched && item.matched !== "unmanual";
|
return item && item.matched && item.matched !== "unmanual";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,18 +124,20 @@ class CheckClasser extends Map<string, string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KeyFn = (item: BaseMatchedItem) => any;
|
||||||
|
|
||||||
class SelectionTable extends VirtualTable {
|
class SelectionTable extends VirtualTable {
|
||||||
checkClasser: CheckClasser;
|
checkClasser: CheckClasser;
|
||||||
|
|
||||||
icons: Icons;
|
icons: Icons;
|
||||||
|
|
||||||
links: any[];
|
links: BaseMatchedItem[];
|
||||||
|
|
||||||
media: any[];
|
media: BaseMatchedItem[];
|
||||||
|
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
items: any[];
|
items: BaseMatchedItem[];
|
||||||
|
|
||||||
status: HTMLElement;
|
status: HTMLElement;
|
||||||
|
|
||||||
@ -142,9 +155,11 @@ class SelectionTable extends VirtualTable {
|
|||||||
|
|
||||||
sortasc: boolean;
|
sortasc: boolean;
|
||||||
|
|
||||||
keyfns: Map<string, (item: any) => any>;
|
keyfns: Map<string, KeyFn>;
|
||||||
|
|
||||||
constructor(treeConfig: any, type: string, links: any[], media: any[]) {
|
constructor(
|
||||||
|
treeConfig: TableConfig | null, type: string,
|
||||||
|
links: BaseMatchedItem[], media: BaseMatchedItem[]) {
|
||||||
if (type === "links" && !links.length) {
|
if (type === "links" && !links.length) {
|
||||||
type = "media";
|
type = "media";
|
||||||
}
|
}
|
||||||
@ -187,7 +202,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
|
|
||||||
this.sortcol = null;
|
this.sortcol = null;
|
||||||
this.sortasc = true;
|
this.sortasc = true;
|
||||||
this.keyfns = new Map([
|
this.keyfns = new Map<string, KeyFn>([
|
||||||
["colDownload", item => item.usable],
|
["colDownload", item => item.usable],
|
||||||
["colTitle", item => [item.title, item.usable]],
|
["colTitle", item => [item.title, item.usable]],
|
||||||
["colDescription", item => [item.description, item.usable]],
|
["colDescription", item => [item.description, item.usable]],
|
||||||
@ -270,7 +285,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
oldmask = "";
|
oldmask = "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
oldmask = m;
|
oldmask = m || oldmask;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Keys.suppressed = true;
|
Keys.suppressed = true;
|
||||||
@ -374,7 +389,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
applyDeltaTo(delta: any[], items: any[]) {
|
applyDeltaTo(delta: ItemDelta[], items: BaseMatchedItem[]) {
|
||||||
const active = items === this.items;
|
const active = items === this.items;
|
||||||
for (const d of delta) {
|
for (const d of delta) {
|
||||||
const {idx = -1, matched = null} = d;
|
const {idx = -1, matched = null} = d;
|
||||||
@ -432,7 +447,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
|
|
||||||
getRowClasses(rowid: number) {
|
getRowClasses(rowid: number) {
|
||||||
const item = this.items[rowid];
|
const item = this.items[rowid];
|
||||||
if (!item || !matched(item)) {
|
if (!item || !matched(item) || !item.matched) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return ["filtered", this.checkClasser.get(item.matched)];
|
return ["filtered", this.checkClasser.get(item.matched)];
|
||||||
@ -467,7 +482,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getText(prop: string, idx: number) {
|
getText(prop: string, idx: number) {
|
||||||
const item = this.items[idx];
|
const item: any = this.items[idx];
|
||||||
if (!item || !(prop in item) || !item[prop]) {
|
if (!item || !(prop in item) || !item[prop]) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -506,7 +521,7 @@ class SelectionTable extends VirtualTable {
|
|||||||
|
|
||||||
getCellCheck(rowid: number, colid: number) {
|
getCellCheck(rowid: number, colid: number) {
|
||||||
if (colid === COL_CHECK) {
|
if (colid === COL_CHECK) {
|
||||||
return matched(this.items[rowid]);
|
return !!matched(this.items[rowid]);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -549,13 +564,15 @@ async function download(paused = false) {
|
|||||||
}
|
}
|
||||||
PORT.postMessage({
|
PORT.postMessage({
|
||||||
msg: "queue",
|
msg: "queue",
|
||||||
type: Table.type,
|
|
||||||
items,
|
items,
|
||||||
paused,
|
options: {
|
||||||
mask,
|
type: Table.type,
|
||||||
maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
|
paused,
|
||||||
fast: FastFilter.value,
|
mask,
|
||||||
fastOnce: $<HTMLInputElement>("#fastOnceCheck").checked,
|
maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
|
||||||
|
fast: FastFilter.value,
|
||||||
|
fastOnce: $<HTMLInputElement>("#fastOnceCheck").checked,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
@ -567,17 +584,17 @@ async function download(paused = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
active: any;
|
active: boolean;
|
||||||
|
|
||||||
container: any;
|
|
||||||
|
|
||||||
elem: HTMLLabelElement;
|
|
||||||
|
|
||||||
label: any;
|
|
||||||
|
|
||||||
checkElem: HTMLInputElement;
|
checkElem: HTMLInputElement;
|
||||||
|
|
||||||
id: any;
|
container: HTMLElement;
|
||||||
|
|
||||||
|
elem: HTMLLabelElement;
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
label: string;
|
||||||
|
|
||||||
constructor(container: HTMLElement, raw: any, active = false) {
|
constructor(container: HTMLElement, raw: any, active = false) {
|
||||||
Object.assign(this, raw);
|
Object.assign(this, raw);
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
import ModalDialog from "../uikit/lib/modal";
|
import ModalDialog from "../uikit/lib/modal";
|
||||||
import { _, localize } from "../lib/i18n";
|
import { _, localize } from "../lib/i18n";
|
||||||
import { Item } from "../lib/item";
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { Item, BaseItem } from "../lib/item";
|
||||||
import { MASK } from "../lib/recentlist";
|
import { MASK } from "../lib/recentlist";
|
||||||
import { BatchGenerator } from "../lib/batches";
|
import { BatchGenerator } from "../lib/batches";
|
||||||
import { WindowState } from "./windowstate";
|
import { WindowState } from "./windowstate";
|
||||||
@ -16,7 +17,7 @@ import { $ } from "./winutil";
|
|||||||
|
|
||||||
const PORT = runtime.connect(null, { name: "single" });
|
const PORT = runtime.connect(null, { name: "single" });
|
||||||
|
|
||||||
let ITEM: any;
|
let ITEM: BaseItem;
|
||||||
let Mask: Dropdown;
|
let Mask: Dropdown;
|
||||||
|
|
||||||
class BatchModalDialog extends ModalDialog {
|
class BatchModalDialog extends ModalDialog {
|
||||||
@ -59,7 +60,7 @@ class BatchModalDialog extends ModalDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setItem(item: any) {
|
function setItem(item: BaseItem) {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -179,10 +180,12 @@ async function downloadInternal(paused: boolean) {
|
|||||||
|
|
||||||
PORT.postMessage({
|
PORT.postMessage({
|
||||||
msg: "queue",
|
msg: "queue",
|
||||||
paused,
|
|
||||||
items,
|
items,
|
||||||
mask,
|
options: {
|
||||||
maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
|
paused,
|
||||||
|
mask,
|
||||||
|
maskOnce: $<HTMLInputElement>("#maskOnceCheck").checked,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -204,7 +207,27 @@ async function init() {
|
|||||||
|
|
||||||
addEventListener("DOMContentLoaded", async function dom() {
|
addEventListener("DOMContentLoaded", async function dom() {
|
||||||
removeEventListener("DOMContentLoaded", dom);
|
removeEventListener("DOMContentLoaded", dom);
|
||||||
await init();
|
|
||||||
|
const inited = init();
|
||||||
|
PORT.onMessage.addListener(async (msg: any) => {
|
||||||
|
try {
|
||||||
|
switch (msg.msg) {
|
||||||
|
case "item": {
|
||||||
|
await inited;
|
||||||
|
setItem(msg.data.item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Error("Unhandled message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
console.error("Failed to process message", msg, ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await inited;
|
||||||
|
|
||||||
$("#btnDownload").addEventListener("click", () => download(false));
|
$("#btnDownload").addEventListener("click", () => download(false));
|
||||||
$("#btnPaused").addEventListener("click", () => download(true));
|
$("#btnPaused").addEventListener("click", () => download(true));
|
||||||
@ -224,27 +247,10 @@ addEventListener("DOMContentLoaded", async function dom() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
PORT.onMessage.addListener((msg: any) => {
|
|
||||||
try {
|
|
||||||
switch (msg.msg) {
|
|
||||||
case "item": {
|
|
||||||
setItem(msg.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw Error("Unhandled message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
console.error("Failed to process message", msg, ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
hookButton($("#maskButton"));
|
hookButton($("#maskButton"));
|
||||||
});
|
});
|
||||||
|
|
||||||
addEventListener("load", function() {
|
addEventListener("load", function () {
|
||||||
$("#URL").focus();
|
$("#URL").focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -258,7 +264,7 @@ addEventListener("contextmenu", event => {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
addEventListener("beforeunload", function() {
|
addEventListener("beforeunload", function () {
|
||||||
PORT.disconnect();
|
PORT.disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { RawPort } from "../lib/browser";
|
||||||
|
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
export class WindowState {
|
export class WindowState {
|
||||||
private readonly port: any;
|
private readonly port: RawPort;
|
||||||
|
|
||||||
constructor(port: any) {
|
constructor(port: RawPort) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.update = this.update.bind(this);
|
this.update = this.update.bind(this);
|
||||||
addEventListener("resize", this.update);
|
addEventListener("resize", this.update);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user