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,69 +5,69 @@ import { PDFIframe } from "@sign/components/sign_request/PDF_iframe";
import { SignablePDFIframe } from "@sign/components/sign_request/signable_PDF_iframe"; import { SignablePDFIframe } from "@sign/components/sign_request/signable_PDF_iframe";
/** /**
* Shared logic for triggered lazy loading of images. * Robust lazy loading trigger for image sign items.
* This ensures that when a sign item element is created or scrolled into view,
* its image is loaded from the data-src attribute.
*/ */
const lazyLoadMixin = { const triggerLazyLoad = (el) => {
_triggerLazyLoad(el) { if (!el) return;
if (!el) return; const lazyImg = el.querySelector('.o_sign_image_lazy');
const lazyImg = el.querySelector('.o_sign_image_lazy'); if (lazyImg && lazyImg.dataset.src) {
if (lazyImg && lazyImg.dataset.src) { const currentSrc = lazyImg.getAttribute('src');
const currentSrc = lazyImg.getAttribute('src'); if (!currentSrc || currentSrc.startsWith('data:image/gif')) {
// Check if it's currently showing the transparent placeholder lazyImg.src = lazyImg.dataset.src;
if (!currentSrc || currentSrc.startsWith('data:image/gif')) { lazyImg.onload = () => {
lazyImg.src = lazyImg.dataset.src; lazyImg.classList.remove('o_sign_image_loading');
lazyImg.onload = () => { el.classList.remove('o_sign_image_loading_container');
lazyImg.classList.remove('o_sign_image_loading'); lazyImg.style.opacity = 1;
el.classList.remove('o_sign_image_loading_container'); };
lazyImg.style.opacity = 1;
};
}
}
},
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, { * Setup IntersectionObserver for an element.
...lazyLoadMixin, */
const setupLazyObserver = (iframeInstance, el) => {
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;
// We also hook into enableCustom to trigger lazy load for initial items 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) { enableCustom(signItem) {
super.enableCustom(signItem); // Base PDFIframe.enableCustom is empty, no need for super
if (signItem.data.type === 'image') { 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, { patch(SignablePDFIframe.prototype, {
// Note: Mixin methods are already inherited if not overwritten,
// but SignablePDFIframe might need its own hooks.
enableCustom(signItem) { enableCustom(signItem) {
super.enableCustom(signItem); super.enableCustom(signItem); // Safe because SignablePDFIframe extends PDFIframe
if (signItem.data.type === 'image') { if (signItem.data.type === 'image') {
const el = signItem.el; const el = signItem.el;
const data = signItem.data; const data = signItem.data;
// Add data-type attribute for CSS targeting
el.setAttribute('data-type', 'image'); el.setAttribute('data-type', 'image');
// Initial font size adjustment for placeholder text // Initial font size adjustment for placeholder
const adjustFontSize = () => { const adjustFontSize = () => {
const placeholder = el.querySelector('.o_placeholder'); const placeholder = el.querySelector('.o_placeholder');
if (placeholder) { if (placeholder) {
@ -144,8 +144,8 @@ patch(SignablePDFIframe.prototype, {
}); });
} }
// Immediately trigger load if value exists // Also setup lazy observer for signer view
this._triggerLazyLoad(el); setupLazyObserver(this, el);
} }
}, },