mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-06 23:12:22 +02:00
Snapshot current maintainer-preview application changes and regression fixtures for integration into lab. Excludes local runtime data, evaluation outputs and source backups. Focused Python regression selection: 140 passed; full suite not certified.
46 lines
1.5 KiB
JavaScript
46 lines
1.5 KiB
JavaScript
// Capture repeat clicks before tool handlers can start another request.
|
|
export function beginAIOperation(button, onCancel) {
|
|
const controller = new AbortController();
|
|
const title = button.title;
|
|
button.disabled = false;
|
|
button.title = 'Cancel running action';
|
|
button.setAttribute('aria-busy', 'true');
|
|
const cancel = event => {
|
|
event.preventDefault();
|
|
event.stopImmediatePropagation();
|
|
if (!controller.signal.aborted) {
|
|
controller.abort();
|
|
onCancel?.();
|
|
}
|
|
};
|
|
button.addEventListener('click', cancel, true);
|
|
return {
|
|
signal: controller.signal,
|
|
finish() {
|
|
button.removeEventListener('click', cancel, true);
|
|
button.title = title;
|
|
button.removeAttribute('aria-busy');
|
|
},
|
|
};
|
|
}
|
|
|
|
export function decodeAIImage(base64, signal) {
|
|
return new Promise((resolve, reject) => {
|
|
const image = new Image();
|
|
const cleanup = () => {
|
|
image.onload = image.onerror = null;
|
|
signal.removeEventListener('abort', abort);
|
|
};
|
|
const abort = () => {
|
|
cleanup();
|
|
image.src = '';
|
|
reject(new DOMException('Cancelled', 'AbortError'));
|
|
};
|
|
if (signal.aborted) { abort(); return; }
|
|
signal.addEventListener('abort', abort, { once: true });
|
|
image.onload = () => { cleanup(); resolve(image); };
|
|
image.onerror = () => { cleanup(); reject(new Error('Failed to decode result image')); };
|
|
image.src = base64.startsWith('data:') ? base64 : 'data:image/png;base64,' + base64;
|
|
});
|
|
}
|