const tooltipElementId = "mmt-app" function bindTooltipsWithDelegation() { // To display the tooltip, the attribute 'data-tooltip' is mandatory => it contains the text to tooltip // Then // the 'truncate' to show only when the text is truncated // the class 'mmt-tooltip' for force the display const elementId = tooltipElementId console.debug("bindTooltips on element " + elementId); const element = document.getElementById(elementId); const tooltipContainer = document.getElementById(`tt_${elementId}`); if (!element) { console.error(`Invalid element '${elementId}' container`); return; } if (!tooltipContainer) { console.error(`Invalid tooltip 'tt_${elementId}' container.`); return; } // Add a single mouseenter and mouseleave listener to the parent element element.addEventListener("mouseenter", (event) => { //console.debug("Entering element", event.target) const cell = event.target.closest("[data-tooltip]"); if (!cell) { // console.debug(" No 'data-tooltip' attribute found. Stopping."); return; } const no_tooltip = element.hasAttribute("mmt-no-tooltip"); if (no_tooltip) { // console.debug(" Attribute 'mmt-no-tooltip' found. Cancelling."); return; } const content = cell.querySelector(".truncate") || cell; const isOverflowing = content.scrollWidth > content.clientWidth; const forceShow = cell.classList.contains("mmt-tooltip"); if (isOverflowing || forceShow) { const tooltipText = cell.getAttribute("data-tooltip"); if (tooltipText) { const rect = cell.getBoundingClientRect(); const tooltipRect = tooltipContainer.getBoundingClientRect(); let top = rect.top - 30; // Above the cell let left = rect.left; // Adjust tooltip position to prevent it from going off-screen if (top < 0) top = rect.bottom + 5; // Move below if no space above if (left + tooltipRect.width > window.innerWidth) { left = window.innerWidth - tooltipRect.width - 5; // Prevent overflow right } // Apply styles for tooltip positioning requestAnimationFrame(() => { tooltipContainer.textContent = tooltipText; tooltipContainer.setAttribute("data-visible", "true"); tooltipContainer.style.top = `${top}px`; tooltipContainer.style.left = `${left}px`; }); } } }, true); // Use capture phase for better delegation if needed element.addEventListener("mouseleave", (event) => { const cell = event.target.closest("[data-tooltip]"); if (cell) { tooltipContainer.setAttribute("data-visible", "false"); } }, true); // Use capture phase for better delegation if needed } function disableTooltip() { const elementId = tooltipElementId // console.debug("disableTooltip on element " + elementId); const element = document.getElementById(elementId); if (!element) { console.error(`Invalid element '${elementId}' container`); return; } element.setAttribute("mmt-no-tooltip", ""); } function enableTooltip() { const elementId = tooltipElementId // console.debug("enableTooltip on element " + elementId); const element = document.getElementById(elementId); if (!element) { console.error(`Invalid element '${elementId}' container`); return; } element.removeAttribute("mmt-no-tooltip"); } // Function to save form data to browser storage and track user input in real time function saveFormData(formId) { const form = document.getElementById(formId); if (!form) { console.error(`Form with ID '${formId}' not found`); return; } const storageKey = `formData_${formId}`; // Function to save current form state function saveCurrentState() { const formData = {}; // Get all input elements const inputs = form.querySelectorAll('input, select, textarea'); inputs.forEach(input => { if (input.type === 'checkbox' || input.type === 'radio') { formData[input.name || input.id] = input.checked; } else { formData[input.name || input.id] = input.value; } }); // Store in browser storage const dataToStore = { timestamp: new Date().toISOString(), data: formData }; try { localStorage.setItem(storageKey, JSON.stringify(dataToStore)); } catch (error) { console.error('Error saving form data:', error); } } // Add event listeners for real-time tracking const inputs = form.querySelectorAll('input, select, textarea'); inputs.forEach(input => { // For text inputs, textareas, and selects if (input.type === 'text' || input.type === 'email' || input.type === 'password' || input.type === 'number' || input.type === 'tel' || input.type === 'url' || input.tagName === 'TEXTAREA' || input.tagName === 'SELECT') { // Use 'input' event for real-time tracking input.addEventListener('input', saveCurrentState); // Also use 'change' event as fallback input.addEventListener('change', saveCurrentState); } // For checkboxes and radio buttons if (input.type === 'checkbox' || input.type === 'radio') { input.addEventListener('change', saveCurrentState); } }); // Save initial state saveCurrentState(); console.debug(`Real-time form tracking enabled for form: ${formId}`); } // Function to restore form data from browser storage function restoreFormData(formId) { const form = document.getElementById(formId); if (!form) { console.error(`Form with ID '${formId}' not found`); return; } const storageKey = `formData_${formId}`; try { const storedData = localStorage.getItem(storageKey); if (storedData) { const parsedData = JSON.parse(storedData); const formData = parsedData.data; // Restore all input values const inputs = form.querySelectorAll('input, select, textarea'); inputs.forEach(input => { const key = input.name || input.id; if (formData.hasOwnProperty(key)) { if (input.type === 'checkbox' || input.type === 'radio') { input.checked = formData[key]; } else { input.value = formData[key]; } } }); } } catch (error) { console.error('Error restoring form data:', error); } } function bindFormData(formId) { console.debug("bindFormData on form " + (formId)); restoreFormData(formId); saveFormData(formId); } // Function to clear saved form data function clearFormData(formId) { const storageKey = `formData_${formId}`; try { localStorage.removeItem(storageKey); console.log(`Cleared saved data for form: ${formId}`); } catch (error) { console.error('Error clearing form data:', error); } }