/** @odoo-module **/ import { patch } from "@web/core/utils/patch"; import { PDFIframe } from "@sign/components/sign_request/PDF_iframe"; patch(PDFIframe.prototype, { 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'); // Function to adjust font size based on container dimensions const adjustFontSize = () => { const placeholder = el.querySelector('.o_placeholder'); if (placeholder) { const containerHeight = el.offsetHeight; const containerWidth = el.offsetWidth; const minDimension = Math.min(containerHeight, containerWidth); const fontSize = Math.max(10, Math.min(16, minDimension * 0.4)); placeholder.style.fontSize = fontSize + 'px !important'; placeholder.style.lineHeight = '1'; } }; // Initial font size adjustment setTimeout(adjustFontSize, 100); // Watch for size changes if (window.ResizeObserver) { const resizeObserver = new ResizeObserver(adjustFontSize); resizeObserver.observe(el); } 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; // Prevent recursive click if clicking the input itself bubbles up 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); // Update state and element data.value = compressedDataUrl; el.dataset.value = compressedDataUrl; // Force immediate display update 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; // Notify Odoo of the value change if (this.handleInput) { this.handleInput(); } }; img.src = readerEvent.target.result; }; reader.readAsDataURL(file); }); } // Performance Fix: Trigger lazy load if already visible this._triggerLazyLoad(el); } }, 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); } } } }, /** * Triggers the load of a lazy-loaded image if it has a data-src attribute * @param {HTMLElement} el */ _triggerLazyLoad(el) { if (!el) return; const lazyImg = el.querySelector('.o_sign_image_lazy'); if (lazyImg && lazyImg.dataset.src) { const currentSrc = lazyImg.getAttribute('src'); // If src is still the transparent placeholder gif or empty, load the real image 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; }; } } }, getSignatureValueFromElement(item) { if (item.data.type === 'image') { return item.el.dataset.value || item.data.value || false; } return super.getSignatureValueFromElement(item); } });