53 lines
2.2 KiB
JavaScript
53 lines
2.2 KiB
JavaScript
/**
|
|
* Image-loading helpers used by photo upload and slot assignment.
|
|
*
|
|
* Before this module: `useTemplate.assignImageToSlot` and `UploadTab.getImageSize`
|
|
* each had their own inline `new Image() + onload + onerror` Promise wrapper,
|
|
* and `App.handlePhotoEditComplete` had a third variant using callbacks
|
|
* instead of a Promise. The three wrappers had subtly different error
|
|
* handling — one rejected with a generic message, another logged to the
|
|
* console, the third silently swallowed errors and used a fallback path.
|
|
*
|
|
* Centralizing here gives every caller the same behavior: a clean Promise
|
|
* that resolves to dimensions or rejects with a descriptive Error. The
|
|
* App.jsx photo-edit flow still uses the lower-level callback form because
|
|
* its onload handler runs synchronously before its setEditingElement call
|
|
* (timing matters for the Filerobot modal teardown sequence) — but the
|
|
* other two consumers go through `loadImageDimensions`.
|
|
*/
|
|
|
|
/**
|
|
* Load an image and resolve to its natural pixel dimensions.
|
|
*
|
|
* Resolves with `{ width, height }` from `naturalWidth`/`naturalHeight`,
|
|
* falling back to `width`/`height` for the rare case where naturalWidth is 0
|
|
* (some Safari versions report this for SVG sources without intrinsic size).
|
|
*
|
|
* Rejects with a descriptive Error if the image fails to load. Callers
|
|
* should `await` and use try/catch — not `.then(undefined, () => fallback)`,
|
|
* which would silently mask bugs.
|
|
*
|
|
* @param {string} src - data:, blob:, or remote URL
|
|
* @returns {Promise<{ width: number, height: number }>}
|
|
*/
|
|
export function loadImageDimensions(src) {
|
|
return new Promise((resolve, reject) => {
|
|
const img = new window.Image();
|
|
img.onload = () => resolve({
|
|
width: img.naturalWidth || img.width,
|
|
height: img.naturalHeight || img.height,
|
|
});
|
|
img.onerror = () => reject(new Error(`Failed to load image: ${truncate(src, 80)}`));
|
|
img.src = src;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Truncate a URL for use in error messages. Long data: URLs in stack traces
|
|
* blow up log readers; the first 80 chars are enough to identify the type.
|
|
*/
|
|
function truncate(s, n) {
|
|
if (typeof s !== 'string') return String(s);
|
|
return s.length > n ? `${s.slice(0, n)}…` : s;
|
|
}
|