mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-16 20:02:20 +02:00
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:
co-authored by
Claude Opus 5.5
parent
c74f475679
commit
5fac693c1c
@@ -0,0 +1,97 @@
|
||||
// Programmatic control surface for the PhotoCraft editor.
|
||||
//
|
||||
// This module turns the editor's internal operations into a stable,
|
||||
// JSON-friendly command API so an MCP server (or the in-editor natural
|
||||
// language entrypoint) can drive the editor without poking at private
|
||||
// closures. The heavy lifting lives in galleryEditor.js, which builds the
|
||||
// handler map from its in-scope functions and installs it on
|
||||
// window.geEditorControl.
|
||||
//
|
||||
// Contract:
|
||||
// control.invoke(op, params) -> Promise<{ ok, result } | { ok:false, error }>
|
||||
// control.run(steps) -> Promise<Array<stepResult>> (sequential)
|
||||
// control.list() -> [{ op, description }]
|
||||
// control.describe(op) -> { op, description } | null
|
||||
//
|
||||
// Every op name is namespaced: document.*, layers.*, selection.*,
|
||||
// adjustments.*, filters.*, transform.*, text.*, history.*, export.*.
|
||||
|
||||
export const EDITOR_CONTROL_VERSION = '1.0';
|
||||
|
||||
function normalizeError(err) {
|
||||
if (!err) return 'Unknown error';
|
||||
if (typeof err === 'string') return err;
|
||||
return err.message || String(err);
|
||||
}
|
||||
|
||||
export function createEditorControl({ handlers = {}, getState = null, version = EDITOR_CONTROL_VERSION } = {}) {
|
||||
const registry = new Map();
|
||||
for (const [op, entry] of Object.entries(handlers)) {
|
||||
if (!entry) continue;
|
||||
if (typeof entry === 'function') {
|
||||
registry.set(op, { run: entry, description: '' });
|
||||
} else if (typeof entry.run === 'function') {
|
||||
registry.set(op, { run: entry.run, description: entry.description || '' });
|
||||
}
|
||||
}
|
||||
|
||||
function describe(op) {
|
||||
const entry = registry.get(op);
|
||||
if (!entry) return null;
|
||||
return { op, description: entry.description };
|
||||
}
|
||||
|
||||
function list() {
|
||||
return Array.from(registry.keys())
|
||||
.sort()
|
||||
.map((op) => ({ op, description: registry.get(op).description }));
|
||||
}
|
||||
|
||||
function snapshot() {
|
||||
if (typeof getState !== 'function') return {};
|
||||
try {
|
||||
return getState() || {};
|
||||
} catch (_err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function invoke(op, params = {}) {
|
||||
const entry = registry.get(op);
|
||||
if (!entry) {
|
||||
return { ok: false, error: `Unknown editor op: ${op}`, op };
|
||||
}
|
||||
try {
|
||||
const result = await entry.run(params || {}, { state: snapshot(), control });
|
||||
return { ok: true, op, result: result === undefined ? null : result };
|
||||
} catch (err) {
|
||||
return { ok: false, op, error: normalizeError(err) };
|
||||
}
|
||||
}
|
||||
|
||||
async function run(steps) {
|
||||
const list = Array.isArray(steps) ? steps : [];
|
||||
const results = [];
|
||||
for (const step of list) {
|
||||
const op = step && step.op;
|
||||
const params = (step && step.params) || {};
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const res = await invoke(op, params);
|
||||
results.push(res);
|
||||
if (!res.ok) break;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
const control = {
|
||||
version,
|
||||
installed: true,
|
||||
list,
|
||||
describe,
|
||||
invoke,
|
||||
run,
|
||||
};
|
||||
return control;
|
||||
}
|
||||
|
||||
export default createEditorControl;
|
||||
Reference in New Issue
Block a user