PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.2
MxChat – AI Chatbot & Content Generation for WordPress v1.2
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
mxchat-basic / js / chat-script.js

chat-script.js in MxChat – AI Chatbot & Content Generation for WordPress 1.2, at js/chat-script.js

562 lines 20.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(document).ready(function($) {
2 //console.log('mxchatChat object:', mxchatChat);
3
4 // Initialize color settings
5 var userMessageBgColor = mxchatChat.user_message_bg_color;
6 var userMessageFontColor = mxchatChat.user_message_font_color;
7 var botMessageBgColor = mxchatChat.bot_message_bg_color;
8 var botMessageFontColor = mxchatChat.bot_message_font_color;
9 var linkTarget = mxchatChat.link_target === 'on' ? '_blank' : '_self';
10
11
12
13 function getChatSession() {
14 var sessionId = getCookie('mxchat_session_id');
15 //console.log("Session ID retrieved from cookie: ", sessionId);
16
17 if (!sessionId) {
18 sessionId = generateSessionId();
19 //console.log("Generated new session ID: ", sessionId);
20 setChatSession(sessionId);
21 }
22
23 //console.log("Final session ID: ", sessionId);
24 return sessionId;
25 }
26
27 function setChatSession(sessionId) {
28 // Set the cookie with a 24-hour expiration (86400 seconds)
29 document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax";
30 }
31
32 // Get cookie value by name
33 function getCookie(name) {
34 let value = "; " + document.cookie;
35 let parts = value.split("; " + name + "=");
36 if (parts.length == 2) return parts.pop().split(";").shift();
37 }
38
39 // Generate a new session ID
40 function generateSessionId() {
41 return 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
42 }
43
44 // Function to send the message to the chatbot (backend)
45 function sendMessageToChatbot(message) {
46 var sessionId = getChatSession(); // Reuse the session ID logic
47
48 // Hide the popular questions section
49 $('#mxchat-popular-questions').hide();
50
51 // Show typing indicator (no need to append the user's message again)
52 appendThinkingMessage();
53 scrollToBottom();
54
55 console.log("Sending message to chatbot:", message); // Log the message
56 console.log("Session ID:", sessionId); // Log the session ID
57
58 // Call the chatbot using the same call logic as sendMessage
59 callMxChat(message, function(response) {
60 // Replace typing indicator with actual response
61 replaceLastMessage("bot", response);
62 });
63 }
64
65
66
67
68 // Function to handle sending a message
69 function sendMessage() {
70 var message = $('#chat-input').val();
71 if (message) {
72 appendMessage("user", message);
73 $('#chat-input').val('');
74
75 // Show typing indicator
76 appendThinkingMessage(); // Use this instead of appendMessage for the typing indicator
77 scrollToBottom(); // Add this line
78
79 callMxChat(message, function(response) {
80 // Replace typing indicator with actual response
81 replaceLastMessage("bot", response);
82 });
83 }
84 }
85
86 // Function to append a thinking message with animation
87 function appendThinkingMessage() {
88 // Remove any existing thinking dots first
89 $('.thinking-dots').remove();
90
91 // Retrieve the bot message font color and background color
92 var botMessageFontColor = mxchatChat.bot_message_font_color;
93 var botMessageBgColor = mxchatChat.bot_message_bg_color;
94
95 var thinkingHtml = '<div class="thinking-dots-container">' +
96 '<div class="thinking-dots">' +
97 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
98 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
99 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
100 '</div>' +
101 '</div>';
102
103 // Append the thinking dots to the chat container (or within the temporary message div)
104 $("#chat-box").append('<div class="bot-message temporary-message" style="background-color: ' + botMessageBgColor + ';">' + thinkingHtml + '</div>');
105 scrollToBottom();
106 }
107
108 // Trigger send button click when "Enter" key is pressed in the input field
109 $('#chat-input').keypress(function(e) {
110 if (e.which == 13) {
111 e.preventDefault();
112 $('#send-button').click();
113 }
114 });
115
116 // Handle send button click
117 $('#send-button').click(function() {
118 sendMessage();
119 });
120
121 // Handle click on popular questions
122 $('.mxchat-popular-question').on('click', function () {
123 var question = $(this).text(); // Get the text of the clicked question
124
125 // Append the question as if the user typed it
126 appendMessage("user", question);
127
128 // Send the question to the server (backend)
129 sendMessageToChatbot(question);
130 });
131
132
133 // Use the linkTarget in your linkify function
134 function linkify(inputText) {
135 // Convert Markdown-style links to HTML links first
136 var markdownLinkPattern = /\[([^\]]+)\]\(([^)]+)\)/g;
137 var replacedText = inputText.replace(markdownLinkPattern, '<a href="$2" target="' + linkTarget + '">$1</a>');
138
139 // URLs starting with http://, https://, or ftp://, but not already inside an <a> tag
140 var urlPattern = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[--A-Z0-9+&@#\/%=~_|])(?![^<]*<\/a>)/gim;
141 replacedText = replacedText.replace(urlPattern, '<a href="$1" target="' + linkTarget + '">$1</a>');
142
143 // URLs starting with "www." not already inside an <a> tag
144 var wwwPattern = /(^|[^\/])(www\.[\S]+(\b|$))(?![^<]*<\/a>)/gim;
145 replacedText = replacedText.replace(wwwPattern, '$1<a href="http://$2" target="' + linkTarget + '">$2</a>');
146
147 return replacedText;
148 }
149
150
151
152 // Updated appendMessage function with debugging
153 function appendMessage(sender, message, isTemporary = false) {
154 var messageClass = sender === "user" ? "user-message" : "bot-message";
155 var bgColor = sender === "user" ? userMessageBgColor : botMessageBgColor;
156 var fontColor = sender === "user" ? userMessageFontColor : botMessageFontColor;
157
158 var messageDiv = $('<div>').addClass(messageClass).css({
159 'background': bgColor,
160 'color': fontColor
161 }).html(linkify(formatBoldText(convertNewlinesToBreaks(message))));
162
163 if (isTemporary) {
164 messageDiv.addClass('temporary-message');
165 }
166
167 messageDiv.hide().appendTo('#chat-box').fadeIn(300);
168 scrollToBottom();
169 }
170
171
172 // Function to replace the last message in the chat
173 // Function to replace the last message in the chat
174 function replaceLastMessage(sender, newMessage) {
175 var messageClass = sender === "user" ? "user-message" : "bot-message";
176 var lastMessageDiv = $('#chat-box').find('.' + messageClass + '.temporary-message').last();
177
178 // Apply linkify, formatBoldText, and convertNewlinesToBreaks to the new message
179 var formattedMessage = linkify(formatBoldText(convertNewlinesToBreaks(newMessage)));
180
181 // Check if the new message is the rate limit message before replacing
182 if (newMessage === mxchatChat.rate_limit_message) {
183 // Append rate limit message without replacing anything
184 appendMessage("bot", formattedMessage);
185 return; // Exit the function to prevent replacing the rate limit message
186 }
187 if (lastMessageDiv.length) {
188 lastMessageDiv.fadeOut(200, function() {
189 // Replace the content with the formatted message
190 $(this).html(formattedMessage).removeClass('temporary-message').fadeIn(200);
191 });
192 } else {
193 appendMessage(sender, formattedMessage);
194 }
195 scrollToBottom();
196 }
197
198
199
200 // Optimized scrollToBottom function for instant scrolling
201 function scrollToBottom(instant = false) {
202 var chatBox = $('#chat-box');
203 if (instant) {
204 // Instantly set the scroll position to the bottom
205 chatBox.scrollTop(chatBox.prop("scrollHeight"));
206 } else {
207 // Use requestAnimationFrame for smoother scrolling if needed
208 let start = null;
209 const scrollHeight = chatBox.prop("scrollHeight");
210 const initialScroll = chatBox.scrollTop();
211 const distance = scrollHeight - initialScroll;
212 const duration = 500; // Duration in ms
213
214 function smoothScroll(timestamp) {
215 if (!start) start = timestamp;
216 const progress = timestamp - start;
217 const currentScroll = initialScroll + (distance * (progress / duration));
218 chatBox.scrollTop(currentScroll);
219
220 if (progress < duration) {
221 requestAnimationFrame(smoothScroll);
222 } else {
223 chatBox.scrollTop(scrollHeight); // Ensure it's exactly at the bottom
224 }
225 }
226
227 requestAnimationFrame(smoothScroll);
228 }
229 }
230
231
232 // Function to format text with **bold** inside double asterisks
233 function formatBoldText(text) {
234 return text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
235 }
236
237 // Function to convert newline characters to HTML line breaks and handle paragraph spacing
238 function convertNewlinesToBreaks(text) {
239 var lines = text.split('\n');
240 var formattedText = '';
241
242 for (var i = 0; i < lines.length; i++) {
243 formattedText += lines[i] + '<br>';
244 }
245
246 return formattedText;
247 }
248
249 // Copy to clipboard function
250 // Function to copy text to clipboard
251 function copyToClipboard(text) {
252 var tempInput = $('<input>');
253 $('body').append(tempInput);
254 tempInput.val(text).select();
255 document.execCommand('copy');
256 tempInput.remove();
257 }
258
259
260 // Initialize session ID
261 var sessionId = getChatSession();
262
263
264 function callMxChat(message, callback) {
265 var sessionId = getChatSession();
266 $.ajax({
267 url: mxchatChat.ajax_url,
268 type: 'POST',
269 dataType: 'json',
270 data: {
271 action: 'mxchat_handle_chat_request',
272 message: message,
273 session_id: sessionId,
274 nonce: mxchatChat.nonce
275 },
276 success: function(response) {
277 // Check for redirect_url in the response and redirect
278 if (response.redirect_url) {
279 window.location.href = response.redirect_url;
280 } else if (response.message) {
281 callback(response.message);
282 } else if (response.completion && response.completion.text) {
283 // Handle Claude's response format
284 callback(response.completion.text);
285 } else {
286 // Handle unknown response format
287 appendMessage("bot", "Sorry, I couldn't process the response.");
288 }
289 },
290 error: function(xhr, status, error) {
291 appendMessage("bot", "Error communicating with the server.");
292 }
293 });
294 }
295
296
297 function loadChatHistory() {
298 var sessionId = getChatSession();
299
300 var chatPersistenceEnabled = mxchatChat.chat_persistence_toggle === 'on'; // Reading from localized script
301
302 console.log("Chat persistence enabled: ", chatPersistenceEnabled);
303 console.log("Session ID for history loading: ", sessionId);
304
305 if (chatPersistenceEnabled && sessionId) {
306 console.log("Loading chat history for session ID:", sessionId);
307 $.ajax({
308 url: mxchatChat.ajax_url,
309 type: 'POST',
310 dataType: 'json',
311 data: {
312 action: 'mxchat_fetch_conversation_history',
313 session_id: sessionId
314 },
315 success: function(response) {
316 if (response.success && response.data && Array.isArray(response.data.conversation)) {
317 var $chatBox = $('#chat-box');
318 var $fragment = $(document.createDocumentFragment());
319
320 $.each(response.data.conversation, function(index, message) {
321 var messageElement = $('<div>').addClass(message.role === 'user' ? 'user-message' : 'bot-message')
322 .css({
323 'background': message.role === 'user' ? userMessageBgColor : botMessageBgColor,
324 'color': message.role === 'user' ? userMessageFontColor : botMessageFontColor
325 })
326 .html(linkify(formatBoldText(convertNewlinesToBreaks(message.content))));
327 $fragment.append(messageElement);
328 });
329
330 $chatBox.append($fragment);
331 scrollToBottom(true);
332
333 // Hide popular questions if chat history exists
334 if (response.data.conversation.length > 0) {
335 $('#mxchat-popular-questions').hide();
336 }
337
338 } else {
339 console.warn("No conversation history found.");
340 }
341 },
342 error: function(xhr, status, error) {
343 console.error("Error loading chat history:", status, error);
344 appendMessage("bot", "Unable to load chat history.");
345 }
346 });
347 } else {
348 console.warn("Chat persistence is disabled or no session ID found. Not loading history.");
349 }
350 }
351
352
353 $(document).ready(function() {
354 loadChatHistory();
355 });
356
357
358
359 // Helper function to check if a string is an image HTML
360 function isImageHtml(str) {
361 return str.startsWith('<img') && str.endsWith('>');
362 }
363
364 // Function to remove thinking dots
365 function removeThinkingDots() {
366 $('.thinking-dots').closest('.temporary-message').remove();
367 }
368
369 function isMobile() {
370 // This can be a simple check, or more sophisticated detection of mobile devices
371 return window.innerWidth <= 768; // Example threshold for mobile devices
372 }
373
374 function disableScroll() {
375 if (isMobile()) {
376 $('body').css('overflow', 'hidden');
377 }
378 }
379
380 function enableScroll() {
381 if (isMobile()) {
382 $('body').css('overflow', '');
383 }
384 }
385
386 // Function to show the chatbot widget (moved outside the Complianz logic)
387 function showChatWidget() {
388 setTimeout(function() {
389 $('#floating-chatbot-button').css('display', 'flex').fadeTo(500, 1);
390 }, 250);
391 }
392
393 // Function to hide the chatbot widget
394 function hideChatWidget() {
395 $('#floating-chatbot-button').css('display', 'none');
396 }
397
398 // Pre-chat dismissal check function (wrapped in a function for reuse)
399 function checkPreChatDismissal() {
400 $.ajax({
401 url: mxchatChat.ajax_url,
402 type: 'POST',
403 data: {
404 action: 'mxchat_check_pre_chat_message_status',
405 _ajax_nonce: mxchatChat.nonce
406 },
407 success: function(response) {
408 if (response.success && !response.data.dismissed) {
409 $('#pre-chat-message').fadeIn(250);
410 } else {
411 $('#pre-chat-message').hide();
412 }
413 },
414 error: function() {
415 console.error('Failed to check pre-chat message dismissal status.');
416 }
417 });
418 }
419
420 // Function to dismiss pre-chat message for 24 hours
421 function handlePreChatDismissal() {
422 $('#pre-chat-message').fadeOut(200);
423 $.ajax({
424 url: mxchatChat.ajax_url,
425 type: 'POST',
426 data: {
427 action: 'mxchat_dismiss_pre_chat_message',
428 _ajax_nonce: mxchatChat.nonce
429 },
430 success: function() {
431 $('#pre-chat-message').hide();
432 },
433 error: function() {
434 console.error('Failed to dismiss pre-chat message.');
435 }
436 });
437 }
438
439 // Handle pre-chat message dismissal on button click
440 $(document).on('click', '.close-pre-chat-message', function(e) {
441 e.stopPropagation();
442 handlePreChatDismissal();
443 });
444
445 // Function for Complianz logic
446 var applyComplianzLogic = mxchatChat.complianz_toggle;
447 if (applyComplianzLogic) {
448 function checkConsentAndShowChat() {
449 var consentStatus = typeof cmplz_has_consent === "function" && cmplz_has_consent('marketing');
450 var consentType = typeof complianz !== 'undefined' ? complianz.consenttype : null;
451
452 if (consentType === 'optin' && !consentStatus) {
453 hideChatWidget();
454 } else if (consentType === 'optout' && !consentStatus) {
455 hideChatWidget();
456 } else {
457 showChatWidget();
458 checkPreChatDismissal(); // Ensure we check dismissal after consent is handled
459 }
460 }
461
462 checkConsentAndShowChat();
463 $(document).on('cmplz_status_change', function(event, category) {
464 checkConsentAndShowChat();
465 });
466 } else {
467 showChatWidget();
468 checkPreChatDismissal(); // Always check pre-chat dismissal when consent logic is not applied
469 }
470
471 // Toggle chatbot visibility on floating button click
472 $(document).on('click', '#floating-chatbot-button', function() {
473 var chatbot = $('#floating-chatbot');
474 if (chatbot.hasClass('hidden')) {
475 chatbot.removeClass('hidden').addClass('visible');
476 $(this).addClass('hidden');
477 disableScroll();
478 handlePreChatDismissal();
479 } else {
480 chatbot.removeClass('visible').addClass('hidden');
481 $(this).removeClass('hidden');
482 enableScroll();
483 checkPreChatDismissal();
484 }
485 });
486
487 $(document).on('click', '#exit-chat-button', function() {
488 $('#floating-chatbot').addClass('hidden').removeClass('visible');
489 $('#floating-chatbot-button').removeClass('hidden');
490 enableScroll();
491 });
492
493 // Close pre-chat message on click
494 $(document).on('click', '.close-pre-chat-message', function(e) {
495 e.stopPropagation(); // Prevent triggering the parent .pre-chat-message click
496 $('#pre-chat-message').fadeOut(200, function() {
497 $(this).remove();
498 });
499 });
500
501 // Open chatbot when pre-chat message is clicked
502 $(document).on('click', '#pre-chat-message', function() {
503 var chatbot = $('#floating-chatbot');
504 if (chatbot.hasClass('hidden')) {
505 chatbot.removeClass('hidden').addClass('visible');
506 $('#floating-chatbot-button').addClass('hidden');
507 $('#pre-chat-message').fadeOut(250); // Hide pre-chat message
508 disableScroll(); // Disable scroll when chatbot opens
509 }
510 });
511
512 // If the chatbot is initially hidden, ensure the button is visible
513 if ($('#floating-chatbot').hasClass('hidden')) {
514 $('#floating-chatbot-button').removeClass('hidden');
515 }
516
517 function setFullHeight() {
518 var vh = $(window).innerHeight() * 0.01;
519 $(':root').css('--vh', vh + 'px');
520 }
521
522 // Set the height when the page loads
523 $(document).ready(function() {
524 setFullHeight();
525 });
526
527 // Set the height on resize and orientation change events
528 $(window).on('resize orientationchange', function() {
529 setFullHeight();
530 });
531
532
533 // Now handle the close button to dismiss the pre-chat message for 24 hours
534 var closeButton = document.querySelector('.close-pre-chat-message');
535 if (closeButton) {
536 closeButton.addEventListener('click', function() {
537 $('#pre-chat-message').fadeOut(200); // Hide the message
538
539 // Send an AJAX request to set the transient flag for 24 hours
540 $.ajax({
541 url: mxchatChat.ajax_url,
542 type: 'POST',
543 data: {
544 action: 'mxchat_dismiss_pre_chat_message',
545 _ajax_nonce: mxchatChat.nonce
546 },
547 success: function() {
548 //console.log('Pre-chat message dismissed for 24 hours.');
549
550 // Ensure the message is hidden after dismissal
551 $('#pre-chat-message').hide();
552 },
553 error: function() {
554 //console.error('Failed to dismiss pre-chat message.');
555 }
556 });
557 });
558 }
559
560
561 });
562