PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.6.1
MxChat – AI Chatbot & Content Generation for WordPress v1.6.1
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | js/chat-script.js +88 -197 2.0.41.6.1 View file →
@@ -1,8 +1,8 @@
1 1 jQuery(document).ready(function($) {
2 2 //console.log('mxchatChat object:', mxchatChat);
3 3 //console.log('Link Target Toggle Value:', mxchatChat.link_target_toggle);
4 -// Add these variables at the top of your chat-script.js file
4 +
5 5 const toolbarIconColor = mxchatChat.toolbar_icon_color || '#212121';
6 6
7 7 // Initialize color settings
8 8 var userMessageBgColor = mxchatChat.user_message_bg_color;
@@ -14,11 +14,9 @@
14 14 var liveAgentMessageFontColor = mxchatChat.live_agent_message_font_color;
15 15
16 16
17 17 var linkTarget = mxchatChat.link_target_toggle === 'on' ? '_blank' : '_self';
18 - let lastSeenMessageId = '';
19 - let notificationCheckInterval;
20 - let notificationBadge;
18 + var lastSeenMessageId = '';
21 19 // Initialize session ID
22 20 var sessionId = getChatSession();
23 21
24 22 let pollingInterval; // Variable to store the interval ID
@@ -28,107 +26,10 @@
28 26 let activePdfFile = null;
29 27 let activeWordFile = null;
30 28
31 29
32 -// Function to create and append notification badge
33 -// Function to create and append notification badge
34 -function createNotificationBadge() {
35 - console.log("Creating notification badge...");
36 - const chatButton = document.getElementById('floating-chatbot-button');
37 - console.log("Chat button found:", !!chatButton);
38 -
39 - if (!chatButton) return;
40 30
41 - // Remove any existing badge first
42 - const existingBadge = chatButton.querySelector('.chat-notification-badge');
43 - if (existingBadge) {
44 - console.log("Removing existing badge");
45 - existingBadge.remove();
46 - }
47 31
48 - notificationBadge = document.createElement('div');
49 - notificationBadge.className = 'chat-notification-badge';
50 - notificationBadge.style.cssText = `
51 - display: none;
52 - position: absolute;
53 - top: -5px;
54 - right: -5px;
55 - background-color: red;
56 - color: white;
57 - border-radius: 50%;
58 - padding: 4px 8px;
59 - font-size: 12px;
60 - font-weight: bold;
61 - z-index: 10001;
62 - `;
63 - chatButton.style.position = 'relative';
64 - chatButton.appendChild(notificationBadge);
65 -
66 - console.log("Notification badge created and appended:", {
67 - exists: !!notificationBadge,
68 - parent: notificationBadge?.parentNode?.id,
69 - display: notificationBadge?.style?.display
70 - });
71 -}
72 -
73 -// Function to check for new messages
74 -function checkForNewMessages() {
75 - const sessionId = getChatSession();
76 - const chatPersistenceEnabled = mxchatChat.chat_persistence_toggle === 'on';
77 -
78 - if (!chatPersistenceEnabled) return;
79 -
80 - $.ajax({
81 - url: mxchatChat.ajax_url,
82 - type: 'POST',
83 - data: {
84 - action: 'mxchat_check_new_messages',
85 - session_id: sessionId,
86 - last_seen_id: lastSeenMessageId,
87 - nonce: mxchatChat.nonce
88 - },
89 - success: function(response) {
90 - if (response.success && response.data.hasNewMessages) {
91 - showNotification();
92 - }
93 - }
94 - });
95 -}
96 -
97 -// Function to show notification
98 -function showNotification() {
99 - const badge = document.getElementById('chat-notification-badge');
100 - if (badge && $('#floating-chatbot').hasClass('hidden')) {
101 - badge.style.display = 'block';
102 - badge.textContent = '1';
103 - }
104 -}
105 -
106 -function hideNotification() {
107 - const badge = document.getElementById('chat-notification-badge');
108 - if (badge) {
109 - badge.style.display = 'none';
110 - }
111 -}
112 -// Function to start notification checking
113 -function startNotificationChecking() {
114 - const chatPersistenceEnabled = mxchatChat.chat_persistence_toggle === 'on';
115 - if (!chatPersistenceEnabled) return;
116 -
117 - createNotificationBadge();
118 - notificationCheckInterval = setInterval(checkForNewMessages, 30000); // Check every 30 seconds
119 -}
120 -
121 -// Function to stop notification checking
122 -function stopNotificationChecking() {
123 - if (notificationCheckInterval) {
124 - clearInterval(notificationCheckInterval);
125 - }
126 -}
127 -
128 -
129 -
130 -
131 32 function getChatSession() {
132 33 var sessionId = getCookie('mxchat_session_id');
133 34 //console.log("Session ID retrieved from cookie: ", sessionId);
134 35
@@ -256,35 +157,24 @@
256 157 sendMessageToChatbot(question);
257 158 });
258 159
259 160
260 -// Add this new function to handle markdown headers
261 -function formatMarkdownHeaders(text) {
262 - // Handle h1 to h6 headers
263 - return text.replace(/^(#{1,6})\s(.+)$/gm, function(match, hashes, content) {
264 - const level = hashes.length;
265 - return `<h${level} class="chat-heading">${content}</h${level}>`;
266 - });
267 -}
268 -
269 -// Update the linkify function to handle both URLs and markdown
161 +// Use the linkTarget in your linkify function
270 162 function linkify(inputText) {
271 - // First process markdown headers
272 - let processedText = formatMarkdownHeaders(inputText);
273 -
274 - // Then process links as before
163 + // Check for already linked URLs and skip them
164 + // We use negative lookaheads to skip anything already in an <a> tag
275 165 var markdownLinkPattern = /\[([^\]]+)\]\((https?:\/\/[^\s]+)\)/g;
276 - processedText = processedText.replace(markdownLinkPattern, '<a href="$2" target="' + linkTarget + '">$1</a>');
166 + var replacedText = inputText.replace(markdownLinkPattern, '<a href="$2" target="' + linkTarget + '">$1</a>');
277 167
278 168 // Replace standalone URLs not already in an <a> tag
279 169 var urlPattern = /(^|[^">])(https?:\/\/[^\s<]+)/gim;
280 - processedText = processedText.replace(urlPattern, '$1<a href="$2" target="' + linkTarget + '">$2</a>');
170 + replacedText = replacedText.replace(urlPattern, '$1<a href="$2" target="' + linkTarget + '">$2</a>');
281 171
282 172 // Replace "www." prefixed URLs not already in an <a> tag
283 173 var wwwPattern = /(^|[^">])(www\.[\S]+(\b|$))(?![^<]*<\/a>)/gim;
284 - processedText = processedText.replace(wwwPattern, '$1<a href="http://$2" target="' + linkTarget + '">$2</a>');
174 + replacedText = replacedText.replace(wwwPattern, '$1<a href="http://$2" target="' + linkTarget + '">$2</a>');
285 175
286 - return processedText;
176 + return replacedText;
287 177 }
288 178
289 179
290 180 function scrollElementToTop(element) {
@@ -366,8 +256,10 @@
366 256 }
367 257 }
368 258
369 259 function callMxChat(message, callback) {
260 + //console.log("Sending message to chatbot:", message);
261 +
370 262 $.ajax({
371 263 url: mxchatChat.ajax_url,
372 264 type: 'POST',
373 265 dataType: 'json',
@@ -377,26 +269,41 @@
377 269 session_id: getChatSession(),
378 270 nonce: mxchatChat.nonce
379 271 },
380 272 success: function(response) {
381 - // Existing chat mode check
273 + //console.log("callMxChat response:", response);
274 +
275 + // Check for chat_mode in the response
382 276 if (response.chat_mode) {
383 277 updateChatModeIndicator(response.chat_mode);
384 278 }
279 + // Also check in fallbackResponse if exists
385 280 else if (response.fallbackResponse && response.fallbackResponse.chat_mode) {
386 281 updateChatModeIndicator(response.fallbackResponse.chat_mode);
387 282 }
388 -
389 283 // Add PDF filename handling
390 284 if (response.data && response.data.filename) {
391 285 showActivePdf(response.data.filename);
392 286 activePdfFile = response.data.filename;
393 287 }
288 + // Add redirect check here
289 + if (response.redirect_url) {
290 + // Show the message first
291 + let responseText = response.text || '';
292 + if (responseText) {
293 + replaceLastMessage("bot", responseText);
294 + }
295 + // Then redirect after a short delay
296 + setTimeout(() => {
297 + window.location.href = response.redirect_url;
298 + }, 1500);
299 + return; // Exit early since we're redirecting
300 + }
394 301
395 -
396 302 // Check for live agent response
397 303 if (response.success && response.data && response.data.status === 'waiting_for_agent') {
398 304 updateChatModeIndicator('agent');
305 + // Do not replace the thinking dots; just wait for the agent's actual response
399 306 return;
400 307 }
401 308
402 309 // Handle other responses
@@ -403,33 +310,31 @@
403 310 let responseText = response.text || '';
404 311 let responseHtml = response.html || '';
405 312 let responseMessage = response.message || '';
406 313
314 + // Check for mode change in text response
407 315 if (responseText === 'You are now chatting with the AI chatbot.') {
408 316 updateChatModeIndicator('ai');
409 317 }
410 318
411 - // Handle the message and show notification if chat is hidden
412 - if (responseText || responseHtml || responseMessage) {
413 - // Update the messages as before
414 - if (responseText && responseHtml) {
415 - replaceLastMessage("bot", responseText, responseHtml);
416 - } else if (responseText) {
417 - replaceLastMessage("bot", responseText);
418 - } else if (responseHtml) {
419 - replaceLastMessage("bot", "", responseHtml);
420 - } else if (responseMessage) {
421 - replaceLastMessage("bot", responseMessage);
422 - }
423 -
424 - // Check if chat is hidden and show notification
425 - if ($('#floating-chatbot').hasClass('hidden')) {
426 - const badge = $('#chat-notification-badge');
427 - if (badge.length) {
428 - badge.show();
429 - }
430 - }
431 - } else {
319 + // For product card or chatbot responses with HTML
320 + if (responseText && responseHtml) {
321 + replaceLastMessage("bot", responseText, responseHtml);
322 + }
323 + // For regular chatbot responses with just text
324 + else if (responseText) {
325 + replaceLastMessage("bot", responseText);
326 + }
327 + // For responses with only HTML (like product cards)
328 + else if (responseHtml) {
329 + replaceLastMessage("bot", "", responseHtml);
330 + }
331 + // For legacy message format
332 + else if (responseMessage) {
333 + replaceLastMessage("bot", responseMessage);
334 + }
335 + // Fallback error case
336 + else {
432 337 console.error("Unexpected response format:", response);
433 338 replaceLastMessage("bot", "I'm sorry, something went wrong.");
434 339 }
435 340
@@ -437,8 +342,9 @@
437 342 lastSeenMessageId = response.message_id;
438 343 }
439 344 },
440 345 error: function(xhr, status, error) {
346 + //console.log("Error communicating with the server:", xhr.status, error);
441 347 replaceLastMessage("bot", "An unexpected error occurred.");
442 348 }
443 349 });
444 350 }
@@ -516,12 +422,12 @@
516 422 }
517 423 }
518 424 });
519 425
426 + // Update the last seen message ID if applicable
520 427 if (messageText.id) {
521 - lastSeenMessageId = messageText.id;
522 - hideNotification();
523 - }
428 + lastSeenMessageId = messageText.id;
429 + }
524 430 } catch (error) {
525 431 console.error("Error rendering message with images:", error);
526 432 }
527 433 }
@@ -574,17 +480,14 @@
574 480 'color': fontColor,
575 481 })
576 482 .removeClass('temporary-message')
577 483 .fadeIn(200, function() {
484 + // After message is displayed, scroll last user message to top
578 485 if (sender === "bot" || sender === "agent") {
579 486 const lastUserMessage = $('#chat-box').find('.user-message').last();
580 487 if (lastUserMessage.length) {
581 488 scrollElementToTop(lastUserMessage);
582 489 }
583 - // Show notification if chat is hidden
584 - if ($('#floating-chatbot').hasClass('hidden')) {
585 - showNotification();
586 - }
587 490 }
588 491 });
589 492 });
590 493 } else {
@@ -609,11 +512,11 @@
609 512 }
610 513 }
611 514
612 515
613 -// Update your checkForAgentMessages function
614 516 function checkForAgentMessages() {
615 517 const sessionId = getChatSession();
518 +
616 519 $.ajax({
617 520 url: mxchatChat.ajax_url,
618 521 type: 'POST',
619 522 dataType: 'json',
@@ -623,24 +526,17 @@
623 526 last_seen_id: lastSeenMessageId,
624 527 nonce: mxchatChat.nonce
625 528 },
626 529 success: function (response) {
530 + //console.log("Agent messages polling response:", response);
627 531 if (response.success && response.data?.new_messages) {
628 - let hasNewMessage = false;
629 -
630 532 response.data.new_messages.forEach(function (message) {
631 533 if (message.role === "agent" && !processedMessageIds.has(message.id)) {
632 - hasNewMessage = true;
633 534 replaceLastMessage("agent", message.content);
634 535 lastSeenMessageId = message.id;
635 536 processedMessageIds.add(message.id);
636 537 }
637 538 });
638 -
639 - if (hasNewMessage && $('#floating-chatbot').hasClass('hidden')) {
640 - showNotification();
641 - }
642 -
643 539 scrollToBottom(true);
644 540 }
645 541 },
646 542 error: function (xhr, status, error) {
@@ -767,37 +663,29 @@
767 663 return textArea.value;
768 664 }
769 665
770 666
771 -// Update formatCodeBlocks function
772 667 function formatCodeBlocks(text) {
773 - // First handle raw PHP tags
774 - text = text.replace(/(<\?php[\s\S]*?\?>)/g, (match) => {
775 - return `<pre><code class="language-php">${escapeHtml(match)}</code></pre>`;
776 - });
668 + // Ensure the input is a string; otherwise, convert or return empty
669 + if (typeof text !== 'string') {
670 + console.error("formatCodeBlocks: Input is not a string:", text);
671 + return typeof text === 'object' && text.text ? text.text : ""; // Use .text if available, else empty
672 + }
777 673
778 - // Then handle code blocks with backticks
779 - text = text.replace(/```php5?\n([\s\S]+?)```/gi, (match, code) => {
780 - return `<pre><code class="language-php">${escapeHtml(code)}</code></pre>`;
674 + const codeBlockPattern = /```(\w+)?\n?([\s\S]+?)```/g;
675 +
676 + return text.replace(codeBlockPattern, (_, language, codeContent) => {
677 + language = language || 'plaintext';
678 +
679 + return `
680 + <div class="mxchat-code-block-container">
681 + <button class="mxchat-copy-button" aria-label="Copy to clipboard">Copy</button>
682 + <pre class="mxchat-code-block"><code class="mxchat-language-${language}">${escapeHtml(codeContent)}</code></pre>
683 + </div>`;
781 684 });
685 +}
782 686
783 - return text;
784 -}
785 687
786 -// Update escapeHtml function to preserve existing code blocks
787 -function escapeHtml(unsafe) {
788 - // First check if it's already a code block
789 - if (unsafe.includes('<pre><code') || unsafe.includes('</code></pre>')) {
790 - return unsafe;
791 - }
792 -
793 - return unsafe
794 - .replace(/&/g, "&amp;")
795 - .replace(/</g, "&lt;")
796 - .replace(/>/g, "&gt;")
797 - .replace(/"/g, "&quot;")
798 - .replace(/'/g, "&#039;");
799 -}
800 688 // Utility function to escape HTML
801 689 function escapeHtml(unsafe) {
802 690 return unsafe
803 691 .replace(/&/g, "&amp;")
@@ -811,18 +699,20 @@
811 699
812 700
813 701 // Function to convert newlines, skipping preformatted text
814 702 function convertNewlinesToBreaks(text) {
815 - // Split while preserving code blocks
816 - return text.split(/(<pre\b[^>]*>[\s\S]*?<\/pre>)/g).map(part => {
817 - if (part.startsWith('<pre')) return part;
818 - return part.replace(/(^|[^>])\n/g, '$1<br>');
819 - }).join('');
703 + // Regex to exclude <pre> and <code> tags from adding <br> tags
704 + return text.replace(/(^|[^>])\n/g, '$1<br>');
820 705 }
821 706
822 707
823 708
709 +$(document).ready(function() {
710 + loadChatHistory();
711 +});
824 712
713 +
714 +
825 715 // Helper function to check if a string is an image HTML
826 716 function isImageHtml(str) {
827 717 return str.startsWith('<img') && str.endsWith('>');
828 718 }
@@ -914,11 +804,15 @@
914 804 // Also check pre-chat message when Complianz is not enabled
915 805 checkPreChatDismissal();
916 806 }
917 807 }
808 +// Initialize when document is ready
809 +$(document).ready(function() {
810 + //console.log('Document ready - starting initialization');
811 + initializeChatVisibility();
812 +});
918 813
919 814
920 -
921 815 function checkConsentAndShowChat() {
922 816 var consentStatus = cmplz_has_consent('marketing');
923 817 var consentType = complianz.consenttype;
924 818
@@ -985,15 +879,16 @@
985 879 var chatbot = $('#floating-chatbot');
986 880 if (chatbot.hasClass('hidden')) {
987 881 chatbot.removeClass('hidden').addClass('visible');
988 882 $(this).addClass('hidden');
989 - $('#chat-notification-badge').hide(); // Hide notification when opening chat
990 883 disableScroll();
884 + // Hide the pre-chat message without dismissing it
991 885 $('#pre-chat-message').fadeOut(250);
992 886 } else {
993 887 chatbot.removeClass('visible').addClass('hidden');
994 888 $(this).removeClass('hidden');
995 889 enableScroll();
890 + // Show the pre-chat message again if it hasn't been dismissed
996 891 checkPreChatDismissal();
997 892 }
998 893 });
999 894
@@ -1032,10 +927,12 @@
1032 927 $(':root').css('--vh', vh + 'px');
1033 928 }
1034 929
1035 930 // Set the height when the page loads
931 + $(document).ready(function() {
932 + setFullHeight();
933 + });
1036 934
1037 -
1038 935 // Set the height on resize and orientation change events
1039 936 $(window).on('resize orientationchange', function() {
1040 937 setFullHeight();
1041 938 });
@@ -1520,15 +1417,9 @@
1520 1417 console.error('Essential elements for email handling are missing.');
1521 1418 }
1522 1419
1523 1420
1524 -// Initialize when document is ready
1525 -$(document).ready(function() {
1526 - setFullHeight();
1527 - initializeChatVisibility();
1528 - loadChatHistory();
1529 1421
1530 -});
1531 1422
1532 1423 });
1533 1424
1534 1425 // Event listener for copy button