feat(photo-editor): Ajax Image Editor client (Photoshop-parity tools)

Photoshop-parity editor client: layers, selection/masking, brushes,
smart filters, LUT import, Quick Edit, mobile gestures, workspaces,
batch operations, and the service-worker versioning (v978->v1006).

Source: vendor/photocraft (ad1cff44) photo-editor client files, merged
onto upstream/dev (a8c147b2). Conflict resolution documented in
pr_work/A_conflicts.md; editor files taken from vendor/photocraft
(upstream's editor is an earlier snapshot of the same feature).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
pewdiepie-archdaemon
2026-10-15 11:57:35 +00:00
co-authored by Claude Opus 5.5
parent c74f475679
commit 5fac693c1c
290 changed files with 34358 additions and 766 deletions
+35
View File
@@ -0,0 +1,35 @@
/**
* Batch runner — a small, dependency-free orchestrator that applies one action
* to every item in a list (open documents), isolating each item so a failure on
* one never aborts the batch. Pure async control flow: the caller supplies
* `runOne`, so the same loop is unit-testable without an editor.
*/
/**
* @param {object} options
* @param {Array<{id:string,name?:string}>} options.documents
* @param {(doc:object, index:number)=>Promise<any>} options.runOne
* @param {number} [options.delayMs]
* @param {(done:number,total:number,doc:object)=>void} [options.onProgress]
* @returns {Promise<Array<{id,name,ok,output?,error?}>>}
*/
export async function runBatchOverDocuments({ documents, runOne, delayMs = 0, onProgress = null } = {}) {
const list = Array.isArray(documents) ? documents.filter(Boolean) : [];
const results = [];
for (let index = 0; index < list.length; index += 1) {
const doc = list[index];
try {
const output = await runOne(doc, index);
results.push({ id: doc.id, name: doc.name, ok: true, output: output === undefined ? null : output });
} catch (error) {
results.push({ id: doc.id, name: doc.name, ok: false, error: String((error && error.message) || error) });
}
if (typeof onProgress === 'function') {
try { onProgress(index + 1, list.length, doc); } catch { /* progress is best-effort */ }
}
if (delayMs > 0) await new Promise(resolve => setTimeout(resolve, delayMs));
}
return results;
}
export default { runBatchOverDocuments };