fix for odoo 19

This commit is contained in:
Suherdy Yacob 2026-01-23 14:31:34 +07:00
parent 6d0c445279
commit 80930a9535

View File

@ -5,15 +5,15 @@ console.log('Loading ultra-safe decimal observer...');
// Function to safely apply decimal styling to any element // Function to safely apply decimal styling to any element
function safelyApplyDecimalStyling(element) { function safelyApplyDecimalStyling(element) {
if (!element || !element.textContent || !document.contains(element)) return false; if (!element || !element.textContent || !document.contains(element)) return false;
// Skip if already processed or if Owl is updating this element // Skip if already processed or if Owl is updating this element
if (element.querySelector('.o_decimal') || if (element.querySelector('.o_decimal') ||
element.classList.contains('o_decimal') || element.classList.contains('o_decimal') ||
element.hasAttribute('data-decimal-processed') || element.hasAttribute('data-decimal-processed') ||
element.hasAttribute('data-owl-updating')) return false; element.hasAttribute('data-owl-updating')) return false;
// CRITICAL: Skip any editable elements or elements that might become editable // CRITICAL: Skip any editable elements or elements that might become editable
if (element.isContentEditable || if (element.isContentEditable ||
element.closest('.o_field_widget:not(.o_readonly_modifier)') || element.closest('.o_field_widget:not(.o_readonly_modifier)') ||
element.closest('[contenteditable="true"]') || element.closest('[contenteditable="true"]') ||
element.closest('input') || element.closest('input') ||
@ -24,88 +24,96 @@ function safelyApplyDecimalStyling(element) {
element.hasAttribute('contenteditable')) { element.hasAttribute('contenteditable')) {
return false; return false;
} }
try { try {
const text = element.textContent.trim(); const text = element.textContent.trim();
if (!text) return false; if (!text) return false;
// Mark as processed to avoid conflicts // Mark as processed to avoid conflicts
element.setAttribute('data-decimal-processed', 'true'); element.setAttribute('data-decimal-processed', 'true');
// Improved patterns that properly distinguish thousands separators from decimal separators // Improved patterns that properly distinguish thousands separators from decimal separators
const patterns = [ const patterns = [
// Currency with decimal: Rp 6,210,000.00 (comma for thousands, dot for decimal) // Currency with decimal: Rp 6,210,000.00 (comma for thousands, dot for decimal)
/^(.*Rp\s*)(\d{1,3}(?:,\d{3})*)\.(\d{2})(.*)$/, /^(.*Rp[\s\u00A0]*)(\d[\d,\s\u00A0]*)\.(\d{2})(.*)$/,
// Standard decimal with thousands: 1,234.56 (comma for thousands, dot for decimal) // Generic decimal with thousand separators (dot as decimal)
/^(.*)(\d{1,3}(?:,\d{3})*)\.(\d+)(.*)$/, /^(.*?)([\d,\s\u00A0]*\d)\.(\d+)(.*)$/,
// Simple decimal without thousands: 240.000, 123.45 // Simple decimal
/^(.*)(\d+)\.(\d+)(.*)$/ /^(.*?)(\d+)\.(\d+)(.*)$/
]; ];
for (const pattern of patterns) { for (const pattern of patterns) {
const match = text.match(pattern); const match = text.match(pattern);
if (match) { if (match) {
const [, prefix, integerPart, decimalPart, suffix] = match; const [, prefix, integerPart, decimalPart, suffix] = match;
console.log('Ultra-Safe Decimal Observer: Styling decimal number', text); // console.log('Ultra-Safe Decimal Observer: MATCH FOUND', {text, prefix, integerPart, decimalPart, suffix});
// Triple-check the element is safe to modify // Triple-check the element is safe to modify
if (element.textContent.trim() === text && // For tfoot, we are more permissive because they are always readonly
document.contains(element) && if (element.textContent.trim() === text &&
!element.closest('.o_field_widget:not(.o_readonly_modifier)')) { document.contains(element) &&
(!element.closest('.o_field_widget:not(.o_readonly_modifier)') || element.closest('tfoot'))) {
console.log('Ultra-Safe Decimal Observer: STYLING', text, element.tagName, element.className);
const newHTML = `${prefix || ''}${integerPart}<span class="o_decimal">.${decimalPart}</span>${suffix || ''}`; const newHTML = `${prefix || ''}${integerPart}<span class="o_decimal">.${decimalPart}</span>${suffix || ''}`;
element.innerHTML = newHTML; element.innerHTML = newHTML;
return true; return true;
} }
} }
} }
// Handle whole numbers in quantity contexts (be even more selective) // Handle whole numbers in quantity contexts (be even more selective)
// Only add decimals to numbers that are clearly quantities in readonly contexts // Only add decimals to numbers that are clearly quantities in readonly contexts
if (text.match(/^\d+$/) && text.length > 0 && text.length <= 4 && if (text.match(/^\d+$/) && text.length > 0 && text.length <= 4 &&
element.closest('.o_readonly_modifier') && ( element.closest('.o_readonly_modifier') && (
element.closest('[name="quantity"]') || element.closest('[name="quantity"]') ||
element.closest('[name="quantity_done"]') || element.closest('[name="quantity_done"]') ||
element.closest('[name="reserved_availability"]') element.closest('[name="reserved_availability"]')
)) { )) {
console.log('Ultra-Safe Decimal Observer: Adding decimals to readonly quantity', text); console.log('Ultra-Safe Decimal Observer: Adding decimals to readonly quantity', text);
// Triple-check before updating // Triple-check before updating
if (element.textContent.trim() === text && if (element.textContent.trim() === text &&
document.contains(element) && document.contains(element) &&
element.closest('.o_readonly_modifier')) { element.closest('.o_readonly_modifier')) {
element.innerHTML = `${text}<span class="o_decimal">.000</span>`; element.innerHTML = `${text}<span class="o_decimal">.000</span>`;
return true; return true;
} }
} }
// Do NOT process numbers with commas that don't have decimal points // Do NOT process numbers with commas that don't have decimal points
// These are likely thousands separators (e.g., 8,500 should stay as 8,500) // These are likely thousands separators (e.g., 8,500 should stay as 8,500)
if (text.match(/^\d{1,3}(?:,\d{3})+$/) && !text.includes('.')) { if (text.match(/^\d{1,3}(?:,\d{3})+$/) && !text.includes('.')) {
console.log('Ultra-Safe Decimal Observer: Skipping thousands separator number', text); console.log('Ultra-Safe Decimal Observer: Skipping thousands separator number', text);
return false; return false;
} }
} catch (error) { } catch (error) {
console.warn('Ultra-safe decimal styling error (non-critical):', error); console.warn('Ultra-safe decimal styling error (non-critical):', error);
// Remove the processing flag if there was an error // Remove the processing flag if there was an error
element.removeAttribute('data-decimal-processed'); element.removeAttribute('data-decimal-processed');
} }
return false; return false;
} }
// Ultra-safe processing of containers // Ultra-safe processing of containers
function ultraSafelyProcessContainer(container) { function ultraSafelyProcessContainer(container) {
if (!container || !document.contains(container)) return; if (!container || !document.contains(container)) return;
try { try {
// Only process elements in readonly contexts to avoid editable field conflicts // Select elements likely to contain formatted decimals in readonly contexts or footers
const elements = container.querySelectorAll('.o_readonly_modifier td:not([data-decimal-processed]), .o_readonly_modifier span:not([data-decimal-processed]), .o_field_monetary.o_readonly_modifier:not([data-decimal-processed]), .o_field_float.o_readonly_modifier:not([data-decimal-processed])'); const elements = container.querySelectorAll('.o_readonly_modifier td:not([data-decimal-processed]), .o_readonly_modifier span:not([data-decimal-processed]), tfoot td:not([data-decimal-processed]), tfoot span:not([data-decimal-processed]), .o_list_number:not([data-decimal-processed])');
elements.forEach(element => { elements.forEach(element => {
// Only process leaf elements in readonly contexts // Optimization: If a TD has a SPAN, we prefer to style the SPAN to preserve tooltips
if ((element.children.length === 0 || if (element.tagName === 'TD' && element.querySelector('span')) {
return;
}
// Only process leaf elements or elements with very simple structures
if ((element.children.length === 0 ||
(element.children.length === 1 && element.children[0].tagName === 'SPAN')) && (element.children.length === 1 && element.children[0].tagName === 'SPAN')) &&
!element.hasAttribute('data-owl-updating') && !element.hasAttribute('data-owl-updating') &&
!element.closest('.o_field_widget:not(.o_readonly_modifier)')) { !element.closest('.o_field_widget:not(.o_readonly_modifier)')) {
@ -144,18 +152,18 @@ const ultraSafeObserver = new MutationObserver((mutations) => {
// Start ultra-safe observing // Start ultra-safe observing
function startUltraSafeObserver() { function startUltraSafeObserver() {
console.log('Ultra-Safe Decimal Observer: Starting ultra-conservative observation'); console.log('Ultra-Safe Decimal Observer: Starting ultra-conservative observation');
// Process existing content safely with delay // Process existing content safely with delay
setTimeout(() => { setTimeout(() => {
ultraSafelyProcessContainer(document.body); ultraSafelyProcessContainer(document.body);
}, 1000); // Initial delay to let everything load }, 1000); // Initial delay to let everything load
// Start observing for new content with very reduced frequency // Start observing for new content with very reduced frequency
ultraSafeObserver.observe(document.body, { ultraSafeObserver.observe(document.body, {
childList: true, childList: true,
subtree: true subtree: true
}); });
// Much less frequent periodic processing to reduce conflicts // Much less frequent periodic processing to reduce conflicts
setInterval(() => { setInterval(() => {
ultraSafelyProcessContainer(document.body); ultraSafelyProcessContainer(document.body);