# mxchat-basic/1.4.2/js/chat-script.js

MxChat – AI Chatbot &amp; Content Generation for WordPress, version 1.4.2. 701 lines.

- Page: https://pluginprobe.com/plugins/mxchat-basic/1.4.2/code/js/chat-script.js
- Raw: https://pluginprobe.com/plugins/mxchat-basic/1.4.2/raw/js/chat-script.js
- Modified: 2024-11-14T16:22:08+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/mxchat-basic/1.4.2/code/js/chat-script.js#L10-L20`.

````javascript
jQuery(document).ready(function($) {
   //console.log('mxchatChat object:', mxchatChat);

    // Initialize color settings
    var userMessageBgColor = mxchatChat.user_message_bg_color;
    var userMessageFontColor = mxchatChat.user_message_font_color;
    var botMessageBgColor = mxchatChat.bot_message_bg_color;
    var botMessageFontColor = mxchatChat.bot_message_font_color;
    var linkTarget = mxchatChat.link_target === 'on' ? '_blank' : '_self';



function getChatSession() {
    var sessionId = getCookie('mxchat_session_id');
    //console.log("Session ID retrieved from cookie: ", sessionId);

    if (!sessionId) {
        sessionId = generateSessionId();
        //console.log("Generated new session ID: ", sessionId);
        setChatSession(sessionId);
    }

    //console.log("Final session ID: ", sessionId);
    return sessionId;
}

function setChatSession(sessionId) {
    // Set the cookie with a 24-hour expiration (86400 seconds)
    document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax";
}

// Get cookie value by name
function getCookie(name) {
    let value = "; " + document.cookie;
    let parts = value.split("; " + name + "=");
    if (parts.length == 2) return parts.pop().split(";").shift();
}

// Generate a new session ID
function generateSessionId() {
    return 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
}

// Function to send the message to the chatbot (backend)
function sendMessageToChatbot(message) {
    var sessionId = getChatSession(); // Reuse the session ID logic

    // Hide the popular questions section
    $('#mxchat-popular-questions').hide();

    // Show thinking indicator (no need to append the user's message again)
    appendThinkingMessage();
    scrollToBottom();

    //console.log("Sending message to chatbot:", message); // Log the message
    //console.log("Session ID:", sessionId); // Log the session ID

    // Call the chatbot using the same call logic as sendMessage
    callMxChat(message, function(response) {
        // ** Ensure temporary thinking message is removed before adding new response **
        $('.temporary-message').remove();

        // Replace thinking indicator with actual response
        replaceLastMessage("bot", response);
    });
}





function sendMessage() {
    var message = $('#chat-input').val();
    if (message) {
        appendMessage("user", message);
        $('#chat-input').val('');

        // Hide the popular questions section
        $('#mxchat-popular-questions').hide();

        // Show typing indicator
        appendThinkingMessage();
        scrollToBottom();

        callMxChat(message, function(response) {
            // Replace typing indicator with actual response
            replaceLastMessage("bot", response);
        });
    }
}


    // Function to append a thinking message with animation
    function appendThinkingMessage() {
        // Remove any existing thinking dots first
        $('.thinking-dots').remove();

        // Retrieve the bot message font color and background color
        var botMessageFontColor = mxchatChat.bot_message_font_color;
        var botMessageBgColor = mxchatChat.bot_message_bg_color;

        var thinkingHtml = '<div class="thinking-dots-container">' +
                           '<div class="thinking-dots">' +
                           '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
                           '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
                           '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
                           '</div>' +
                           '</div>';

        // Append the thinking dots to the chat container (or within the temporary message div)
        $("#chat-box").append('<div class="bot-message temporary-message" style="background-color: ' + botMessageBgColor + ';">' + thinkingHtml + '</div>');
        scrollToBottom();
    }

    // Trigger send button click when "Enter" key is pressed in the input field
    $('#chat-input').keypress(function(e) {
        if (e.which == 13) {
            e.preventDefault();
            $('#send-button').click();
        }
    });

    // Handle send button click
    $('#send-button').click(function() {
        sendMessage();
    });

    // Handle click on popular questions
    $('.mxchat-popular-question').on('click', function () {
        var question = $(this).text(); // Get the text of the clicked question

        // Append the question as if the user typed it
        appendMessage("user", question);

        // Send the question to the server (backend)
        sendMessageToChatbot(question);
    });


// Use the linkTarget in your linkify function
function linkify(inputText) {
    // Check for already linked URLs and skip them
    // We use negative lookaheads to skip anything already in an <a> tag
    var markdownLinkPattern = /\[([^\]]+)\]\((https?:\/\/[^\s]+)\)/g;
    var replacedText = inputText.replace(markdownLinkPattern, '<a href="$2" target="' + linkTarget + '">$1</a>');

    // Replace standalone URLs not already in an <a> tag
    var urlPattern = /(^|[^">])(https?:\/\/[^\s<]+)/gim;
    replacedText = replacedText.replace(urlPattern, '$1<a href="$2" target="' + linkTarget + '">$2</a>');

    // Replace "www." prefixed URLs not already in an <a> tag
    var wwwPattern = /(^|[^">])(www\.[\S]+(\b|$))(?![^<]*<\/a>)/gim;
    replacedText = replacedText.replace(wwwPattern, '$1<a href="http://$2" target="' + linkTarget + '">$2</a>');

    return replacedText;
}


function scrollElementToTop(element) {
    var chatBox = $('#chat-box');
    var elementTop = element.position().top + chatBox.scrollTop();
    chatBox.animate({ scrollTop: elementTop }, 500);
}


// Optimized scrollToBottom function for instant scrolling
function scrollToBottom(instant = false) {
    var chatBox = $('#chat-box');
    if (instant) {
        // Instantly set the scroll position to the bottom
        chatBox.scrollTop(chatBox.prop("scrollHeight"));
    } else {
        // Use requestAnimationFrame for smoother scrolling if needed
        let start = null;
        const scrollHeight = chatBox.prop("scrollHeight");
        const initialScroll = chatBox.scrollTop();
        const distance = scrollHeight - initialScroll;
        const duration = 500; // Duration in ms

        function smoothScroll(timestamp) {
            if (!start) start = timestamp;
            const progress = timestamp - start;
            const currentScroll = initialScroll + (distance * (progress / duration));
            chatBox.scrollTop(currentScroll);

            if (progress < duration) {
                requestAnimationFrame(smoothScroll);
            } else {
                chatBox.scrollTop(scrollHeight); // Ensure it's exactly at the bottom
            }
        }

        requestAnimationFrame(smoothScroll);
    }
}


    // Function to format text with **bold** inside double asterisks
    function formatBoldText(text) {
        return text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
    }

    // Function to convert newline characters to HTML line breaks and handle paragraph spacing
    function convertNewlinesToBreaks(text) {
        var lines = text.split('\n');
        var formattedText = '';

        for (var i = 0; i < lines.length; i++) {
            formattedText += lines[i] + '<br>';
        }

        return formattedText;
    }

    // Copy to clipboard function
    // Function to copy text to clipboard
    function copyToClipboard(text) {
        var tempInput = $('<input>');
        $('body').append(tempInput);
        tempInput.val(text).select();
        document.execCommand('copy');
        tempInput.remove();
    }


// Initialize session ID
var sessionId = getChatSession();

function callMxChat(message, callback) {
    var sessionId = getChatSession();
    $.ajax({
        url: mxchatChat.ajax_url,
        type: 'POST',
        dataType: 'json',
        data: {
            action: 'mxchat_handle_chat_request',
            message: message,
            session_id: sessionId,
            nonce: mxchatChat.nonce
        },
        success: function(response) {
            //console.log("API Response:", response); // Debug log

            // Check for the presence of 'message' in response as a fallback for 'text'
            var responseText = response.text || response.message || '';  
            var responseHtml = response.html || '';  // Capture product card HTML
            var images = response.images || [];

            // Display the responseText if available, or responseHtml if included
            if (responseText || responseHtml || images.length > 0) {
                replaceLastMessage("bot", responseText, responseHtml, images);
            } else {
                appendMessage("bot", "I'm sorry, something went wrong.");
            }

            // Handle any redirection for checkout if available
            if (response.redirect_url) {
                setTimeout(function() {
                    window.location.href = response.redirect_url;
                }, 2000);
            }
        },
        error: function(xhr, status, error) {
            console.error("Error communicating with the server:", error);
            appendMessage("bot", "Error communicating with the server.");
        }
    });
}

function appendMessage(sender, messageText = '', messageHtml = '', images = [], isTemporary = false) {
    try {
        var messageClass = sender === "user" ? "user-message" : "bot-message";
        var bgColor = sender === "user" ? userMessageBgColor : botMessageBgColor;
        var fontColor = sender === "user" ? userMessageFontColor : botMessageFontColor;

        var messageDiv = $('<div>').addClass(messageClass).css({
            'background': bgColor,
            'color': fontColor
        });

        // Format the message text, including code blocks
        var fullMessage = linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(messageText))));

        if (images && images.length > 0) {
            fullMessage += '<div class="image-gallery">';
            images.forEach(img => {
                fullMessage += `
                    <div style="margin-bottom: 10px;">
                        <strong>${img.title}</strong><br>
                        <a href="${img.image_url}" target="_blank">
                            <img src="${img.thumbnail_url}" alt="${img.title}" style="max-width: 100px; height: auto; margin: 5px;" />
                        </a>
                    </div>`;
            });
            fullMessage += '</div>';
        }

        if (messageHtml) {
            fullMessage += '<br><br>' + messageHtml;
        }

        messageDiv.html(fullMessage);

        if (isTemporary) {
            messageDiv.addClass('temporary-message');
        }

        messageDiv.hide().appendTo('#chat-box').fadeIn(300, function() {
            if (sender === "bot") {
                // After bot's message is displayed, scroll last user message to top
                var lastUserMessage = $('#chat-box').find('.user-message').last();
                if (lastUserMessage.length) {
                    scrollElementToTop(lastUserMessage);
                }
            }
        });
    } catch (error) {
        console.error("Error rendering message with images:", error);
    }
}


function replaceLastMessage(sender, responseText, responseHtml = '', images = []) {
    var messageClass = sender === "user" ? "user-message" : "bot-message";
    var lastMessageDiv = $('#chat-box').find('.' + messageClass + '.temporary-message').last();

    // Format response text, including code blocks
    var fullMessage = Array.isArray(responseText) ?
        responseText.map(item => linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(item))))).join("<br>") :
        linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(responseText))));

    if (responseHtml) {
        fullMessage += '<br><br>' + responseHtml;
    }

    if (images.length > 0) {
        fullMessage += '<div class="image-gallery">';
        images.forEach(img => {
            fullMessage += `
                <div style="margin-bottom: 10px;">
                    <strong>${img.title}</strong><br>
                    <a href="${img.image_url}" target="_blank">
                        <img src="${img.thumbnail_url}" alt="${img.title}" style="max-width: 100px; height: auto; margin: 5px;" />
                    </a>
                </div>`;
        });
        fullMessage += '</div>';
    }

    if (lastMessageDiv.length) {
        lastMessageDiv.fadeOut(200, function() {
            $(this).html(fullMessage).removeClass('temporary-message').fadeIn(200, function() {
                // After bot's message is displayed, scroll last user message to top
                var lastUserMessage = $('#chat-box').find('.user-message').last();
                if (lastUserMessage.length) {
                    scrollElementToTop(lastUserMessage);
                }
            });
        });
    } else {
        appendMessage(sender, responseText, responseHtml, images);
    }
}


function loadChatHistory() {
    var sessionId = getChatSession();
    var chatPersistenceEnabled = mxchatChat.chat_persistence_toggle === 'on';

    if (chatPersistenceEnabled && sessionId) {
        $.ajax({
            url: mxchatChat.ajax_url,
            type: 'POST',
            dataType: 'json',
            data: {
                action: 'mxchat_fetch_conversation_history',
                session_id: sessionId
            },
            success: function(response) {
                if (response.success && response.data && Array.isArray(response.data.conversation)) {
                    var $chatBox = $('#chat-box');
                    var $fragment = $(document.createDocumentFragment());

                    $.each(response.data.conversation, function(index, message) {
                        var messageElement = $('<div>').addClass(message.role === 'user' ? 'user-message' : 'bot-message')
                            .css({
                                'background': message.role === 'user' ? userMessageBgColor : botMessageBgColor,
                                'color': message.role === 'user' ? userMessageFontColor : botMessageFontColor
                            });

                        var content = message.content;

                        // Decode any escaped characters
                        content = content.replace(/\\'/g, "'").replace(/\\"/g, '"');
                        content = decodeHTMLEntities(content);

                        // Detect if the content is HTML by checking for specific classes
                        if (content.includes("mxchat-product-card") || content.includes("mxchat-image-gallery")) {
                            // Append HTML content directly
                            messageElement.html(content);
                        } else {
                            // Format plain text content with code block support
                            var formattedContent = linkify(
                                formatBoldText(
                                    convertNewlinesToBreaks(formatCodeBlocks(content))
                                )
                            );
                            messageElement.html(formattedContent);
                        }

                        $fragment.append(messageElement);
                    });

                    $chatBox.append($fragment);
                    scrollToBottom(true);

                    if (response.data.conversation.length > 0) {
                        $('#mxchat-popular-questions').hide();
                    }
                } else {
                    console.warn("No conversation history found.");
                }
            },
            error: function(xhr, status, error) {
                console.error("Error loading chat history:", status, error);
                appendMessage("bot", "Unable to load chat history.");
            }
        });
    } else {
        console.warn("Chat persistence is disabled or no session ID found. Not loading history.");
    }
}


// Function to decode HTML entities
function decodeHTMLEntities(text) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = text;
    return textArea.value;
}


function formatCodeBlocks(text) {
    // Regex to match triple backticks and capture content between them
    var codeBlockPattern = /```(\w+)?\n?([\s\S]+?)```/g;

    return text.replace(codeBlockPattern, function(_, language, codeContent) {
        language = language || 'plaintext';

        // Wrap code content in <pre> and <code> tags
        return `<div class="code-block-container">
                    <pre class="code-block"><code class="language-${language}">${escapeHtml(codeContent)}</code></pre>
                </div>`;
    });
}

function escapeHtml(unsafe) {
    return unsafe
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}

// Function to convert newlines, skipping preformatted text
function convertNewlinesToBreaks(text) {
    // Regex to exclude <pre> and <code> tags from adding <br> tags
    return text.replace(/(^|[^>])\n/g, '$1<br>');
}



$(document).ready(function() {
    loadChatHistory();
});



    // Helper function to check if a string is an image HTML
    function isImageHtml(str) {
        return str.startsWith('<img') && str.endsWith('>');
    }

    // Function to remove thinking dots
    function removeThinkingDots() {
        $('.thinking-dots').closest('.temporary-message').remove();
    }

    function isMobile() {
        // This can be a simple check, or more sophisticated detection of mobile devices
        return window.innerWidth <= 768; // Example threshold for mobile devices
    }

    function disableScroll() {
        if (isMobile()) {
            $('body').css('overflow', 'hidden');
        }
    }

    function enableScroll() {
        if (isMobile()) {
            $('body').css('overflow', '');
        }
    }

 // Function to show the chatbot widget (moved outside the Complianz logic)
    function showChatWidget() {
        setTimeout(function() {
            $('#floating-chatbot-button').css('display', 'flex').fadeTo(500, 1);
        }, 250);
    }

    // Function to hide the chatbot widget
    function hideChatWidget() {
        $('#floating-chatbot-button').css('display', 'none');
    }

// Pre-chat dismissal check function (wrapped in a function for reuse)
    function checkPreChatDismissal() {
        $.ajax({
            url: mxchatChat.ajax_url,
            type: 'POST',
            data: {
                action: 'mxchat_check_pre_chat_message_status',
                _ajax_nonce: mxchatChat.nonce
            },
            success: function(response) {
                if (response.success && !response.data.dismissed) {
                    $('#pre-chat-message').fadeIn(250);
                } else {
                    $('#pre-chat-message').hide();
                }
            },
            error: function() {
                console.error('Failed to check pre-chat message dismissal status.');
            }
        });
    }

    // Function to dismiss pre-chat message for 24 hours
    function handlePreChatDismissal() {
        $('#pre-chat-message').fadeOut(200);
        $.ajax({
            url: mxchatChat.ajax_url,
            type: 'POST',
            data: {
                action: 'mxchat_dismiss_pre_chat_message',
                _ajax_nonce: mxchatChat.nonce
            },
            success: function() {
                $('#pre-chat-message').hide();
            },
            error: function() {
                console.error('Failed to dismiss pre-chat message.');
            }
        });
    }

    // Handle pre-chat message dismissal on button click
    $(document).on('click', '.close-pre-chat-message', function(e) {
        e.stopPropagation();
        handlePreChatDismissal();
    });

    // Function for Complianz logic
    var applyComplianzLogic = mxchatChat.complianz_toggle;
    if (applyComplianzLogic) {
        function checkConsentAndShowChat() {
            var consentStatus = typeof cmplz_has_consent === "function" && cmplz_has_consent('marketing');
            var consentType = typeof complianz !== 'undefined' ? complianz.consenttype : null;

            if (consentType === 'optin' && !consentStatus) {
                hideChatWidget();
            } else if (consentType === 'optout' && !consentStatus) {
                hideChatWidget();
            } else {
                showChatWidget();
                checkPreChatDismissal(); // Ensure we check dismissal after consent is handled
            }
        }

        checkConsentAndShowChat();
        $(document).on('cmplz_status_change', function(event, category) {
            checkConsentAndShowChat();
        });
    } else {
        showChatWidget();
        checkPreChatDismissal(); // Always check pre-chat dismissal when consent logic is not applied
    }

    // Toggle chatbot visibility on floating button click
    $(document).on('click', '#floating-chatbot-button', function() {
        var chatbot = $('#floating-chatbot');
        if (chatbot.hasClass('hidden')) {
            chatbot.removeClass('hidden').addClass('visible');
            $(this).addClass('hidden');
            disableScroll();
            // Hide the pre-chat message without dismissing it
            $('#pre-chat-message').fadeOut(250);
        } else {
            chatbot.removeClass('visible').addClass('hidden');
            $(this).removeClass('hidden');
            enableScroll();
            // Show the pre-chat message again if it hasn't been dismissed
            checkPreChatDismissal();
        }
    });

    $(document).on('click', '#exit-chat-button', function() {
        $('#floating-chatbot').addClass('hidden').removeClass('visible');
        $('#floating-chatbot-button').removeClass('hidden');
        enableScroll();
    });

    // Close pre-chat message on click
    $(document).on('click', '.close-pre-chat-message', function(e) {
        e.stopPropagation(); // Prevent triggering the parent .pre-chat-message click
        $('#pre-chat-message').fadeOut(200, function() {
            $(this).remove();
        });
    });

    // Open chatbot when pre-chat message is clicked
    $(document).on('click', '#pre-chat-message', function() {
        var chatbot = $('#floating-chatbot');
        if (chatbot.hasClass('hidden')) {
            chatbot.removeClass('hidden').addClass('visible');
            $('#floating-chatbot-button').addClass('hidden');
            $('#pre-chat-message').fadeOut(250); // Hide pre-chat message
            disableScroll(); // Disable scroll when chatbot opens
        }
    });

    // If the chatbot is initially hidden, ensure the button is visible
    if ($('#floating-chatbot').hasClass('hidden')) {
        $('#floating-chatbot-button').removeClass('hidden');
    }

    function setFullHeight() {
        var vh = $(window).innerHeight() * 0.01;
        $(':root').css('--vh', vh + 'px');
    }

    // Set the height when the page loads
    $(document).ready(function() {
        setFullHeight();
    });

    // Set the height on resize and orientation change events
    $(window).on('resize orientationchange', function() {
        setFullHeight();
    });


    // Now handle the close button to dismiss the pre-chat message for 24 hours
    var closeButton = document.querySelector('.close-pre-chat-message');
    if (closeButton) {
        closeButton.addEventListener('click', function() {
            $('#pre-chat-message').fadeOut(200); // Hide the message

            // Send an AJAX request to set the transient flag for 24 hours
            $.ajax({
                url: mxchatChat.ajax_url,
                type: 'POST',
                data: {
                    action: 'mxchat_dismiss_pre_chat_message',
                    _ajax_nonce: mxchatChat.nonce
                },
                success: function() {
                    //console.log('Pre-chat message dismissed for 24 hours.');

                    // Ensure the message is hidden after dismissal
                    $('#pre-chat-message').hide();
                },
                error: function() {
                    //console.error('Failed to dismiss pre-chat message.');
                }
            });
        });
    }



    
// Event listener for Add to Cart button
$(document).on('click', '.add-to-cart-button', function() {
    var productId = $(this).data('product-id'); // Get product ID from data attribute

    // Simulate user message first for proper ordering
    appendMessage("user", "add to cart"); // Display the user's "add to cart" message first


    // Use existing function to send the "add to cart" command to the chatbot
    sendMessageToChatbot("add to cart"); // Triggers the chatbot response as though user typed it
});



});

````
