/** @odoo-module **/ import { patch } from "@web/core/utils/patch"; 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. */ const lazyLoadMixin = { _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 = () => { lazyImg.classList.remove('o_sign_image_loading'); 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, { ...lazyLoadMixin, // We also hook into enableCustom to trigger lazy load for initial items enableCustom(signItem) { super.enableCustom(signItem); if (signItem.data.type === 'image') { this._triggerLazyLoad(signItem.el); } } }); // 2. Patch SignablePDFIframe for upload handlers and specific behaviors (covers signing 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); 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 const adjustFontSize = () => { const placeholder = el.querySelector('.o_placeholder'); if (placeholder) { const minDimension = Math.min(el.offsetHeight, el.offsetWidth); const fontSize = Math.max(10, Math.min(16, minDimension * 0.4)); placeholder.style.fontSize = fontSize + 'px !important'; placeholder.style.lineHeight = '1'; } }; setTimeout(adjustFontSize, 100); // Upload implementation const input = el.querySelector('.o_sign_image_upload_input'); if (input) { el.addEventListener('click', (e) => { if (this.readonly || (data.responsible > 0 && data.responsible !== this.currentRole)) return; if (e.target !== input) { input.click(); } }); input.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (readerEvent) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); let width = img.width; let height = img.height; const MAX_SIZE = 1080; if (width > height) { if (width > MAX_SIZE) { height *= MAX_SIZE / width; width = MAX_SIZE; } } else if (height > MAX_SIZE) { width *= MAX_SIZE / height; height = MAX_SIZE; } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height); const compressedDataUrl = canvas.toDataURL('image/jpeg', 0.7); data.value = compressedDataUrl; el.dataset.value = compressedDataUrl; const placeholder = el.querySelector('.o_placeholder'); if (placeholder) placeholder.remove(); let existingImg = el.querySelector('img'); if (!existingImg) { existingImg = document.createElement('img'); existingImg.style.maxWidth = '100%'; existingImg.style.maxHeight = '100%'; existingImg.style.objectFit = 'contain'; const body = el.querySelector('.sign_item_body') || el; body.appendChild(existingImg); } existingImg.src = compressedDataUrl; if (this.handleInput) { this.handleInput(); } }; img.src = readerEvent.target.result; }; reader.readAsDataURL(file); }); } // Immediately trigger load if value exists this._triggerLazyLoad(el); } }, getSignatureValueFromElement(item) { if (item.data.type === 'image') { return item.el.dataset.value || item.data.value || false; } return super.getSignatureValueFromElement(item); } });