| @@ -265,10 +265,9 @@ | ||
| 265 | 265 | return `<h${level} class="chat-heading">${content}</h${level}>`; |
| 266 | 266 | }); |
| 267 | 267 | } |
| 268 | 268 | |
| 269 | -// Update the linkify function to handle both URLs and markdown | |
| 270 | -// Modified linkify function that only processes URLs in user content | |
| 269 | +// Update the linkify function to handle URLs, markdown, and phone numbers | |
| 271 | 270 | function linkify(inputText) { |
| 272 | 271 | if (!inputText) return ''; |
| 273 | 272 | |
| 274 | 273 | // Process markdown headers |
| @@ -281,8 +280,16 @@ | ||
| 281 | 280 | const safeText = sanitizeUserInput(text); |
| 282 | 281 | return `<a href="${safeUrl}" target="${linkTarget}">${safeText}</a>`; |
| 283 | 282 | }); |
| 284 | 283 | |
| 284 | + // Process phone numbers (tel:) | |
| 285 | + const phonePattern = /\[([^\]]+)\]\((tel:[\d+]+)\)/g; | |
| 286 | + processedText = processedText.replace(phonePattern, (match, text, phone) => { | |
| 287 | + const safePhone = encodeURI(phone); | |
| 288 | + const safeText = sanitizeUserInput(text); | |
| 289 | + return `<a href="${safePhone}">${safeText}</a>`; | |
| 290 | + }); | |
| 291 | + | |
| 285 | 292 | // Process standalone URLs |
| 286 | 293 | const urlPattern = /(^|[^">])(https?:\/\/[^\s<]+)/gim; |
| 287 | 294 | processedText = processedText.replace(urlPattern, (match, prefix, url) => { |
| 288 | 295 | const safeUrl = encodeURI(url); |
| @@ -298,9 +305,8 @@ | ||
| 298 | 305 | |
| 299 | 306 | return processedText; |
| 300 | 307 | } |
| 301 | 308 | |
| 302 | - | |
| 303 | 309 | function scrollElementToTop(element) { |
| 304 | 310 | var chatBox = $('#chat-box'); |
| 305 | 311 | var elementTop = element.position().top + chatBox.scrollTop(); |
| 306 | 312 | chatBox.animate({ scrollTop: elementTop }, 500); |
| @@ -367,11 +373,17 @@ | ||
| 367 | 373 | |
| 368 | 374 | function updateChatModeIndicator(mode) { |
| 369 | 375 | const indicator = document.getElementById('chat-mode-indicator'); |
| 370 | 376 | if (indicator) { |
| 371 | - indicator.textContent = mode === 'agent' ? 'Live Agent' : 'AI Agent'; | |
| 377 | + // For Live Agent, keep as is; for AI mode, use the customized text | |
| 378 | + if (mode === 'agent') { | |
| 379 | + indicator.textContent = 'Live Agent'; | |
| 380 | + } else { | |
| 381 | + // Get the custom AI agent text from a data attribute we'll add to the element | |
| 382 | + const customAiText = indicator.getAttribute('data-ai-text') || 'AI Agent'; | |
| 383 | + indicator.textContent = customAiText; | |
| 384 | + } | |
| 372 | 385 | } |
| 373 | - | |
| 374 | 386 | // Start or stop polling based on mode |
| 375 | 387 | if (mode === 'agent') { |
| 376 | 388 | startPolling(); |
| 377 | 389 | } else { |
| @@ -1129,10 +1141,18 @@ | ||
| 1129 | 1141 | document.getElementById('word-upload').click(); |
| 1130 | 1142 | }); |
| 1131 | 1143 | } |
| 1132 | 1144 | |
| 1145 | +function addSafeEventListener(elementId, eventType, handler) { | |
| 1146 | + const element = document.getElementById(elementId); | |
| 1147 | + if (element) { | |
| 1148 | + element.addEventListener(eventType, handler); | |
| 1149 | + } | |
| 1150 | +} | |
| 1151 | + | |
| 1152 | + | |
| 1133 | 1153 | // PDF file input change handler |
| 1134 | -document.getElementById('pdf-upload').addEventListener('change', async function(e) { | |
| 1154 | +addSafeEventListener('pdf-upload', 'change', async function(e) { | |
| 1135 | 1155 | const file = e.target.files[0]; |
| 1136 | 1156 | |
| 1137 | 1157 | if (!file || file.type !== 'application/pdf') { |
| 1138 | 1158 | alert('Please select a valid PDF file.'); |
| @@ -1204,9 +1224,9 @@ | ||
| 1204 | 1224 | } |
| 1205 | 1225 | }); |
| 1206 | 1226 | |
| 1207 | 1227 | // Word file input change handler |
| 1208 | -document.getElementById('word-upload').addEventListener('change', async function(e) { | |
| 1228 | +addSafeEventListener('word-upload', 'change', async function(e) { | |
| 1209 | 1229 | const file = e.target.files[0]; |
| 1210 | 1230 | |
| 1211 | 1231 | if (!file || file.type !== 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') { |
| 1212 | 1232 | alert('Please select a valid Word document (.docx).'); |
| @@ -1439,21 +1459,24 @@ | ||
| 1439 | 1459 | document.addEventListener('DOMContentLoaded', function() { |
| 1440 | 1460 | checkInitialDocumentStatus(); |
| 1441 | 1461 | }); |
| 1442 | 1462 | |
| 1443 | -// Style all toolbar elements | |
| 1444 | 1463 | const toolbarElements = [ |
| 1445 | 1464 | '#mxchat-chatbot .toolbar-btn svg', |
| 1446 | 1465 | '#mxchat-chatbot .active-pdf-name', |
| 1447 | 1466 | '#mxchat-chatbot .active-word-name', |
| 1448 | 1467 | '#mxchat-chatbot .remove-pdf-btn svg', |
| 1449 | - '#mxchat-chatbot .remove-word-btn svg' | |
| 1468 | + '#mxchat-chatbot .remove-word-btn svg', | |
| 1469 | + '#mxchat-chatbot .toolbar-perplexity svg' | |
| 1450 | 1470 | ]; |
| 1451 | -$(toolbarElements.join(', ')).css({ | |
| 1452 | - 'fill': toolbarIconColor, | |
| 1453 | - 'color': toolbarIconColor | |
| 1471 | + | |
| 1472 | +toolbarElements.forEach(selector => { | |
| 1473 | + $(selector).css({ | |
| 1474 | + 'fill': toolbarIconColor, | |
| 1475 | + 'stroke': toolbarIconColor, | |
| 1476 | + 'color': toolbarIconColor | |
| 1477 | + }); | |
| 1454 | 1478 | }); |
| 1455 | - | |
| 1456 | 1479 | |
| 1457 | 1480 | |
| 1458 | 1481 | // Ensure essential elements are defined |
| 1459 | 1482 | const emailForm = document.getElementById('email-collection-form'); |