226 lines
7.3 KiB
JavaScript
226 lines
7.3 KiB
JavaScript
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);
|
|
}
|
|
}
|