PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.1.8
MxChat – AI Chatbot & Content Generation for WordPress v1.1.8
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.1.8, at js/chat-script.js

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