updated files with new features and improvements: caching proper
This commit is contained in:
+34
-4
@@ -140,6 +140,7 @@
|
||||
const cardBackCache = new Map();
|
||||
const cardBackThumbnailCache = new Map();
|
||||
const imagePreloadCache = new Map();
|
||||
const loadedImageCache = new Map();
|
||||
const deckImagePreloadCache = new Map();
|
||||
const deckPreloadStatus = {
|
||||
activeDeckId: DEFAULT_DECK_ID,
|
||||
@@ -574,6 +575,7 @@
|
||||
cardBackCache.clear();
|
||||
cardBackThumbnailCache.clear();
|
||||
imagePreloadCache.clear();
|
||||
loadedImageCache.clear();
|
||||
deckImagePreloadCache.clear();
|
||||
backgroundDeckWarmupPromise = null;
|
||||
setDeckPreloadStatus({
|
||||
@@ -948,7 +950,11 @@
|
||||
function preloadImageUrl(url) {
|
||||
const normalizedUrl = String(url || "").trim();
|
||||
if (!normalizedUrl) {
|
||||
return Promise.resolve(false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
if (loadedImageCache.has(normalizedUrl)) {
|
||||
return Promise.resolve(loadedImageCache.get(normalizedUrl));
|
||||
}
|
||||
|
||||
if (imagePreloadCache.has(normalizedUrl)) {
|
||||
@@ -971,12 +977,20 @@
|
||||
}
|
||||
|
||||
image.decoding = "async";
|
||||
image.onload = () => finalize(true);
|
||||
image.onerror = () => finalize(false);
|
||||
image.onload = () => {
|
||||
loadedImageCache.set(normalizedUrl, image);
|
||||
finalize(image);
|
||||
};
|
||||
image.onerror = () => finalize(null);
|
||||
image.src = normalizedUrl;
|
||||
|
||||
if (image.complete) {
|
||||
finalize(Boolean(image.naturalWidth));
|
||||
if (image.naturalWidth) {
|
||||
loadedImageCache.set(normalizedUrl, image);
|
||||
finalize(image);
|
||||
} else {
|
||||
finalize(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -984,6 +998,20 @@
|
||||
return preloadPromise;
|
||||
}
|
||||
|
||||
function ensureImageLoaded(url) {
|
||||
return preloadImageUrl(url);
|
||||
}
|
||||
|
||||
function isImageLoaded(url) {
|
||||
const normalizedUrl = String(url || "").trim();
|
||||
if (!normalizedUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const cachedImage = loadedImageCache.get(normalizedUrl);
|
||||
return Boolean(cachedImage?.complete && cachedImage?.naturalWidth);
|
||||
}
|
||||
|
||||
async function preloadImageUrls(urls, concurrency = 6) {
|
||||
const queue = Array.from(new Set(Array.isArray(urls) ? urls.map((entry) => String(entry || "").trim()).filter(Boolean) : []));
|
||||
if (queue.length === 0) {
|
||||
@@ -1268,6 +1296,8 @@
|
||||
resolveTarotCardBackThumbnail,
|
||||
preloadDeckImages,
|
||||
preloadAllDeckImages,
|
||||
ensureImageLoaded,
|
||||
isImageLoaded,
|
||||
getDeckPreloadStatus: () => emitDeckPreloadStatus(),
|
||||
getTarotCardDisplayName,
|
||||
getTarotCardSearchAliases,
|
||||
|
||||
+68
-10
@@ -54,6 +54,8 @@
|
||||
let activePinchGesture = null;
|
||||
let suppressNextCardClick = false;
|
||||
let suppressDeckCompareToggleUntil = 0;
|
||||
let primaryImageRequestToken = 0;
|
||||
let overlayImageRequestToken = 0;
|
||||
|
||||
const LIGHTBOX_ZOOM_SCALE = 6.66;
|
||||
const LIGHTBOX_ZOOM_STEP = 0.1;
|
||||
@@ -837,6 +839,7 @@
|
||||
const label = String(normalized.label || normalized.altText || "Tarot card enlarged image").trim() || "Tarot card enlarged image";
|
||||
return {
|
||||
src: String(normalized.src || "").trim(),
|
||||
previewSrc: String(normalized.previewSrc || "").trim(),
|
||||
altText: String(normalized.altText || label).trim() || label,
|
||||
label,
|
||||
cardId: String(normalized.cardId || "").trim(),
|
||||
@@ -847,6 +850,66 @@
|
||||
};
|
||||
}
|
||||
|
||||
function getImageRequestToken(layer = "primary") {
|
||||
if (layer === "overlay") {
|
||||
overlayImageRequestToken += 1;
|
||||
return overlayImageRequestToken;
|
||||
}
|
||||
|
||||
primaryImageRequestToken += 1;
|
||||
return primaryImageRequestToken;
|
||||
}
|
||||
|
||||
function getCurrentImageRequestToken(layer = "primary") {
|
||||
return layer === "overlay" ? overlayImageRequestToken : primaryImageRequestToken;
|
||||
}
|
||||
|
||||
function applyCardImageToElement(targetImageEl, cardRequest, layer = "primary") {
|
||||
if (!(targetImageEl instanceof HTMLImageElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalizedCard = normalizeCardRequest(cardRequest);
|
||||
const fullSrc = String(normalizedCard.src || "").trim();
|
||||
const previewSrc = String(normalizedCard.previewSrc || "").trim();
|
||||
const normalizedPreviewSrc = previewSrc && previewSrc !== fullSrc ? previewSrc : "";
|
||||
const imageCache = window.TarotCardImages || {};
|
||||
const fullImageLoaded = typeof imageCache.isImageLoaded === "function"
|
||||
? imageCache.isImageLoaded(fullSrc)
|
||||
: false;
|
||||
const requestToken = getImageRequestToken(layer);
|
||||
const initialSrc = fullSrc && (!normalizedPreviewSrc || fullImageLoaded)
|
||||
? fullSrc
|
||||
: (normalizedPreviewSrc || fullSrc);
|
||||
|
||||
if (initialSrc) {
|
||||
targetImageEl.src = initialSrc;
|
||||
targetImageEl.alt = normalizedCard.altText;
|
||||
} else {
|
||||
targetImageEl.removeAttribute("src");
|
||||
targetImageEl.alt = normalizedCard.altText;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fullSrc || initialSrc === fullSrc || typeof imageCache.ensureImageLoaded !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
imageCache.ensureImageLoaded(fullSrc)
|
||||
.then((loadedImage) => {
|
||||
if (!loadedImage || getCurrentImageRequestToken(layer) !== requestToken || !lightboxState.isOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetImageEl.src !== fullSrc) {
|
||||
targetImageEl.src = fullSrc;
|
||||
targetImageEl.alt = normalizedCard.altText;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeDeckOptions(deckOptions) {
|
||||
if (!Array.isArray(deckOptions)) {
|
||||
return [];
|
||||
@@ -3198,8 +3261,7 @@
|
||||
if (isCompactLightboxLayout()) {
|
||||
lightboxState.mobileInfoView = "overlay";
|
||||
}
|
||||
overlayImageEl.src = normalizedCard.src;
|
||||
overlayImageEl.alt = normalizedCard.altText;
|
||||
applyCardImageToElement(overlayImageEl, normalizedCard, "overlay");
|
||||
overlayImageEl.style.display = "block";
|
||||
overlayImageEl.style.opacity = String(lightboxState.overlayOpacity);
|
||||
if (syncSelection && typeof lightboxState.onSelectCardId === "function") {
|
||||
@@ -3254,8 +3316,7 @@
|
||||
}
|
||||
|
||||
lightboxState.primaryCard = nextCard;
|
||||
imageEl.src = nextCard.src;
|
||||
imageEl.alt = nextCard.altText;
|
||||
applyCardImageToElement(imageEl, nextCard, "primary");
|
||||
resetZoom();
|
||||
if (lightboxState.deckCompareMode) {
|
||||
syncDeckCompareCards();
|
||||
@@ -3279,10 +3340,8 @@
|
||||
lightboxState.primaryCard = nextPrimaryCard;
|
||||
lightboxState.secondaryCard = nextSecondaryCard;
|
||||
|
||||
imageEl.src = nextPrimaryCard.src;
|
||||
imageEl.alt = nextPrimaryCard.altText;
|
||||
overlayImageEl.src = nextSecondaryCard.src;
|
||||
overlayImageEl.alt = nextSecondaryCard.altText;
|
||||
applyCardImageToElement(imageEl, nextPrimaryCard, "primary");
|
||||
applyCardImageToElement(overlayImageEl, nextSecondaryCard, "overlay");
|
||||
overlayImageEl.style.display = "block";
|
||||
overlayImageEl.style.opacity = String(lightboxState.overlayOpacity);
|
||||
|
||||
@@ -3723,8 +3782,7 @@
|
||||
setInfoPanelOpen(getPersistedInfoPanelVisibility(), { persist: false });
|
||||
lightboxState.mobileInfoView = "primary";
|
||||
|
||||
imageEl.src = normalizedPrimary.src;
|
||||
imageEl.alt = normalizedPrimary.altText;
|
||||
applyCardImageToElement(imageEl, normalizedPrimary, "primary");
|
||||
clearSecondaryCard();
|
||||
resetZoom();
|
||||
previousFocusedEl = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
||||
|
||||
@@ -770,6 +770,9 @@
|
||||
const src = typeof resolveTarotCardImage === "function"
|
||||
? resolveTarotCardImage(card.name, deckOptions)
|
||||
: "";
|
||||
const previewSrc = typeof resolveTarotCardThumbnail === "function"
|
||||
? (resolveTarotCardThumbnail(card.name, deckOptions) || src)
|
||||
: src;
|
||||
const deckMeta = resolvedDeckId ? getRegisteredDeckOptionMap().get(resolvedDeckId) : null;
|
||||
const label = (typeof getTarotCardDisplayName === "function"
|
||||
? getTarotCardDisplayName(card.name, deckOptions)
|
||||
@@ -777,6 +780,7 @@
|
||||
|
||||
return {
|
||||
src,
|
||||
previewSrc,
|
||||
altText: label,
|
||||
label,
|
||||
cardId: card.id,
|
||||
|
||||
Reference in New Issue
Block a user