From 16e7b7e6e569f4d6c0f827bc455e9dfb362210ea Mon Sep 17 00:00:00 2001 From: StarFleetCPTN Date: Mon, 7 Apr 2025 11:21:11 -0700 Subject: [PATCH] refactor: Improve toast notification rendering and event handling - Refactored the ShowToastJS function to create toast elements using DOM methods for better safety and maintainability. - Changed the event listener for the 'showToast' event from document.body to document for improved event handling. - Ensured that the message content is set using textContent to prevent potential XSS vulnerabilities. --- components/shared/toast/toast_js.templ | 47 ++++++++++++++++---------- static/js/app.js | 2 +- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/components/shared/toast/toast_js.templ b/components/shared/toast/toast_js.templ index 5c6b8ec..599ee2b 100644 --- a/components/shared/toast/toast_js.templ +++ b/components/shared/toast/toast_js.templ @@ -33,22 +33,36 @@ templ ShowToastJS() { textColorClass = 'text-blue-500 dark:text-blue-200'; } - // Set inner HTML with appropriate icon and message - toast.innerHTML = ` -
- ${type === 'success' - ? '' - : type === 'error' - ? '' - : ''} -
-
${message}
- + // Create icon div + const iconDiv = document.createElement('div'); + iconDiv.className = `inline-flex items-center justify-center flex-shrink-0 w-8 h-8 rounded-lg ${iconClass}`; + iconDiv.innerHTML = type === 'success' + ? '' + : type === 'error' + ? '' + : ''; + + // Create message div and set text content safely + const messageDiv = document.createElement('div'); + messageDiv.className = 'ml-3 text-sm font-normal'; + messageDiv.textContent = message; // Use textContent for safety + + // Create close button + const closeButton = document.createElement('button'); // Keep this declaration + closeButton.type = 'button'; + closeButton.className = 'ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700'; + closeButton.setAttribute('data-dismiss-target', `#${toast.id}`); + closeButton.setAttribute('aria-label', 'Close'); + closeButton.innerHTML = ` + Close + `; + // Append elements to the toast + toast.appendChild(iconDiv); + toast.appendChild(messageDiv); + toast.appendChild(closeButton); + // Add toast to container toastContainer.appendChild(toast); @@ -58,9 +72,8 @@ templ ShowToastJS() { toast.classList.add('translate-y-0', 'opacity-100'); }, 10); - // Add event listener to close button - const closeButton = toast.querySelector('button[data-dismiss-target]'); - closeButton.addEventListener('click', function() { + // Add event listener to the close button we created earlier + closeButton.addEventListener('click', function() { // Use the existing closeButton variable // Animate out before removing toast.classList.add('opacity-0', 'translate-y-4'); setTimeout(() => { diff --git a/static/js/app.js b/static/js/app.js index e10a336..a3226fc 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -449,7 +449,7 @@ function enhanceMobileForms() { // Listen for custom 'showToast' event triggered by HX-Trigger -document.body.addEventListener('showToast', function(event) { +document.addEventListener('showToast', function(event) { // Changed from document.body // Debug logs removed if (event.detail && event.detail.message && event.detail.type) { // Call the globally defined showToast function from toast_js.templ