PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.6.3
MxChat – AI Chatbot & Content Generation for WordPress v1.6.3
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/mxchat-admin.js +414 -552 2.0.41.6.3 View file →
@@ -1,552 +1,414 @@
1 -// Simple debounce function implementation
2 -function debounce(func, wait) {
3 - let timeout;
4 - return function executedFunction(...args) {
5 - const later = () => {
6 - clearTimeout(timeout);
7 - func(...args);
8 - };
9 - clearTimeout(timeout);
10 - timeout = setTimeout(later, wait);
11 - };
12 -}
13 -
14 -// Helper function to open edit modal
15 -function mxchatOpenEditModal(intentId, phrases) {
16 - const modal = document.getElementById('mxchat-edit-modal');
17 - if (!modal) return;
18 -
19 - // Get form fields
20 - const intentIdField = document.getElementById('edit_intent_id');
21 - const phrasesField = document.getElementById('edit_phrases');
22 -
23 - // Set values
24 - intentIdField.value = intentId;
25 - phrasesField.value = phrases;
26 -
27 - // Show modal with animation
28 - modal.style.display = 'flex';
29 - requestAnimationFrame(() => {
30 - modal.classList.add('active');
31 - });
32 -
33 - // Set up close handlers
34 - const closeModal = () => {
35 - modal.classList.remove('active');
36 - setTimeout(() => {
37 - modal.style.display = 'none';
38 - }, 300); // Match the CSS transition time
39 - };
40 -
41 - // Close button handler
42 - const closeBtn = modal.querySelector('.mxchat-modal-close');
43 - if (closeBtn) {
44 - closeBtn.onclick = closeModal;
45 - }
46 -
47 - // Cancel button handler
48 - const cancelBtn = modal.querySelector('.mxchat-modal-cancel');
49 - if (cancelBtn) {
50 - cancelBtn.onclick = closeModal;
51 - }
52 -
53 - // Click outside modal to close
54 - modal.onclick = (e) => {
55 - if (e.target === modal) {
56 - closeModal();
57 - }
58 - };
59 -
60 - // Focus the textarea
61 - phrasesField.focus();
62 -}
63 -
64 -// Initialize event listeners
65 -document.addEventListener('DOMContentLoaded', () => {
66 - // Set up edit button handlers
67 - document.querySelectorAll('.mxchat-edit-button').forEach(button => {
68 - button.onclick = () => {
69 - const intentId = button.dataset.intentId;
70 - const phrases = button.dataset.phrases;
71 - mxchatOpenEditModal(intentId, phrases);
72 - };
73 - });
74 -});
75 -
76 -jQuery(document).ready(function($) {
77 - // Ensure we have a debounce function (use lodash if available, otherwise use our implementation)
78 - const useDebounce = (window._ && window._.debounce) ? window._.debounce : debounce;
79 -
80 - // --- AJAX Auto-Save ---
81 - const $autosaveSections = $('.mxchat-autosave-section');
82 -
83 - if ($autosaveSections.length) {
84 - // Handle real-time range slider value updates
85 - $autosaveSections.find('input[type="range"]').on('input', function() {
86 - const value = $(this).val();
87 - $('#threshold_value').text(value);
88 - });
89 -
90 - // Handle all input changes (including range slider)
91 - $autosaveSections.find('input, textarea, select').on('change', function() {
92 - const $field = $(this);
93 - const name = $field.attr('name');
94 - let value;
95 -
96 - // Handle different input types
97 - if ($field.attr('type') === 'checkbox') {
98 - value = $field.is(':checked') ? 'on' : 'off';
99 - } else {
100 - value = $field.val();
101 - }
102 -
103 - // Create feedback container
104 - const feedbackContainer = $('<div class="feedback-container"></div>');
105 - const spinner = $('<div class="saving-spinner"></div>');
106 - const successIcon = $('<div class="success-icon">✔</div>');
107 -
108 - // Position feedback container based on input type
109 - if ($field.closest('.toggle-switch').length) {
110 - $field.closest('td').append(feedbackContainer);
111 - } else if ($field.closest('.mxchat-toggle-switch').length) {
112 - $field.closest('.mxchat-toggle-container').append(feedbackContainer);
113 - } else if ($field.closest('.slider-container').length) {
114 - $field.closest('.slider-container').after(feedbackContainer);
115 - } else {
116 - $field.after(feedbackContainer);
117 - }
118 - feedbackContainer.append(spinner);
119 -
120 - // Determine which AJAX action and nonce to use:
121 - var ajaxAction, nonce;
122 - // Use the new AJAX action for submenu fields:
123 - if ( name.indexOf('mxchat_prompts_options') !== -1 ||
124 - name === 'mxchat_auto_sync_posts' ||
125 - name === 'mxchat_auto_sync_pages' ) {
126 - ajaxAction = 'mxchat_save_prompts_setting';
127 - nonce = mxchatPromptsAdmin.prompts_setting_nonce;
128 - } else {
129 - // Otherwise, use the existing AJAX action.
130 - ajaxAction = 'mxchat_save_setting';
131 - nonce = mxchatAdmin.setting_nonce;
132 - }
133 -
134 - // AJAX save request
135 - $.ajax({
136 - url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
137 - type: 'POST',
138 - data: {
139 - action: ajaxAction,
140 - name: name,
141 - value: value,
142 - _ajax_nonce: nonce
143 - },
144 - success: function(response) {
145 - if (response.success) {
146 - spinner.fadeOut(200, function() {
147 - feedbackContainer.append(successIcon);
148 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
149 - feedbackContainer.remove();
150 - });
151 - });
152 - } else {
153 - alert('Error saving: ' + (response.data?.message || 'Unknown error'));
154 - if ($field.attr('type') === 'checkbox') {
155 - $field.prop('checked', !$field.is(':checked'));
156 - }
157 - feedbackContainer.remove();
158 - }
159 - },
160 - error: function() {
161 - alert('An error occurred while saving.');
162 - if ($field.attr('type') === 'checkbox') {
163 - $field.prop('checked', !$field.is(':checked'));
164 - }
165 - feedbackContainer.remove();
166 - }
167 - });
168 - });
169 -
170 - // Initialize color pickers with debouncing
171 - $autosaveSections.find('.my-color-field').each(function() {
172 - const $colorField = $(this);
173 -
174 - $(this).wpColorPicker({
175 - change: useDebounce(function(event, ui) {
176 - // Safety check - ensure we have a valid field and value
177 - if (!$colorField || !$colorField.val()) {
178 - console.warn('Color picker not ready');
179 - return;
180 - }
181 -
182 - const name = $colorField.attr('name');
183 - const value = $colorField.val();
184 -
185 - if (!name || !value) {
186 - console.warn('Missing required color picker values');
187 - return;
188 - }
189 -
190 - // Create feedback container
191 - const feedbackContainer = $('<div class="feedback-container"></div>');
192 - const spinner = $('<div class="saving-spinner"></div>');
193 - const successIcon = $('<div class="success-icon">✔</div>');
194 -
195 - // Position feedback container
196 - $colorField.closest('.wp-picker-container').after(feedbackContainer);
197 - feedbackContainer.append(spinner);
198 -
199 - // Determine AJAX action and nonce for color fields:
200 - var ajaxAction, nonce;
201 - if ( name.indexOf('mxchat_prompts_options') !== -1 ||
202 - name === 'mxchat_auto_sync_posts' ||
203 - name === 'mxchat_auto_sync_pages' ) {
204 - ajaxAction = 'mxchat_save_prompts_setting';
205 - nonce = mxchatPromptsAdmin.prompts_setting_nonce;
206 - } else {
207 - ajaxAction = 'mxchat_save_setting';
208 - nonce = mxchatAdmin.setting_nonce;
209 - }
210 -
211 - // AJAX save request
212 - $.ajax({
213 - url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
214 - type: 'POST',
215 - data: {
216 - action: ajaxAction,
217 - name: name,
218 - value: value,
219 - _ajax_nonce: nonce
220 - },
221 - success: function(response) {
222 - if (response.success) {
223 - spinner.fadeOut(200, function() {
224 - feedbackContainer.append(successIcon);
225 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
226 - feedbackContainer.remove();
227 - });
228 - });
229 - } else {
230 - alert('Error saving: ' + (response.data?.message || 'Unknown error'));
231 - feedbackContainer.remove();
232 - }
233 - },
234 - error: function() {
235 - alert('An error occurred while saving.');
236 - feedbackContainer.remove();
237 - }
238 - });
239 - }, 500)
240 - });
241 - });
242 -
243 - // Reinitialize color pickers when switching tabs
244 - $('.mxchat-nav-tab').on('click.mxchat', function() {
245 - setTimeout(function() {
246 - $('.my-color-field:visible').wpColorPicker('close');
247 - }, 100);
248 - });
249 - }
250 -
251 - // Initialize tabs system
252 - function initTabs() {
253 - // Remove any existing handlers first
254 - $('.mxchat-nav-tab').off('click.mxchat');
255 -
256 - // Add new click handlers
257 - $('.mxchat-nav-tab').on('click.mxchat', function(e) {
258 - e.preventDefault();
259 - e.stopPropagation();
260 -
261 - var $this = $(this);
262 -
263 - // Get tab ID - try href first, fallback to data-tab, then to default
264 - var tabId = $this.attr('href');
265 - if (tabId) {
266 - tabId = tabId.replace('#', '');
267 - } else {
268 - tabId = $this.data('tab') || 'chatbot';
269 - }
270 -
271 - // Safety check for empty tabId
272 - if (!tabId) {
273 - console.warn('No tab identifier found');
274 - return;
275 - }
276 -
277 - // Update tabs
278 - $('.mxchat-nav-tab').removeClass('mxchat-nav-tab-active');
279 - $this.addClass('mxchat-nav-tab-active');
280 -
281 - // Update content areas - with safety check
282 - $('.mxchat-tab-content').removeClass('active').hide();
283 - var $targetTab = $('#' + tabId);
284 - if ($targetTab.length) {
285 - $targetTab.addClass('active').show();
286 -
287 - // Store active tab
288 - try {
289 - localStorage.setItem('mxchat_active_tab', tabId);
290 - } catch (e) {
291 - console.warn('LocalStorage not available:', e);
292 - }
293 - } else {
294 - console.warn('Tab content #' + tabId + ' not found');
295 - }
296 - });
297 - }
298 -
299 - // Initialize tabs and handle events
300 - initTabs();
301 - $(document).on('widget-added widget-updated postbox-toggled', initTabs);
302 -
303 - // Activate initial tab
304 - try {
305 - var savedTab = localStorage.getItem('mxchat_active_tab');
306 - if (savedTab && $('#' + savedTab).length > 0) {
307 - $('.mxchat-nav-tab[href="#' + savedTab + '"]').trigger('click.mxchat');
308 - } else {
309 - $('.mxchat-nav-tab').first().trigger('click.mxchat');
310 - }
311 - } catch (e) {
312 - $('.mxchat-nav-tab').first().trigger('click.mxchat');
313 - }
314 -
315 - // Attach edit modal event handler
316 - $(document).on('click', '.mxchat-edit-button', function() {
317 - const intentId = $(this).data('intent-id');
318 - const phrases = $(this).data('phrases');
319 - mxchatOpenEditModal(intentId, phrases);
320 - });
321 -
322 - // Toggle visibility handlers
323 - function toggleVisibility(selector) {
324 - $(selector).on('click', function() {
325 - var inputField = $(this).prev('input');
326 - if (inputField.attr('type') === 'password') {
327 - inputField.attr('type', 'text');
328 - $(this).text('Hide');
329 - } else {
330 - inputField.attr('type', 'password');
331 - $(this).text('Show');
332 - }
333 - });
334 - }
335 -
336 - // Initialize all toggle visibility buttons
337 - [
338 - '#toggleApiKeyVisibility',
339 - '#toggleWooCommerceSecretVisibility',
340 - '#toggleLoopsApiKeyVisibility',
341 - '#toggleXaiApiKeyVisibility',
342 - '#toggleClaudeApiKeyVisibility',
343 - '#toggleBraveApiKeyVisibility',
344 - '#toggleWebhookUrlVisibility',
345 - '#toggleSecretKeyVisibility',
346 - '#toggleBotTokenVisibility',
347 - '#toggleDeepSeekApiKeyVisibility'
348 - ].forEach(toggleVisibility);
349 -
350 - // Add Intent Form Submission
351 - $('#mxchat-add-intent-form').on('submit', function(event) {
352 - $('#mxchat-intent-loading').show();
353 - $('#mxchat-intent-loading-text').show();
354 - $(this).find('button[type="submit"]').hide();
355 - });
356 -
357 - // Inline Edit Functionality
358 - $('.edit-button').on('click', function() {
359 - var row = $(this).closest('tr');
360 - row.find('.content-view, .url-view').hide();
361 - row.find('.content-edit, .url-edit').show();
362 - row.find('.edit-button').hide();
363 - row.find('.save-button').show();
364 - });
365 -
366 - // Save button handler
367 - $('.save-button').on('click', function() {
368 - var button = $(this);
369 - var row = button.closest('tr');
370 - var id = button.data('id');
371 - var newContent = row.find('.content-edit').val();
372 - var newUrl = row.find('.url-edit').val();
373 -
374 - button.prop('disabled', true);
375 - button.text('Saving...');
376 -
377 - $.ajax({
378 - url: mxchatAdmin.ajax_url,
379 - type: 'POST',
380 - data: {
381 - action: 'mxchat_save_inline_prompt',
382 - id: id,
383 - article_content: newContent,
384 - article_url: newUrl,
385 - _ajax_nonce: mxchatAdmin.inline_edit_nonce
386 - },
387 - success: function(response) {
388 - button.prop('disabled', false);
389 - button.text('Save');
390 -
391 - if (response.success) {
392 - row.find('.content-view').html(newContent.replace(/\n/g, "<br>"));
393 - if (newUrl) {
394 - row.find('.url-view').html('<a href="' + newUrl + '" target="_blank">' + newUrl + '</a>');
395 - } else {
396 - row.find('.url-view').html('N/A');
397 - }
398 -
399 - row.find('.content-edit, .url-edit').hide();
400 - row.find('.content-view, .url-view').show();
401 - row.find('.save-button').hide();
402 - row.find('.edit-button').show();
403 - } else {
404 - alert('Error saving content: ' + (response.data?.message || 'Unknown error'));
405 - }
406 - },
407 - error: function() {
408 - button.prop('disabled', false);
409 - button.text('Save');
410 - alert('An error occurred while saving.');
411 - }
412 - });
413 - });
414 -
415 - // Activation handling
416 - const form = $('#mxchat-activation-form');
417 - const spinner = $('#mxchat-activation-spinner');
418 - const submitButton = $('#activate_license_button');
419 - const licenseStatus = $('#mxchat-license-status');
420 -
421 - if (form.length && licenseStatus.length && submitButton.length) {
422 - function handleActivationResponse(response) {
423 - spinner.hide();
424 - if (response.success) {
425 - licenseStatus.text('Active');
426 - licenseStatus.removeClass('inactive').addClass('active');
427 - form.hide();
428 - } else {
429 - licenseStatus.text('Inactive');
430 - alert(response.data || 'Activation failed. Please check your input.');
431 - submitButton.prop('disabled', false);
432 - }
433 - }
434 -
435 - form.on('submit', function(event) {
436 - event.preventDefault();
437 - spinner.show();
438 - submitButton.prop('disabled', true);
439 -
440 - var formData = {
441 - action: 'mxchat_activate_license',
442 - mxchat_pro_email: $('#mxchat_pro_email').val(),
443 - mxchat_activation_key: $('#mxchat_activation_key').val(),
444 - security: mxchatAdmin.license_nonce
445 - };
446 -
447 - $.post(mxchatAdmin.ajax_url, formData, function(response) {
448 - handleActivationResponse(response);
449 - }).fail(function() {
450 - alert('Server error. Please try again.');
451 - spinner.hide();
452 - submitButton.prop('disabled', false);
453 - });
454 - });
455 - }
456 -
457 - // Questions handling
458 - $('.mxchat-add-question').on('click', function () {
459 - const container = $('#mxchat-additional-questions-container');
460 - const questionCount = container.find('.mxchat-question-row').length + 4;
461 - const questionIndex = container.find('.mxchat-question-row').length;
462 -
463 - const newQuestion = `
464 - <div class="mxchat-question-row">
465 - <input type="text"
466 - name="additional_popular_questions[]"
467 - placeholder="Enter Additional Popular Question ${questionCount}"
468 - class="regular-text mxchat-question-input"
469 - data-question-index="${questionIndex}" />
470 - <button type="button" class="button mxchat-remove-question"
471 - aria-label="Remove question">Remove</button>
472 - </div>
473 - `;
474 - container.append(newQuestion);
475 - });
476 -
477 - $(document).on('click', '.mxchat-remove-question', function () {
478 - $(this).closest('.mxchat-question-row').remove();
479 - saveQuestions();
480 - });
481 -
482 - $(document).on('change', '.mxchat-question-input', function() {
483 - saveQuestions();
484 - });
485 -
486 - function saveQuestions() {
487 - const questions = [];
488 - $('.mxchat-question-input').each(function() {
489 - const value = $(this).val().trim();
490 - if (value) {
491 - questions.push(value);
492 - }
493 - });
494 -
495 - const feedbackContainer = $('<div class="feedback-container"></div>');
496 - const spinner = $('<div class="saving-spinner"></div>');
497 - const successIcon = $('<div class="success-icon">✔</div>');
498 -
499 - // Append feedback after the add button
500 - $('.mxchat-add-question').after(feedbackContainer);
501 - feedbackContainer.append(spinner);
502 -
503 - // Save via AJAX
504 - $.ajax({
505 - url: mxchatAdmin.ajax_url,
506 - type: 'POST',
507 - data: {
508 - action: 'mxchat_save_setting',
509 - name: 'additional_popular_questions',
510 - value: JSON.stringify(questions),
511 - _ajax_nonce: mxchatAdmin.setting_nonce
512 - },
513 - success: function(response) {
514 - if (response.success) {
515 - spinner.fadeOut(200, function() {
516 - feedbackContainer.append(successIcon);
517 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
518 - feedbackContainer.remove();
519 - });
520 - });
521 - } else {
522 - alert('Error saving questions: ' + (response.data?.message || 'Unknown error'));
523 - feedbackContainer.remove();
524 - }
525 - },
526 - error: function() {
527 - alert('An error occurred while saving questions.');
528 - feedbackContainer.remove();
529 - }
530 - });
531 - }
532 -
533 - // Live agent status handler
534 - const statusToggle = document.getElementById('live_agent_status');
535 - const statusText = statusToggle?.parentElement.nextElementSibling?.querySelector('.status-text');
536 - if (statusToggle && statusText) {
537 - statusToggle.addEventListener('change', function() {
538 - // Update display text
539 - statusText.textContent = this.checked ? 'Online' : 'Offline';
540 -
541 - // Send the correct on/off value to the server
542 - if (window.mxchatSaveSetting) {
543 - window.mxchatSaveSetting('live_agent_status', this.checked ? 'on' : 'off');
544 - }
545 - });
546 - }
547 -
548 -
549 -});
550 -
551 -
552 -
1 +function mxchatOpenEditModal(intentId, phrases) {
2 + const modal = document.getElementById('mxchat-edit-modal');
3 + if (!modal) return;
4 + const intentIdField = document.getElementById('edit_intent_id');
5 + const phrasesField = document.getElementById('edit_phrases');
6 +
7 + intentIdField.value = intentId;
8 + phrasesField.value = phrases;
9 + modal.style.display = 'block';
10 +}
11 +
12 +
13 +
14 +
15 +jQuery(document).ready(function($) {
16 + //console.log('Script loaded'); // Confirm script is loading
17 +
18 +
19 +// --- AJAX Auto-Save ---
20 +// Only target elements within the autosave sections
21 +const $autosaveSections = $('.mxchat-autosave-section');
22 +
23 +if ($autosaveSections.length) {
24 + // Handle real-time range slider value updates
25 + $autosaveSections.find('input[type="range"]').on('input', function() {
26 + const value = $(this).val();
27 + $('#threshold_value').text(value);
28 + });
29 +
30 + // Handle all input changes (including range slider)
31 + $autosaveSections.find('input, textarea, select').on('change', function() {
32 + const $field = $(this);
33 + const name = $field.attr('name');
34 + let value;
35 +
36 + // Handle different input types
37 + if ($field.attr('type') === 'checkbox') {
38 + value = $field.is(':checked') ? 'on' : 'off';
39 + } else {
40 + value = $field.val();
41 + }
42 +
43 + // Create feedback container
44 + const feedbackContainer = $('<div class="feedback-container"></div>');
45 + const spinner = $('<div class="saving-spinner"></div>');
46 + const successIcon = $('<div class="success-icon">✔</div>');
47 +
48 + // Position feedback container based on input type
49 + if ($field.closest('.toggle-switch').length) {
50 + $field.closest('.toggle-switch').after(feedbackContainer);
51 + } else if ($field.closest('.slider-container').length) {
52 + $field.closest('.slider-container').after(feedbackContainer);
53 + } else {
54 + $field.after(feedbackContainer);
55 + }
56 + feedbackContainer.append(spinner);
57 +
58 + // AJAX save request
59 + $.ajax({
60 + url: mxchatAdmin.ajax_url,
61 + type: 'POST',
62 + data: {
63 + action: 'mxchat_save_setting',
64 + name: name,
65 + value: value,
66 + _ajax_nonce: mxchatAdmin.setting_nonce
67 + },
68 + success: function(response) {
69 + if (response.success) {
70 + spinner.fadeOut(200, function() {
71 + feedbackContainer.append(successIcon);
72 + successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
73 + feedbackContainer.remove();
74 + });
75 + });
76 + } else {
77 + alert('Error saving: ' + response.data.message);
78 + if ($field.attr('type') === 'checkbox') {
79 + $field.prop('checked', !$field.is(':checked'));
80 + }
81 + feedbackContainer.remove();
82 + }
83 + },
84 + error: function() {
85 + alert('An error occurred while saving.');
86 + if ($field.attr('type') === 'checkbox') {
87 + $field.prop('checked', !$field.is(':checked'));
88 + }
89 + feedbackContainer.remove();
90 + }
91 + });
92 + });
93 +
94 + // Initialize color pickers with debouncing
95 + $autosaveSections.find('.my-color-field').wpColorPicker({
96 + change: _.debounce(function(event, ui) {
97 + const $field = $(this);
98 + const name = $field.attr('name');
99 + const value = $field.val();
100 +
101 + // Create feedback container
102 + const feedbackContainer = $('<div class="feedback-container"></div>');
103 + const spinner = $('<div class="saving-spinner"></div>');
104 + const successIcon = $('<div class="success-icon">✔</div>');
105 +
106 + // Position feedback container
107 + $field.closest('.wp-picker-container').after(feedbackContainer);
108 + feedbackContainer.append(spinner);
109 +
110 + // AJAX save request
111 + $.ajax({
112 + url: mxchatAdmin.ajax_url,
113 + type: 'POST',
114 + data: {
115 + action: 'mxchat_save_setting',
116 + name: name,
117 + value: value,
118 + _ajax_nonce: mxchatAdmin.setting_nonce
119 + },
120 + success: function(response) {
121 + if (response.success) {
122 + spinner.fadeOut(200, function() {
123 + feedbackContainer.append(successIcon);
124 + successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
125 + feedbackContainer.remove();
126 + });
127 + });
128 + } else {
129 + alert('Error saving: ' + response.data.message);
130 + feedbackContainer.remove();
131 + }
132 + },
133 + error: function() {
134 + alert('An error occurred while saving.');
135 + feedbackContainer.remove();
136 + }
137 + });
138 + }, 500)
139 + });
140 +}
141 +
142 + // --- Tab Navigation and Toggles ---
143 +
144 + $('.mxchat-nav-tab').on('click', function(e) {
145 + e.preventDefault();
146 + $('.mxchat-nav-tab').removeClass('mxchat-nav-tab-active');
147 + $(this).addClass('mxchat-nav-tab-active');
148 + $('.mxchat-tab-content').removeClass('active').hide();
149 + var activeTab = $(this).attr('href');
150 + $(activeTab).addClass('active').show();
151 + });
152 +
153 + // Activate the first tab by default
154 + $('.mxchat-nav-tab-active').trigger('click');
155 +
156 +
157 + // Attach click event to dynamically call the function
158 + $(document).on('click', '.mxchat-edit-button', function() {
159 + const intentId = $(this).data('intent-id');
160 + const phrases = $(this).data('phrases');
161 + mxchatOpenEditModal(intentId, phrases);
162 + });
163 +
164 + // Toggle visibility of various API keys
165 + function toggleVisibility(selector) {
166 + $(selector).on('click', function() {
167 + var inputField = $(this).prev('input');
168 + if (inputField.attr('type') === 'password') {
169 + inputField.attr('type', 'text');
170 + $(this).text('Hide');
171 + } else {
172 + inputField.attr('type', 'password');
173 + $(this).text('Show');
174 + }
175 + });
176 + }
177 + toggleVisibility('#toggleApiKeyVisibility');
178 + toggleVisibility('#toggleWooCommerceSecretVisibility');
179 + toggleVisibility('#toggleLoopsApiKeyVisibility');
180 + toggleVisibility('#toggleXaiApiKeyVisibility');
181 + toggleVisibility('#toggleClaudeApiKeyVisibility');
182 + toggleVisibility('#toggleBraveApiKeyVisibility');
183 + toggleVisibility('#toggleWebhookUrlVisibility');
184 + toggleVisibility('#toggleSecretKeyVisibility');
185 + toggleVisibility('#toggleBotTokenVisibility');
186 + toggleVisibility('#toggleDeepSeekApiKeyVisibility');
187 +
188 +
189 + // --- Add Intent Form Submission ---
190 +
191 + $('#mxchat-add-intent-form').on('submit', function(event) {
192 + $('#mxchat-intent-loading').show();
193 + $('#mxchat-intent-loading-text').show();
194 + $(this).find('button[type="submit"]').hide(); // Hide the submit button to prevent multiple clicks
195 + });
196 +
197 + // --- Inline Edit Functionality ---
198 +
199 + $('.edit-button').on('click', function() {
200 + var row = $(this).closest('tr');
201 + row.find('.content-view, .url-view').hide();
202 + row.find('.content-edit, .url-edit').show();
203 + row.find('.edit-button').hide();
204 + row.find('.save-button').show();
205 + });
206 +
207 +$('.save-button').on('click', function() {
208 + var button = $(this);
209 + var row = button.closest('tr');
210 + var id = button.data('id');
211 + var newContent = row.find('.content-edit').val();
212 + var newUrl = row.find('.url-edit').val();
213 +
214 + // Add loading state
215 + button.prop('disabled', true);
216 + button.text('Saving...');
217 +
218 + $.ajax({
219 + url: mxchatAdmin.ajax_url,
220 + type: 'POST',
221 + data: {
222 + action: 'mxchat_save_inline_prompt',
223 + id: id,
224 + article_content: newContent,
225 + article_url: newUrl,
226 + _ajax_nonce: mxchatAdmin.inline_edit_nonce
227 + },
228 + success: function(response) {
229 + button.prop('disabled', false);
230 + button.text('Save');
231 +
232 + if (response.success) {
233 + // Update the view
234 + row.find('.content-view').html(newContent.replace(/\n/g, "<br>"));
235 + if (newUrl) {
236 + row.find('.url-view').html('<a href="' + newUrl + '" target="_blank">' + newUrl + '</a>');
237 + } else {
238 + row.find('.url-view').html('N/A');
239 + }
240 +
241 + // Hide edit fields, show view fields
242 + row.find('.content-edit, .url-edit').hide();
243 + row.find('.content-view, .url-view').show();
244 + row.find('.save-button').hide();
245 + row.find('.edit-button').show();
246 + } else {
247 + alert('Error saving content: ' + (response.data?.message || 'Unknown error'));
248 + }
249 + },
250 + error: function() {
251 + button.prop('disabled', false);
252 + button.text('Save');
253 + alert('An error occurred while saving.');
254 + }
255 + });
256 +});
257 +
258 + // --- Activation Script ---
259 +
260 + // Select activation-related elements
261 + var form = $('#mxchat-activation-form');
262 + var spinner = $('#mxchat-activation-spinner');
263 + var submitButton = $('#activate_license_button');
264 + var licenseStatus = $('#mxchat-license-status');
265 +
266 + // Ensure essential elements exist before running activation-specific code
267 + if (form.length && licenseStatus.length && submitButton.length) {
268 + //console.log('Activation elements detected, running activation-specific code.');
269 +
270 + // Function to handle the response from the activation AJAX request
271 + function handleActivationResponse(response) {
272 + spinner.hide(); // Hide the spinner
273 +
274 + if (response.success) {
275 + // Update UI on successful activation
276 + licenseStatus.text('Active');
277 + licenseStatus.removeClass('inactive').addClass('active');
278 + form.hide(); // Hide the activation form after successful activation
279 + } else {
280 + licenseStatus.text('Inactive');
281 + alert(response.data || 'Activation failed. Please check your input.');
282 + submitButton.prop('disabled', false); // Re-enable button on failure
283 + }
284 + }
285 +
286 + // Event listener for form submission to activate the license
287 + form.on('submit', function(event) {
288 + event.preventDefault();
289 +
290 + // Show spinner and disable the submit button
291 + spinner.show();
292 + submitButton.prop('disabled', true);
293 +
294 + // Gather form data
295 + var formData = {
296 + action: 'mxchat_activate_license',
297 + mxchat_pro_email: $('#mxchat_pro_email').val(),
298 + mxchat_activation_key: $('#mxchat_activation_key').val(),
299 + security: mxchatAdmin.license_nonce // FIXED: Using correct nonce
300 + };
301 +
302 + // Send the AJAX request using jQuery
303 + $.post(mxchatAdmin.ajax_url, formData, function(response) {
304 + handleActivationResponse(response);
305 + }).fail(function() {
306 + alert('Server error. Please try again.');
307 + spinner.hide();
308 + submitButton.prop('disabled', false);
309 + });
310 + });
311 + } else {
312 + //console.log('Activation elements not found; skipping activation-specific code.');
313 + }
314 +
315 +
316 +
317 +
318 + // Handle adding new questions
319 + $('.mxchat-add-question').on('click', function () {
320 + const container = $('#mxchat-additional-questions-container');
321 + const questionCount = container.find('.mxchat-question-row').length + 4;
322 + const questionIndex = container.find('.mxchat-question-row').length;
323 +
324 + const newQuestion = `
325 + <div class="mxchat-question-row">
326 + <input type="text"
327 + name="additional_popular_questions[]"
328 + placeholder="Enter Additional Popular Question ${questionCount}"
329 + class="regular-text mxchat-question-input"
330 + data-question-index="${questionIndex}" />
331 + <button type="button" class="button mxchat-remove-question"
332 + aria-label="Remove question">Remove</button>
333 + </div>
334 + `;
335 + container.append(newQuestion);
336 + });
337 +
338 + // Handle removing questions
339 + $(document).on('click', '.mxchat-remove-question', function () {
340 + const $row = $(this).closest('.mxchat-question-row');
341 + $row.remove();
342 +
343 + // Save the updated questions array after removal
344 + saveQuestions();
345 + });
346 +
347 + // Handle question input changes
348 + $(document).on('change', '.mxchat-question-input', function() {
349 + saveQuestions();
350 + });
351 +
352 + // Function to save all questions
353 + function saveQuestions() {
354 + const questions = [];
355 + $('.mxchat-question-input').each(function() {
356 + const value = $(this).val().trim();
357 + if (value) {
358 + questions.push(value);
359 + }
360 + });
361 +
362 + // Create feedback container
363 + const feedbackContainer = $('<div class="feedback-container"></div>');
364 + const spinner = $('<div class="saving-spinner"></div>');
365 + const successIcon = $('<div class="success-icon">✔</div>');
366 +
367 + // Append feedback after the add button
368 + $('.mxchat-add-question').after(feedbackContainer);
369 + feedbackContainer.append(spinner);
370 +
371 + // Save via AJAX
372 + $.ajax({
373 + url: mxchatAdmin.ajax_url,
374 + type: 'POST',
375 + data: {
376 + action: 'mxchat_save_setting',
377 + name: 'additional_popular_questions',
378 + value: JSON.stringify(questions),
379 + _ajax_nonce: mxchatAdmin.setting_nonce
380 + },
381 + success: function(response) {
382 + if (response.success) {
383 + spinner.fadeOut(200, function() {
384 + feedbackContainer.append(successIcon);
385 + successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
386 + feedbackContainer.remove();
387 + });
388 + });
389 + } else {
390 + alert('Error saving questions: ' + response.data.message);
391 + feedbackContainer.remove();
392 + }
393 + },
394 + error: function() {
395 + alert('An error occurred while saving questions.');
396 + feedbackContainer.remove();
397 + }
398 + });
399 + }
400 +
401 +const statusToggle = document.getElementById('live_agent_status');
402 +const statusText = statusToggle?.parentElement.nextElementSibling?.querySelector('.status-text');
403 +if (statusToggle && statusText) {
404 + statusToggle.addEventListener('change', function() {
405 + // Update display text
406 + statusText.textContent = this.checked ? 'Online' : 'Offline';
407 +
408 + // Send the correct on/off value to the server
409 + if (window.mxchatSaveSetting) {
410 + window.mxchatSaveSetting('live_agent_status', this.checked ? 'on' : 'off');
411 + }
412 + });
413 +}
414 +});