refactor: improve image field lazy loading mechanism with fallbacks and enhance its loading state styling.

This commit is contained in:
Suherdy Yacob 2026-03-16 15:09:24 +07:00
parent 65056cb9ea
commit 947543d54d
2 changed files with 34 additions and 19 deletions

View File

@ -52,10 +52,13 @@ body div.o_sign_sign_item.o_sign_image_item span.o_placeholder {
}
.o_sign_image_item.o_sign_image_loading_container {
background: #f6f7f8;
background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
background-size: 800px 104px;
animation: o_sign_image_shimmer 1.2s forwards infinite linear;
background: #f6f7f8 !important;
background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%) !important;
background-size: 800px 104px !important;
animation: o_sign_image_shimmer 1.2s forwards infinite linear !important;
min-width: 50px !important;
min-height: 50px !important;
z-index: 10 !important;
}
@keyframes o_sign_image_shimmer {

View File

@ -27,43 +27,55 @@ const triggerLazyLoad = (el) => {
* Setup IntersectionObserver for an element.
*/
const setupLazyObserver = (iframeInstance, el) => {
if (!el || !window.IntersectionObserver) {
// Fallback for no observer support
triggerLazyLoad(el);
return;
}
const lazyImg = el.querySelector('.o_sign_image_lazy');
if (!lazyImg || !lazyImg.dataset.src) return;
// Use the viewer container as root if possible
const root = iframeInstance.root ? iframeInstance.root.querySelector('#viewerContainer') : null;
// Use a safety timeout to ensure it loads even if observer fails
const safetyTimeout = setTimeout(() => triggerLazyLoad(el), 5000);
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
clearTimeout(safetyTimeout);
triggerLazyLoad(el);
observer.disconnect();
}
});
}, {
root: root,
rootMargin: '200px'
});
observer.observe(el);
};
// 1. Patch PDFIframe for read-only views
// 1. Patch PDFIframe (Base class)
// We patch only what is strictly necessary and avoid super calls if possible for base classes
patch(PDFIframe.prototype, {
enableCustom(signItem) {
// Base PDFIframe.enableCustom is empty, no need for super
if (signItem.data.type === 'image') {
// PDFIframe.enableCustom is normally empty
if (typeof super.enableCustom === 'function') {
super.enableCustom(signItem);
}
if (signItem && signItem.data && signItem.data.type === 'image') {
setupLazyObserver(this, signItem.el);
}
}
});
// 2. Patch SignablePDFIframe for active signer views
// 2. Patch SignablePDFIframe (Subclass)
patch(SignablePDFIframe.prototype, {
enableCustom(signItem) {
super.enableCustom(signItem); // Safe because SignablePDFIframe extends PDFIframe
if (signItem.data.type === 'image') {
// Ensure we call the base implementation (which now includes our lazy loading)
super.enableCustom(signItem);
if (signItem && signItem.data && signItem.data.type === 'image') {
const el = signItem.el;
const data = signItem.data;
if (!el) return;
el.setAttribute('data-type', 'image');
@ -143,9 +155,6 @@ patch(SignablePDFIframe.prototype, {
reader.readAsDataURL(file);
});
}
// Also setup lazy observer for signer view
setupLazyObserver(this, el);
}
},
@ -153,6 +162,9 @@ patch(SignablePDFIframe.prototype, {
if (item.data.type === 'image') {
return item.el.dataset.value || item.data.value || false;
}
return super.getSignatureValueFromElement(item);
if (typeof super.getSignatureValueFromElement === 'function') {
return super.getSignatureValueFromElement(item);
}
return false;
}
});