components/media/media-actions.ts
72 lines and 3 functions in DrDustinEdwards/capsomer, at commit d3966cc on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| applyBulkTag | 8 to 44 | 7 | No data: no coverage report in this map | No data: no coverage report in this map | No data: mutation testing has not run on this repo yet |
| <anonymous:37> | 37 to 37 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: mutation testing has not run on this repo yet |
| copyText | 55 to 76 | 3 | No data: no coverage report in this map | No data: no coverage report in this map | No data: mutation testing has not run on this repo yet |
Imports
It imports no other module of this repo. Imported by components/media/media.react.tsx, components/media/media.ts.
Source
// The media library's bulk tags and the clipboard: plain functions the behaviour module and the React
// wrapper share.
// ---------------------------------------------------------------------------------------
// Bulk tags: add or remove one tag across a
// selection. An item already in the wanted state is skipped, so it is not rewritten for nothing,
// and one item's failure is recorded without stopping the rest.
export async function applyBulkTag<T>({
ids,
wanted,
adding,
missing,
read,
write,
}: {
ids: readonly string[];
wanted: string;
adding: boolean;
missing: string;
read: (id: string) => Promise<{ item: T; tags: string[] } | null>;
write: (id: string, item: T, tags: string[]) => Promise<unknown>;
}): Promise<{ done: string[]; skipped: string[]; failed: string[] }> {
const failed: string[] = [];
const done: string[] = [];
const skipped: string[] = [];
for (const id of ids) {
try {
const found = await read(id);
if (!found) {
failed.push(`${id}: ${missing}`);
continue;
}
if (adding === found.tags.includes(wanted)) {
skipped.push(id);
continue;
}
await write(id, found.item, adding ? [...found.tags, wanted] : found.tags.filter((t) => t !== wanted));
done.push(id);
} catch (error) {
failed.push(`${id}: ${error instanceof Error ? error.message : "failed"}`);
}
}
return { done, skipped, failed };
}
// ---------------------------------------------------------------------------------------
// The clipboard. Copy through the Clipboard API; where the page may not, through a selected
// field and the document's own copy command; where neither works, say so and leave the text
// selected.
// How long the copy status stays: a success is short news, a failure leaves time to copy by hand.
export const COPIED_MS = 2500;
export const COPY_FAILED_MS = 8000;
export async function copyText(text: string): Promise<boolean> {
try {
await navigator.clipboard.writeText(text);
return true;
} catch {
// fall through
}
try {
const area = document.createElement("textarea");
area.value = text;
area.setAttribute("readonly", "");
area.style.setProperty("position", "fixed");
area.style.setProperty("opacity", "0");
document.body.append(area);
area.select();
const ok = document.execCommand("copy");
area.remove();
return ok;
} catch {
return false;
}
}