feat: Implement IntersectionObserver for lazy loading of image sign items instead of immediate triggering.

This commit is contained in:
Suherdy Yacob 2026-03-16 14:59:19 +07:00
parent 0f9d0e02e6
commit 65056cb9ea

View File

@ -5,17 +5,13 @@ import { PDFIframe } from "@sign/components/sign_request/PDF_iframe";
import { SignablePDFIframe } from "@sign/components/sign_request/signable_PDF_iframe";
/**
* Shared logic for triggered lazy loading of images.
* This ensures that when a sign item element is created or scrolled into view,
* its image is loaded from the data-src attribute.
* Robust lazy loading trigger for image sign items.
*/
const lazyLoadMixin = {
_triggerLazyLoad(el) {
const triggerLazyLoad = (el) => {
if (!el) return;
const lazyImg = el.querySelector('.o_sign_image_lazy');
if (lazyImg && lazyImg.dataset.src) {
const currentSrc = lazyImg.getAttribute('src');
// Check if it's currently showing the transparent placeholder
if (!currentSrc || currentSrc.startsWith('data:image/gif')) {
lazyImg.src = lazyImg.dataset.src;
lazyImg.onload = () => {
@ -25,49 +21,53 @@ const lazyLoadMixin = {
};
}
}
},
refreshSignItemsForPage(page) {
super.refreshSignItemsForPage(page);
if (this.signItems && this.signItems[page]) {
for (const id in this.signItems[page]) {
const item = this.signItems[page][id];
if (item && item.el) {
this._triggerLazyLoad(item.el);
}
}
}
}
};
// 1. Patch the base PDFIframe for shared lazy-loading logic (covers read-only views)
patch(PDFIframe.prototype, {
...lazyLoadMixin,
/**
* Setup IntersectionObserver for an element.
*/
const setupLazyObserver = (iframeInstance, el) => {
const lazyImg = el.querySelector('.o_sign_image_lazy');
if (!lazyImg || !lazyImg.dataset.src) return;
// We also hook into enableCustom to trigger lazy load for initial items
// Use the viewer container as root if possible
const root = iframeInstance.root ? iframeInstance.root.querySelector('#viewerContainer') : null;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
triggerLazyLoad(el);
observer.disconnect();
}
});
}, {
root: root,
rootMargin: '200px'
});
observer.observe(el);
};
// 1. Patch PDFIframe for read-only views
patch(PDFIframe.prototype, {
enableCustom(signItem) {
super.enableCustom(signItem);
// Base PDFIframe.enableCustom is empty, no need for super
if (signItem.data.type === 'image') {
this._triggerLazyLoad(signItem.el);
setupLazyObserver(this, signItem.el);
}
}
});
// 2. Patch SignablePDFIframe for upload handlers and specific behaviors (covers signing views)
// 2. Patch SignablePDFIframe for active signer views
patch(SignablePDFIframe.prototype, {
// Note: Mixin methods are already inherited if not overwritten,
// but SignablePDFIframe might need its own hooks.
enableCustom(signItem) {
super.enableCustom(signItem);
super.enableCustom(signItem); // Safe because SignablePDFIframe extends PDFIframe
if (signItem.data.type === 'image') {
const el = signItem.el;
const data = signItem.data;
// Add data-type attribute for CSS targeting
el.setAttribute('data-type', 'image');
// Initial font size adjustment for placeholder text
// Initial font size adjustment for placeholder
const adjustFontSize = () => {
const placeholder = el.querySelector('.o_placeholder');
if (placeholder) {
@ -144,8 +144,8 @@ patch(SignablePDFIframe.prototype, {
});
}
// Immediately trigger load if value exists
this._triggerLazyLoad(el);
// Also setup lazy observer for signer view
setupLazyObserver(this, el);
}
},