parent
dcf9603da8
commit
58c7955c64
1
TODO.md
1
TODO.md
@ -10,7 +10,6 @@ Planned for later.
|
||||
|
||||
* Soft errors and retry logic
|
||||
* Big caveat: When the server still responds, like 50x errors which would be recoverable, we actually have no way of knowing it did in respond in such a way. See P4 - Handle Errors remarks.
|
||||
* Delete files (well, as far as the browser allows)
|
||||
* Inter-addon API (basic)
|
||||
* Add downloads
|
||||
* vtable perf: cache column widths
|
||||
|
@ -207,6 +207,22 @@
|
||||
"description": "button text",
|
||||
"message": "Delete"
|
||||
},
|
||||
"deletefiles": {
|
||||
"description": "menu action",
|
||||
"message": "Delete Files"
|
||||
},
|
||||
"deletefiles_button": {
|
||||
"description": "button text",
|
||||
"message": "Delete"
|
||||
},
|
||||
"deletefiles_text": {
|
||||
"description": "messagebox text",
|
||||
"message": "Are you sure you want to delete the following files?"
|
||||
},
|
||||
"deletefiles_title": {
|
||||
"description": "messagebox title",
|
||||
"message": "Delete Files"
|
||||
},
|
||||
"description": {
|
||||
"description": "Description (keep it short); e.g. the description column in select",
|
||||
"message": "Description"
|
||||
@ -529,10 +545,6 @@
|
||||
"description": "Status text; manager",
|
||||
"message": "Paused"
|
||||
},
|
||||
"pref_sounds": {
|
||||
"description": "checkbox text",
|
||||
"message": "Play sounds"
|
||||
},
|
||||
"pref_add_paused": {
|
||||
"description": "Preferences/General",
|
||||
"message": "Add new downloads paused, instead of starting them immediately"
|
||||
@ -585,6 +597,10 @@
|
||||
"description": "Preferences/General",
|
||||
"message": "Show URLs instead of Names"
|
||||
},
|
||||
"pref_sounds": {
|
||||
"description": "checkbox text",
|
||||
"message": "Play sounds"
|
||||
},
|
||||
"pref_text_links": {
|
||||
"description": "Preferences/General",
|
||||
"message": "Try to find links in the website text (slower)"
|
||||
|
@ -81,6 +81,7 @@ interface Downloads {
|
||||
search(query: DownloadsQuery): Promise<any[]>;
|
||||
getFileIcon(id: number, options?: any): Promise<string>;
|
||||
setShelfEnabled(state: boolean): void;
|
||||
removeFile(manId: number): Promise<void>;
|
||||
onCreated: ExtensionListener;
|
||||
onChanged: ExtensionListener;
|
||||
onErased: ExtensionListener;
|
||||
|
@ -511,4 +511,19 @@ body > * {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: var(--done-color);
|
||||
}
|
||||
|
||||
.deletefiles-list {
|
||||
padding-left: 1ex;
|
||||
padding-right: 1.5ex;
|
||||
border: 1px solid lightgray;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(128,128,128,0.1);
|
||||
max-height: 8em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.deletefiles-list > li {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
@ -75,6 +75,7 @@
|
||||
<ul id="table-context" class="table-context">
|
||||
<li id="ctx-open-file" data-key="Enter" data-i18n="open-file" data-icon="icon-file">Open File</li>
|
||||
<li id="ctx-open-directory" data-key="ACCEL-Enter" data-i18n="open-directory" data-icon="icon-folder">Open Directory</li>
|
||||
<li id="ctx-delete-files" data-key="ACCEL-Delete" data-i18n="deletefiles" data-icon="icon-delete"></li>
|
||||
<li>-</li>
|
||||
<li id="ctx-resume" data-key="ACCEL-KeyR" data-i18n="resume-download" data-icon="icon-go">Resume</li>
|
||||
<li id="ctx-pause" data-key="ACCEL-KeyP" data-i18n="pause-download" data-icon="icon-pause">Pause</li>
|
||||
@ -125,6 +126,12 @@
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template id="deletefiles-template">
|
||||
<h1 class="deletefiles-title" data-i18n="deletefiles_title"></h1>
|
||||
<p class="deletefiles-text" data-i18n="deletefiles_text"></p>
|
||||
<ul class="deletefiles-list"></ul>
|
||||
</template>
|
||||
|
||||
<template id="menufilter-template">
|
||||
<ul>
|
||||
<li id="ctx-menufilter-seperator">-</li>
|
||||
|
@ -7,7 +7,7 @@ import { Prefs } from "../../lib/prefs";
|
||||
import { Keys } from "../keys";
|
||||
import { $ } from "../winutil";
|
||||
|
||||
export default class RemovalModalDialog extends ModalDialog {
|
||||
export class RemovalModalDialog extends ModalDialog {
|
||||
private readonly text: string;
|
||||
|
||||
private readonly pref: string;
|
||||
@ -68,3 +68,57 @@ export default class RemovalModalDialog extends ModalDialog {
|
||||
this.focusDefault();
|
||||
}
|
||||
}
|
||||
|
||||
export class DeleteFilesDialog extends ModalDialog {
|
||||
private readonly paths: string[];
|
||||
|
||||
constructor(paths: string[]) {
|
||||
super();
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
async getContent() {
|
||||
const content = $<HTMLTemplateElement>("#deletefiles-template").
|
||||
content.cloneNode(true) as DocumentFragment;
|
||||
await localize(content);
|
||||
const list = $(".deletefiles-list", content);
|
||||
for (const path of this.paths) {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = path;
|
||||
list.appendChild(li);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
get buttons() {
|
||||
return [
|
||||
{
|
||||
title: _("deletefiles_button"),
|
||||
value: "ok",
|
||||
default: true,
|
||||
dismiss: false,
|
||||
},
|
||||
{
|
||||
title: _("cancel"),
|
||||
value: "cancel",
|
||||
default: false,
|
||||
dismiss: true,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
async show() {
|
||||
Keys.suppressed = true;
|
||||
try {
|
||||
return await super.show();
|
||||
}
|
||||
finally {
|
||||
Keys.suppressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
shown() {
|
||||
this.focusDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import {
|
||||
MenuFilter
|
||||
} from "./itemfilters";
|
||||
import { FilteredCollection } from "./itemfilters";
|
||||
import RemovalModalDialog from "./removaldlg";
|
||||
import { RemovalModalDialog, DeleteFilesDialog } from "./removaldlg";
|
||||
import { Stats } from "./stats";
|
||||
import PORT from "./port";
|
||||
import { DownloadState, StateTexts, StateClasses, StateIcons } from "./state";
|
||||
@ -404,6 +404,8 @@ export class DownloadTable extends VirtualTable {
|
||||
|
||||
private readonly openDirectoryAction: Broadcaster;
|
||||
|
||||
private readonly deleteFilesAction: Broadcaster;
|
||||
|
||||
private readonly moveTopAction: Broadcaster;
|
||||
|
||||
private readonly moveUpAction: Broadcaster;
|
||||
@ -579,6 +581,9 @@ export class DownloadTable extends VirtualTable {
|
||||
this.openDirectoryAction = new Broadcaster("ctx-open-directory");
|
||||
this.openDirectoryAction.onaction = this.openDirectory.bind(this);
|
||||
|
||||
this.deleteFilesAction = new Broadcaster("ctx-delete-files");
|
||||
this.deleteFilesAction.onaction = this.deleteFiles.bind(this);
|
||||
|
||||
const moveAction = (method: string) => {
|
||||
if (this.selection.empty) {
|
||||
return;
|
||||
@ -610,6 +615,7 @@ export class DownloadTable extends VirtualTable {
|
||||
this.moveBottomAction,
|
||||
this.openFileAction,
|
||||
this.openDirectoryAction,
|
||||
this.deleteFilesAction,
|
||||
]);
|
||||
|
||||
this.on(
|
||||
@ -782,6 +788,10 @@ export class DownloadTable extends VirtualTable {
|
||||
this.cancelAction.disabled = true;
|
||||
}
|
||||
|
||||
if (!(states & DownloadState.DONE)) {
|
||||
this.deleteFilesAction.disabled = true;
|
||||
}
|
||||
|
||||
const item = this.focusRow >= 0 ?
|
||||
this.downloads.filtered[this.focusRow] :
|
||||
null;
|
||||
@ -860,6 +870,33 @@ export class DownloadTable extends VirtualTable {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteFiles() {
|
||||
const items = [];
|
||||
for (const rowid of this.selection) {
|
||||
const item = this.downloads.filtered[rowid];
|
||||
if (item.state === DownloadState.DONE && item.manId) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
if (!items.length) {
|
||||
return;
|
||||
}
|
||||
const sids = items.map(i => i.sessionId);
|
||||
const paths = items.map(i => i.destFull);
|
||||
await new DeleteFilesDialog(paths).show();
|
||||
await Promise.all(items.map(async item => {
|
||||
try {
|
||||
if (item.manId && item.state === DownloadState.DONE) {
|
||||
await downloads.removeFile(item.manId);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// ignored
|
||||
}
|
||||
}));
|
||||
this.removeDownloadsInternal(sids);
|
||||
}
|
||||
|
||||
removeDownloadsInternal(sids?: number[]) {
|
||||
if (!sids) {
|
||||
sids = [];
|
||||
|
Loading…
x
Reference in New Issue
Block a user