Files
Multi-Debrid-Downloader/src/renderer/selection.ts
T
Sucukdeluxe 40428a69b4 feat(collector): rebuild link preview as package workspace
Inspect pasted links, text files and DLC containers before queue insertion and resolve supported hoster metadata without starting downloads. Group multipart files into expandable packages with size, status, availability, timestamps, filtering and stable selection. Add selected or complete transfer to Downloads while retaining entries on failed or partial handoff. Keep collector toolbar spacing consistent and show the full 1Fichier identity with its provider icon in Downloads.
2026-08-22 02:22:42 +02:00

66 lines
2.3 KiB
TypeScript

import type { SessionState } from "../shared/types";
const DOWNLOAD_SELECTION_PRESERVE_SELECTOR = ".downloads-package-card, .downloads-item-row, .downloads-selection-cell, .package-card, .ctx-menu, .modal-backdrop, .modal-card";
export function shouldClearDownloadSelection(target: Pick<Element, "closest">): boolean {
return !target.closest(DOWNLOAD_SELECTION_PRESERVE_SELECTOR);
}
export function shouldClearDownloadSelectionOnEscape(tagName: string, inputType = ""): boolean {
const normalizedTag = tagName.toUpperCase();
if (normalizedTag === "TEXTAREA") return false;
if (normalizedTag !== "INPUT") return true;
return ["checkbox", "radio", "button"].includes(inputType.toLowerCase());
}
export function resolveEscapeSelectionScope(
view: string,
settingsSection: string,
tagName: string,
inputType = ""
): "downloads" | "collector" | "history" | "accounts" | null {
if (!shouldClearDownloadSelectionOnEscape(tagName, inputType)) {
return null;
}
if (view === "downloads" || view === "history" || view === "collector") {
return view;
}
return view === "settings" && settingsSection === "accounts" ? "accounts" : null;
}
export function releaseAccountSelectionFocus(
activeElement: { closest: (selector: string) => unknown; blur: () => void } | null
): boolean {
if (!activeElement?.closest(".settings-account-row")) {
return false;
}
activeElement.blur();
return true;
}
/**
* Drop selected ids whose package OR item no longer exists in the session.
* The selection set mixes package and item ids; when entries vanish (delta
* removal, backup-driven session swap, completed-cleanup) a stale id would
* otherwise inflate the selection count and the "(N)" action labels and keep
* "multi" styling alive for ghosts.
*
* Returns the SAME set instance when nothing changed, so callers can use it
* directly as a React state updater without forcing a re-render.
*/
export function pruneSelection(
selected: ReadonlySet<string>,
session: Pick<SessionState, "packages" | "items">
): Set<string> {
if (selected.size === 0) {
return selected as Set<string>;
}
const next = new Set<string>();
for (const id of selected) {
if (session.packages[id] || session.items[id]) {
next.add(id);
}
}
return next.size === selected.size ? (selected as Set<string>) : next;
}