# mxchat-basic/2.0.4/js/mxchat-admin.js

MxChat – AI Chatbot &amp; Content Generation for WordPress, version 2.0.4. 553 lines.

- Page: https://pluginprobe.com/plugins/mxchat-basic/2.0.4/code/js/mxchat-admin.js
- Raw: https://pluginprobe.com/plugins/mxchat-basic/2.0.4/raw/js/mxchat-admin.js
- Modified: 2025-02-17T17:03:00+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/2.0.4/code/js/mxchat-admin.js#L10-L20`.

```javascript
// Simple debounce function implementation
function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// Helper function to open edit modal
function mxchatOpenEditModal(intentId, phrases) {
    const modal = document.getElementById('mxchat-edit-modal');
    if (!modal) return;

    // Get form fields
    const intentIdField = document.getElementById('edit_intent_id');
    const phrasesField = document.getElementById('edit_phrases');

    // Set values
    intentIdField.value = intentId;
    phrasesField.value = phrases;

    // Show modal with animation
    modal.style.display = 'flex';
    requestAnimationFrame(() => {
        modal.classList.add('active');
    });

    // Set up close handlers
    const closeModal = () => {
        modal.classList.remove('active');
        setTimeout(() => {
            modal.style.display = 'none';
        }, 300); // Match the CSS transition time
    };

    // Close button handler
    const closeBtn = modal.querySelector('.mxchat-modal-close');
    if (closeBtn) {
        closeBtn.onclick = closeModal;
    }

    // Cancel button handler
    const cancelBtn = modal.querySelector('.mxchat-modal-cancel');
    if (cancelBtn) {
        cancelBtn.onclick = closeModal;
    }

    // Click outside modal to close
    modal.onclick = (e) => {
        if (e.target === modal) {
            closeModal();
        }
    };

    // Focus the textarea
    phrasesField.focus();
}

// Initialize event listeners
document.addEventListener('DOMContentLoaded', () => {
    // Set up edit button handlers
    document.querySelectorAll('.mxchat-edit-button').forEach(button => {
        button.onclick = () => {
            const intentId = button.dataset.intentId;
            const phrases = button.dataset.phrases;
            mxchatOpenEditModal(intentId, phrases);
        };
    });
});

jQuery(document).ready(function($) {
    // Ensure we have a debounce function (use lodash if available, otherwise use our implementation)
    const useDebounce = (window._ && window._.debounce) ? window._.debounce : debounce;

    // --- AJAX Auto-Save ---
    const $autosaveSections = $('.mxchat-autosave-section');

    if ($autosaveSections.length) {
        // Handle real-time range slider value updates
        $autosaveSections.find('input[type="range"]').on('input', function() {
            const value = $(this).val();
            $('#threshold_value').text(value);
        });

        // Handle all input changes (including range slider)
        $autosaveSections.find('input, textarea, select').on('change', function() {
            const $field = $(this);
            const name = $field.attr('name');
            let value;

            // Handle different input types
            if ($field.attr('type') === 'checkbox') {
                value = $field.is(':checked') ? 'on' : 'off';
            } else {
                value = $field.val();
            }

            // Create feedback container
            const feedbackContainer = $('<div class="feedback-container"></div>');
            const spinner = $('<div class="saving-spinner"></div>');
            const successIcon = $('<div class="success-icon">✔</div>');

            // Position feedback container based on input type
            if ($field.closest('.toggle-switch').length) {
                $field.closest('td').append(feedbackContainer);
            } else if ($field.closest('.mxchat-toggle-switch').length) {
                $field.closest('.mxchat-toggle-container').append(feedbackContainer);
            } else if ($field.closest('.slider-container').length) {
                $field.closest('.slider-container').after(feedbackContainer);
            } else {
                $field.after(feedbackContainer);
            }
            feedbackContainer.append(spinner);

            // Determine which AJAX action and nonce to use:
            var ajaxAction, nonce;
            // Use the new AJAX action for submenu fields:
            if ( name.indexOf('mxchat_prompts_options') !== -1 ||
                 name === 'mxchat_auto_sync_posts' ||
                 name === 'mxchat_auto_sync_pages' ) {
                ajaxAction = 'mxchat_save_prompts_setting';
                nonce = mxchatPromptsAdmin.prompts_setting_nonce;
            } else {
                // Otherwise, use the existing AJAX action.
                ajaxAction = 'mxchat_save_setting';
                nonce = mxchatAdmin.setting_nonce;
            }

            // AJAX save request
            $.ajax({
                url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
                type: 'POST',
                data: {
                    action: ajaxAction,
                    name: name,
                    value: value,
                    _ajax_nonce: nonce
                },
                success: function(response) {
                    if (response.success) {
                        spinner.fadeOut(200, function() {
                            feedbackContainer.append(successIcon);
                            successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
                                feedbackContainer.remove();
                            });
                        });
                    } else {
                        alert('Error saving: ' + (response.data?.message || 'Unknown error'));
                        if ($field.attr('type') === 'checkbox') {
                            $field.prop('checked', !$field.is(':checked'));
                        }
                        feedbackContainer.remove();
                    }
                },
                error: function() {
                    alert('An error occurred while saving.');
                    if ($field.attr('type') === 'checkbox') {
                        $field.prop('checked', !$field.is(':checked'));
                    }
                    feedbackContainer.remove();
                }
            });
        });

        // Initialize color pickers with debouncing
        $autosaveSections.find('.my-color-field').each(function() {
            const $colorField = $(this);
            
            $(this).wpColorPicker({
                change: useDebounce(function(event, ui) {
                    // Safety check - ensure we have a valid field and value
                    if (!$colorField || !$colorField.val()) {
                        console.warn('Color picker not ready');
                        return;
                    }

                    const name = $colorField.attr('name');
                    const value = $colorField.val();

                    if (!name || !value) {
                        console.warn('Missing required color picker values');
                        return;
                    }

                    // Create feedback container
                    const feedbackContainer = $('<div class="feedback-container"></div>');
                    const spinner = $('<div class="saving-spinner"></div>');
                    const successIcon = $('<div class="success-icon">✔</div>');

                    // Position feedback container
                    $colorField.closest('.wp-picker-container').after(feedbackContainer);
                    feedbackContainer.append(spinner);

                    // Determine AJAX action and nonce for color fields:
                    var ajaxAction, nonce;
                    if ( name.indexOf('mxchat_prompts_options') !== -1 ||
                         name === 'mxchat_auto_sync_posts' ||
                         name === 'mxchat_auto_sync_pages' ) {
                        ajaxAction = 'mxchat_save_prompts_setting';
                        nonce = mxchatPromptsAdmin.prompts_setting_nonce;
                    } else {
                        ajaxAction = 'mxchat_save_setting';
                        nonce = mxchatAdmin.setting_nonce;
                    }

                    // AJAX save request
                    $.ajax({
                        url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
                        type: 'POST',
                        data: {
                            action: ajaxAction,
                            name: name,
                            value: value,
                            _ajax_nonce: nonce
                        },
                        success: function(response) {
                            if (response.success) {
                                spinner.fadeOut(200, function() {
                                    feedbackContainer.append(successIcon);
                                    successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
                                        feedbackContainer.remove();
                                    });
                                });
                            } else {
                                alert('Error saving: ' + (response.data?.message || 'Unknown error'));
                                feedbackContainer.remove();
                            }
                        },
                        error: function() {
                            alert('An error occurred while saving.');
                            feedbackContainer.remove();
                        }
                    });
                }, 500)
            });
        });

        // Reinitialize color pickers when switching tabs
        $('.mxchat-nav-tab').on('click.mxchat', function() {
            setTimeout(function() {
                $('.my-color-field:visible').wpColorPicker('close');
            }, 100);
        });
    }

    // Initialize tabs system
    function initTabs() {
        // Remove any existing handlers first
        $('.mxchat-nav-tab').off('click.mxchat');
        
        // Add new click handlers
        $('.mxchat-nav-tab').on('click.mxchat', function(e) {
            e.preventDefault();
            e.stopPropagation();
            
            var $this = $(this);
            
            // Get tab ID - try href first, fallback to data-tab, then to default
            var tabId = $this.attr('href');
            if (tabId) {
                tabId = tabId.replace('#', '');
            } else {
                tabId = $this.data('tab') || 'chatbot';
            }
            
            // Safety check for empty tabId
            if (!tabId) {
                console.warn('No tab identifier found');
                return;
            }
            
            // Update tabs
            $('.mxchat-nav-tab').removeClass('mxchat-nav-tab-active');
            $this.addClass('mxchat-nav-tab-active');
            
            // Update content areas - with safety check
            $('.mxchat-tab-content').removeClass('active').hide();
            var $targetTab = $('#' + tabId);
            if ($targetTab.length) {
                $targetTab.addClass('active').show();
                
                // Store active tab
                try {
                    localStorage.setItem('mxchat_active_tab', tabId);
                } catch (e) {
                    console.warn('LocalStorage not available:', e);
                }
            } else {
                console.warn('Tab content #' + tabId + ' not found');
            }
        });
    }
    
    // Initialize tabs and handle events
    initTabs();
    $(document).on('widget-added widget-updated postbox-toggled', initTabs);
    
    // Activate initial tab
    try {
        var savedTab = localStorage.getItem('mxchat_active_tab');
        if (savedTab && $('#' + savedTab).length > 0) {
            $('.mxchat-nav-tab[href="#' + savedTab + '"]').trigger('click.mxchat');
        } else {
            $('.mxchat-nav-tab').first().trigger('click.mxchat');
        }
    } catch (e) {
        $('.mxchat-nav-tab').first().trigger('click.mxchat');
    }
    
    // Attach edit modal event handler
    $(document).on('click', '.mxchat-edit-button', function() {
        const intentId = $(this).data('intent-id');
        const phrases = $(this).data('phrases');
        mxchatOpenEditModal(intentId, phrases);
    });
    
    // Toggle visibility handlers
    function toggleVisibility(selector) {
        $(selector).on('click', function() {
            var inputField = $(this).prev('input');
            if (inputField.attr('type') === 'password') {
                inputField.attr('type', 'text');
                $(this).text('Hide');
            } else {
                inputField.attr('type', 'password');
                $(this).text('Show');
            }
        });
    }
    
    // Initialize all toggle visibility buttons
    [
        '#toggleApiKeyVisibility',
        '#toggleWooCommerceSecretVisibility',
        '#toggleLoopsApiKeyVisibility',
        '#toggleXaiApiKeyVisibility',
        '#toggleClaudeApiKeyVisibility',
        '#toggleBraveApiKeyVisibility',
        '#toggleWebhookUrlVisibility',
        '#toggleSecretKeyVisibility',
        '#toggleBotTokenVisibility',
        '#toggleDeepSeekApiKeyVisibility'
    ].forEach(toggleVisibility);
    
    // Add Intent Form Submission
    $('#mxchat-add-intent-form').on('submit', function(event) {
        $('#mxchat-intent-loading').show();
        $('#mxchat-intent-loading-text').show();
        $(this).find('button[type="submit"]').hide();
    });
    
    // Inline Edit Functionality
    $('.edit-button').on('click', function() {
        var row = $(this).closest('tr');
        row.find('.content-view, .url-view').hide();
        row.find('.content-edit, .url-edit').show();
        row.find('.edit-button').hide();
        row.find('.save-button').show();
    });
    
    // Save button handler
    $('.save-button').on('click', function() {
        var button = $(this);
        var row = button.closest('tr');
        var id = button.data('id');
        var newContent = row.find('.content-edit').val();
        var newUrl = row.find('.url-edit').val();
    
        button.prop('disabled', true);
        button.text('Saving...');
    
        $.ajax({
            url: mxchatAdmin.ajax_url,
            type: 'POST',
            data: {
                action: 'mxchat_save_inline_prompt',
                id: id,
                article_content: newContent,
                article_url: newUrl,
                _ajax_nonce: mxchatAdmin.inline_edit_nonce
            },
            success: function(response) {
                button.prop('disabled', false);
                button.text('Save');
                
                if (response.success) {
                    row.find('.content-view').html(newContent.replace(/\n/g, "<br>"));
                    if (newUrl) {
                        row.find('.url-view').html('<a href="' + newUrl + '" target="_blank">' + newUrl + '</a>');
                    } else {
                        row.find('.url-view').html('N/A');
                    }
                    
                    row.find('.content-edit, .url-edit').hide();
                    row.find('.content-view, .url-view').show();
                    row.find('.save-button').hide();
                    row.find('.edit-button').show();
                } else {
                    alert('Error saving content: ' + (response.data?.message || 'Unknown error'));
                }
            },
            error: function() {
                button.prop('disabled', false);
                button.text('Save');
                alert('An error occurred while saving.');
            }
        });
    });
    
    // Activation handling
    const form = $('#mxchat-activation-form');
    const spinner = $('#mxchat-activation-spinner');
    const submitButton = $('#activate_license_button');
    const licenseStatus = $('#mxchat-license-status');
    
    if (form.length && licenseStatus.length && submitButton.length) {
        function handleActivationResponse(response) {
            spinner.hide();
            if (response.success) {
                licenseStatus.text('Active');
                licenseStatus.removeClass('inactive').addClass('active');
                form.hide();
            } else {
                licenseStatus.text('Inactive');
                alert(response.data || 'Activation failed. Please check your input.');
                submitButton.prop('disabled', false);
            }
        }
    
        form.on('submit', function(event) {
            event.preventDefault();
            spinner.show();
            submitButton.prop('disabled', true);
        
            var formData = {
                action: 'mxchat_activate_license',
                mxchat_pro_email: $('#mxchat_pro_email').val(),
                mxchat_activation_key: $('#mxchat_activation_key').val(),
                security: mxchatAdmin.license_nonce
            };
        
            $.post(mxchatAdmin.ajax_url, formData, function(response) {
                handleActivationResponse(response);
            }).fail(function() {
                alert('Server error. Please try again.');
                spinner.hide();
                submitButton.prop('disabled', false);
            });
        });
    }
    
    // Questions handling
    $('.mxchat-add-question').on('click', function () {
        const container = $('#mxchat-additional-questions-container');
        const questionCount = container.find('.mxchat-question-row').length + 4;
        const questionIndex = container.find('.mxchat-question-row').length;
    
        const newQuestion = `
            <div class="mxchat-question-row">
                <input type="text"
                       name="additional_popular_questions[]"
                       placeholder="Enter Additional Popular Question ${questionCount}"
                       class="regular-text mxchat-question-input"
                       data-question-index="${questionIndex}" />
                <button type="button" class="button mxchat-remove-question"
                        aria-label="Remove question">Remove</button>
            </div>
        `;
        container.append(newQuestion);
    });
    
    $(document).on('click', '.mxchat-remove-question', function () {
        $(this).closest('.mxchat-question-row').remove();
        saveQuestions();
    });
    
    $(document).on('change', '.mxchat-question-input', function() {
        saveQuestions();
    });
    
    function saveQuestions() {
        const questions = [];
        $('.mxchat-question-input').each(function() {
            const value = $(this).val().trim();
            if (value) {
                questions.push(value);
            }
        });
    
        const feedbackContainer = $('<div class="feedback-container"></div>');
        const spinner = $('<div class="saving-spinner"></div>');
        const successIcon = $('<div class="success-icon">✔</div>');
    
        // Append feedback after the add button
        $('.mxchat-add-question').after(feedbackContainer);
        feedbackContainer.append(spinner);
    
        // Save via AJAX
        $.ajax({
            url: mxchatAdmin.ajax_url,
            type: 'POST',
            data: {
                action: 'mxchat_save_setting',
                name: 'additional_popular_questions',
                value: JSON.stringify(questions),
                _ajax_nonce: mxchatAdmin.setting_nonce
            },
            success: function(response) {
                if (response.success) {
                    spinner.fadeOut(200, function() {
                        feedbackContainer.append(successIcon);
                        successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
                            feedbackContainer.remove();
                        });
                    });
                } else {
                    alert('Error saving questions: ' + (response.data?.message || 'Unknown error'));
                    feedbackContainer.remove();
                }
            },
            error: function() {
                alert('An error occurred while saving questions.');
                feedbackContainer.remove();
            }
        });
    }
    
    // Live agent status handler
    const statusToggle = document.getElementById('live_agent_status');
    const statusText = statusToggle?.parentElement.nextElementSibling?.querySelector('.status-text');
    if (statusToggle && statusText) {
        statusToggle.addEventListener('change', function() {
            // Update display text
            statusText.textContent = this.checked ? 'Online' : 'Offline';
            
            // Send the correct on/off value to the server
            if (window.mxchatSaveSetting) {
                window.mxchatSaveSetting('live_agent_status', this.checked ? 'on' : 'off');
            }
        });
    }
    
    
});




```
