PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.3.9
MxChat – AI Chatbot & Content Generation for WordPress v2.3.9
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/content-selector.js +252 -525 3.2.212.3.9 View file →
@@ -8,13 +8,11 @@
8 8 const $pagination = $('.mxchat-kb-pagination');
9 9 const $processButton = $('#mxchat-kb-process-selected');
10 10 const $selectAll = $('#mxchat-kb-select-all');
11 11 const $selectionCount = $('.mxchat-kb-selection-count');
12 - // ACF→PDF extraction is an install-level setting (Knowledge → ACF Fields);
13 - // the server reads the stored option — nothing to collect in this modal.
14 -
12 +
15 13 // Filter elements
16 - const $searchInput = $('#mxchat-kb-content-search');
14 + const $searchInput = $('#mxchat-kb-content-search');1
17 15 const $typeFilter = $('#mxchat-kb-content-type-filter');
18 16 const $statusFilter = $('#mxchat-kb-content-status-filter');
19 17 const $processedFilter = $('#mxchat-kb-processed-filter');
20 18
@@ -39,134 +37,51 @@
39 37 // Handle import option box clicks (for non-WordPress options)
40 38 $('.mxchat-import-box').on('click', function() {
41 39 const $box = $(this);
42 40 const option = $box.data('option');
43 -
41 +
44 42 // Skip if this is the WordPress option (it has its own handler)
45 43 if (option === 'wordpress') {
46 44 return;
47 45 }
48 -
46 +
49 47 // Update active state
50 48 $('.mxchat-import-box').removeClass('active');
51 49 $box.addClass('active');
52 -
50 +
53 51 // Hide all input areas
54 - $('#mxchat-url-input-area, #mxchat-content-input-area, #mxchat-pdf-upload-area, #mxchat-document-upload-area, #mxchat-youtube-input-area').hide();
55 -
56 - // Hide sitemap-specific sections (but NOT for sitemap option - let detection logic handle it)
57 - if (option !== 'sitemap') {
58 - $('#mxchat-detected-sitemaps, #mxchat-no-sitemaps, #mxchat-sitemaps-loading').hide();
59 - }
60 -
52 + $('#mxchat-url-input-area, #mxchat-content-input-area').hide();
53 +
61 54 // Handle different import options
62 55 switch (option) {
63 - case 'pdf-url':
56 + case 'pdf':
64 57 case 'sitemap':
65 58 case 'url':
66 59 // Show URL input area with appropriate placeholder
67 60 $('#mxchat-url-input-area').show();
68 61 $('#sitemap_url').attr('placeholder', $box.data('placeholder'));
69 - $('#import_type').val(option === 'pdf-url' ? 'pdf' : option);
70 -
71 - // UPDATED: Add or update bot_id hidden field for URL forms
72 - updateBotIdInForm('#mxchat-url-form');
73 -
62 + $('#import_type').val(option);
63 +
74 64 // Update the description text based on the import type
75 65 let descriptionText = '';
76 - if (option === 'pdf-url') {
66 + if (option === 'pdf') {
77 67 descriptionText = 'Import a PDF document by entering its URL above. PDFs are processed via cron job. If processing does not start, you can manually process batch 5 pages at a time.';
78 68 } else if (option === 'sitemap') {
79 69 descriptionText = 'Enter a content-specific sub-sitemap URL, not the sitemap index. Sitemaps are processed via cron job. If processing does not start, you can manually process batch 5 pages at a time.';
80 - // Re-show sitemap sections if they were previously loaded
81 - const $sitemapsList = $('#mxchat-sitemaps-list');
82 - if ($sitemapsList.children().length > 0) {
83 - // Sitemaps were already loaded, just show the container
84 - $('#mxchat-detected-sitemaps').show();
85 - } else if ($('#mxchat-no-sitemaps').data('was-shown')) {
86 - // No sitemaps message was shown before
87 - $('#mxchat-no-sitemaps').show();
88 - }
89 - // Note: If neither condition is true, initSitemapDetection will show loading state
90 70 } else if (option === 'url') {
91 71 descriptionText = 'Import content from any webpage by entering its URL.';
92 72 }
93 73 $('#url-description-text').text(descriptionText);
94 74 break;
95 -
75 +
96 76 case 'content':
97 77 // Show content input area
98 78 $('#mxchat-content-input-area').show();
99 -
100 - // UPDATED: Add or update bot_id hidden field for content forms
101 - updateBotIdInForm('#mxchat-content-form');
102 79 break;
103 -
104 - case 'pdf-upload':
105 - // Show PDF file upload area
106 - $('#mxchat-pdf-upload-area').show();
107 -
108 - // Add or update bot_id hidden field for PDF upload form
109 - updateBotIdInForm('#mxchat-pdf-upload-form');
110 - break;
111 -
112 - case 'document-upload':
113 - // Show document (.docx/.txt/.md) upload area
114 - $('#mxchat-document-upload-area').show();
115 -
116 - // Add or update bot_id hidden field for the document upload form
117 - updateBotIdInForm('#mxchat-document-upload-form');
118 - break;
119 -
120 - case 'youtube':
121 - // Show YouTube import area
122 - $('#mxchat-youtube-input-area').show();
123 -
124 - // Add or update bot_id hidden field for YouTube form
125 - updateBotIdInForm('#mxchat-youtube-form');
126 - break;
127 80 }
128 81 });
129 82
130 -// YouTube import: toggle the manual-description box with the mode radios, and
131 -// only require the textarea when "Write my own" is selected.
132 -$(document).on('change', 'input[name="youtube_description_mode"]', function() {
133 - const manual = $('input[name="youtube_description_mode"]:checked').val() === 'manual';
134 - $('#mxchat-youtube-description-field').toggle(manual);
135 - $('#mxchat-youtube-description').prop('required', manual);
136 -});
137 83
138 -// If the server bounced back with prefill state (auto-import found no
139 -// transcript), reopen the YouTube form in manual mode ready to augment.
140 -if ($('#mxchat-youtube-form').data('yt-prefill')) {
141 - $('.mxchat-import-box[data-option="youtube"]').trigger('click');
142 - $('input[name="youtube_description_mode"]').trigger('change');
143 - $('#mxchat-youtube-description').trigger('focus');
144 -}
145 -
146 -// Helper function to add/update bot_id hidden field in forms
147 -function updateBotIdInForm(formSelector) {
148 - const $form = $(formSelector);
149 - if ($form.length === 0) return;
150 -
151 - // Get current bot_id from the bot selector dropdown
152 - const currentBotId = $('#mxchat-bot-selector').val();
153 -
154 - // Only add bot_id field if multi-bot is active and bot is not 'default'
155 - if (currentBotId && currentBotId !== 'default') {
156 - // Remove existing bot_id field if it exists
157 - $form.find('input[name="bot_id"]').remove();
158 -
159 - // Add new bot_id field
160 - $form.append('<input type="hidden" name="bot_id" value="' + currentBotId + '">');
161 -
162 - console.log('Updated bot_id in form ' + formSelector + ' to: ' + currentBotId);
163 - } else {
164 - // Remove bot_id field if bot is default
165 - $form.find('input[name="bot_id"]').remove();
166 - }
167 -}
168 -
169 84 // Load content via AJAX
170 85 function loadContent() {
171 86 $loading.show();
172 87 $contentList.find('.mxchat-kb-content-item').remove();
@@ -174,9 +89,9 @@
174 89 const data = {
175 90 action: 'mxchat_get_content_list',
176 91 nonce: mxchatSelector.nonce,
177 92 page: currentPage,
178 - per_page: 100,
93 + per_page: 50,
179 94 search: $searchInput.val(),
180 95 post_type: $typeFilter.val(),
181 96 post_status: $statusFilter.val(),
182 97 processed_filter: $processedFilter.val()
@@ -241,22 +156,18 @@
241 156
242 157 // Render content items
243 158 function renderContentItems(items) {
244 159 let html = '';
245 -
160 +
246 161 items.forEach(function(item) {
247 162 const isSelected = selectedItems.has(item.id);
248 163 const isProcessed = item.already_processed;
249 - const chunkCount = item.chunk_count || 0;
250 -
251 - // Updated badge text - include chunk count if > 1
252 - let badgeText = 'Not In Knowledge Base';
253 - if (isProcessed) {
254 - badgeText = chunkCount > 1 ? `In Knowledge Base (${chunkCount} chunks)` : 'In Knowledge Base';
255 - }
164 +
165 + // Updated badge text
166 + const badgeText = isProcessed ? 'In Knowledge Base' : 'Not In Knowledge Base';
256 167 const badgeClass = isProcessed ? 'mxchat-kb-processed-badge' : 'mxchat-kb-unprocessed-badge';
257 -
258 -
168 +
169 +
259 170 html += `
260 171 <div class="mxchat-kb-content-item ${isProcessed ? 'processed' : ''}" data-id="${item.id}">
261 172 <div class="mxchat-kb-content-checkbox">
262 173 <input type="checkbox" id="content-${item.id}" ${isSelected ? 'checked' : ''}>
@@ -276,9 +187,9 @@
276 187 </div>
277 188 </div>
278 189 `;
279 190 });
280 -
191 +
281 192 $contentList.html(html);
282 193
283 194 // Add event listeners for checkboxes using delegation for better performance
284 195 $contentList.off('change', 'input[type="checkbox"]').on('change', 'input[type="checkbox"]', function() {
@@ -351,36 +262,18 @@
351 262 function updateSelection() {
352 263 const selectedCount = selectedItems.size;
353 264 $selectionCount.text(selectedCount + ' ' + (selectedCount === 1 ? 'selected' : 'selected'));
354 265 $('.mxchat-kb-selected-count').text('(' + selectedCount + ')');
355 -
356 - // Show/hide clear all selections link
357 - let $clearAllLink = $('.mxchat-kb-clear-all-selections');
358 - if (selectedCount > 0) {
359 - if ($clearAllLink.length === 0) {
360 - $clearAllLink = $('<a href="#" class="mxchat-kb-clear-all-selections" style="margin-left: 10px; font-size: 12px; color: var(--mxch-error, #dc2626);">Clear all</a>');
361 - $selectionCount.after($clearAllLink);
362 - $clearAllLink.on('click', function(e) {
363 - e.preventDefault();
364 - selectedItems.clear();
365 - $('.mxchat-kb-content-item input[type="checkbox"]').prop('checked', false);
366 - updateSelection();
367 - });
368 - }
369 - $clearAllLink.show();
370 - } else {
371 - $clearAllLink.hide();
372 - }
373 -
266 +
374 267 // Determine if any selected items are already processed
375 268 const hasProcessedItems = Array.from(selectedItems).some(id => {
376 269 const item = allItems.find(item => item.id === id);
377 270 return item && item.already_processed;
378 271 });
379 -
272 +
380 273 if (selectedCount > 0) {
381 274 $processButton.prop('disabled', false);
382 -
275 +
383 276 // Update button text based on selection
384 277 if (hasProcessedItems && selectedCount === 1) {
385 278 $processButton.text('Update Selected Content (1)').addClass('update-mode');
386 279 } else if (hasProcessedItems && selectedCount > 1) {
@@ -392,9 +285,9 @@
392 285 $processButton.prop('disabled', true);
393 286 $processButton.text('Process Selected Content').removeClass('update-mode mixed-mode');
394 287 $('.mxchat-kb-selected-count').text('(0)');
395 288 }
396 -
289 +
397 290 updateSelectAllState();
398 291 }
399 292
400 293 // Update "Select All" checkbox state
@@ -449,399 +342,295 @@
449 342 selectedItems.clear(); // Clear selection when filter changes
450 343 loadContent();
451 344 });
452 345
453 -// Process selected content
454 -$processButton.on('click', function() {
455 - if (selectedItems.size === 0) {
456 - return;
457 - }
458 -
459 - const $button = $(this);
460 - $button.prop('disabled', true);
461 -
462 - // Update button text based on mode
463 - if ($button.hasClass('update-mode')) {
464 - $button.text('Updating...');
465 - } else if ($button.hasClass('mixed-mode')) {
466 - $button.text('Processing/Updating...');
467 - } else {
468 - $button.text('Processing...');
469 - }
470 -
471 - // Convert selected items to array
472 - const selectedPostIds = Array.from(selectedItems);
473 - const totalToProcess = selectedPostIds.length;
474 - let processed = 0;
475 - let updated = 0;
476 - let failed = 0;
477 - const results = {
478 - success: [],
479 - updated: [],
480 - failed: []
481 - };
482 -
483 - // UPDATED: Get current bot_id for WordPress content processing
484 - const currentBotId = $('#mxchat-bot-selector').val();
485 -
486 - // Flag to track if processing should be aborted
487 - let abortProcessing = false;
488 - let currentXHR = null;
489 -
490 - // Create a modal to show progress with stop button
491 - const $progressModal = $('<div class="mxchat-kb-processing-overlay">' +
492 - '<div class="mxchat-kb-processing-content">' +
493 - '<h3>Processing Content</h3>' +
494 - '<p class="mxchat-kb-processing-status">Processing 1 of ' + totalToProcess + '...</p>' +
495 - '<div class="mxchat-kb-progress-bar"><div class="mxchat-kb-progress-fill" style="width: 0%"></div></div>' +
496 - '<p class="mxchat-kb-current-item"></p>' +
497 - '<button type="button" class="mxchat-kb-stop-processing mxch-btn mxch-btn-secondary" style="margin-top: 15px;">' +
498 - '<span class="dashicons dashicons-controls-pause" style="margin-right: 5px;"></span>Stop Processing</button>' +
499 - '</div>' +
500 - '</div>');
501 -
502 - $('body').append($progressModal);
503 -
504 - // Handle stop button click
505 - $progressModal.find('.mxchat-kb-stop-processing').on('click', function() {
506 - abortProcessing = true;
507 - $(this).prop('disabled', true).html('<span class="dashicons dashicons-update spin" style="margin-right: 5px;"></span>Stopping...');
508 - if (currentXHR) {
509 - currentXHR.abort();
510 - }
511 - });
512 -
513 - // Process posts one by one
514 - function processNext(index) {
515 - // Check if processing was aborted
516 - if (abortProcessing) {
517 - finishProcessing(true); // Pass true to indicate abort
346 + // Process selected content
347 + $processButton.on('click', function() {
348 + if (selectedItems.size === 0) {
518 349 return;
519 350 }
520 -
521 - if (index >= selectedPostIds.length) {
522 - // All done
523 - finishProcessing();
524 - return;
351 +
352 + const $button = $(this);
353 + $button.prop('disabled', true);
354 +
355 + // Update button text based on mode
356 + if ($button.hasClass('update-mode')) {
357 + $button.text('Updating...');
358 + } else if ($button.hasClass('mixed-mode')) {
359 + $button.text('Processing/Updating...');
360 + } else {
361 + $button.text('Processing...');
525 362 }
526 -
527 - const postId = selectedPostIds[index];
528 - const percent = Math.round((index / totalToProcess) * 100);
529 - const item = allItems.find(item => item.id === postId);
530 - const isUpdate = item && item.already_processed;
531 -
532 - // Update progress UI
533 - $progressModal.find('.mxchat-kb-processing-status')
534 - .text((isUpdate ? 'Updating' : 'Processing') + ' ' + (index + 1) + ' of ' + totalToProcess + '...');
535 - $progressModal.find('.mxchat-kb-progress-fill').css('width', percent + '%');
536 -
537 - // UPDATED: Prepare AJAX data with bot_id
538 - const ajaxData = {
539 - action: 'mxchat_process_selected_content',
540 - nonce: mxchatSelector.nonce,
541 - post_ids: [postId],
542 - is_update: isUpdate
363 +
364 + // Convert selected items to array
365 + const selectedPostIds = Array.from(selectedItems);
366 + const totalToProcess = selectedPostIds.length;
367 + let processed = 0;
368 + let updated = 0;
369 + let failed = 0;
370 + const results = {
371 + success: [],
372 + updated: [],
373 + failed: []
543 374 };
544 -
545 - // Add bot_id if multi-bot is active and not default
546 - if (currentBotId && currentBotId !== 'default') {
547 - ajaxData.bot_id = currentBotId;
548 - }
549 -
550 - // Make AJAX request for this post (store reference for potential abort)
551 - currentXHR = $.ajax({
552 - url: mxchatSelector.ajaxurl,
553 - method: 'POST',
554 - data: ajaxData,
555 - dataType: 'json',
556 - success: function(response) {
557 - if (response.success) {
558 - if (isUpdate) {
559 - updated++;
560 - results.updated.push({
561 - id: postId,
562 - title: response.data.title || ('ID: ' + postId)
563 - });
375 +
376 + // Create a modal to show progress
377 + const $progressModal = $('<div class="mxchat-kb-processing-overlay">' +
378 + '<div class="mxchat-kb-processing-content">' +
379 + '<h3>Processing Content</h3>' +
380 + '<p class="mxchat-kb-processing-status">Processing 1 of ' + totalToProcess + '...</p>' +
381 + '<div class="mxchat-kb-progress-bar"><div class="mxchat-kb-progress-fill" style="width: 0%"></div></div>' +
382 + '<p class="mxchat-kb-current-item"></p>' +
383 + '</div>' +
384 + '</div>');
385 +
386 + $('body').append($progressModal);
387 +
388 + // Process posts one by one
389 + function processNext(index) {
390 + if (index >= selectedPostIds.length) {
391 + // All done
392 + finishProcessing();
393 + return;
394 + }
395 +
396 + const postId = selectedPostIds[index];
397 + const percent = Math.round((index / totalToProcess) * 100);
398 + const item = allItems.find(item => item.id === postId);
399 + const isUpdate = item && item.already_processed;
400 +
401 + // Update progress UI
402 + $progressModal.find('.mxchat-kb-processing-status')
403 + .text((isUpdate ? 'Updating' : 'Processing') + ' ' + (index + 1) + ' of ' + totalToProcess + '...');
404 + $progressModal.find('.mxchat-kb-progress-fill').css('width', percent + '%');
405 +
406 + // Make AJAX request for this post
407 + $.ajax({
408 + url: mxchatSelector.ajaxurl,
409 + method: 'POST',
410 + data: {
411 + action: 'mxchat_process_selected_content',
412 + nonce: mxchatSelector.nonce,
413 + post_ids: [postId],
414 + is_update: isUpdate
415 + },
416 + dataType: 'json',
417 + success: function(response) {
418 + if (response.success) {
419 + if (isUpdate) {
420 + updated++;
421 + results.updated.push({
422 + id: postId,
423 + title: response.data.title || ('ID: ' + postId)
424 + });
425 + } else {
426 + processed++;
427 + results.success.push({
428 + id: postId,
429 + title: response.data.title || ('ID: ' + postId)
430 + });
431 + }
432 +
433 + $progressModal.find('.mxchat-kb-current-item')
434 + .text('Successfully ' + (isUpdate ? 'updated' : 'processed') + ': ' + response.data.title);
564 435 } else {
565 - processed++;
566 - results.success.push({
436 + failed++;
437 + results.failed.push({
567 438 id: postId,
568 - title: response.data.title || ('ID: ' + postId)
439 + error: response.data || 'Unknown error'
569 440 });
441 +
442 + $progressModal.find('.mxchat-kb-current-item')
443 + .text('Failed to ' + (isUpdate ? 'update' : 'process') + ' ID: ' + postId);
570 444 }
571 445
572 - let successText = 'Successfully ' + (isUpdate ? 'updated' : 'processed') + ': ' + response.data.title;
573 - const pdfCount = parseInt(response.data.pdf_extracted_count, 10) || 0;
574 - if (pdfCount > 0) {
575 - const suffixTpl = (mxchatSelector.i18n && mxchatSelector.i18n.pdfExtractedSuffix) || ' (%d PDF(s) extracted)';
576 - successText += suffixTpl.replace('%d', pdfCount);
577 - }
578 - $progressModal.find('.mxchat-kb-current-item').text(successText);
579 - } else {
446 + // Process next post
447 + setTimeout(function() {
448 + processNext(index + 1);
449 + }, 500); // Small delay between requests
450 + },
451 + error: function(xhr, status, error) {
580 452 failed++;
581 453 results.failed.push({
582 454 id: postId,
583 - error: response.data || 'Unknown error'
455 + error: error || 'Server error'
584 456 });
585 457
586 458 $progressModal.find('.mxchat-kb-current-item')
587 - .text('Failed to ' + (isUpdate ? 'update' : 'process') + ' ID: ' + postId);
459 + .text('Error ' + (isUpdate ? 'updating' : 'processing') + ' ID: ' + postId);
460 +
461 + // Process next post
462 + setTimeout(function() {
463 + processNext(index + 1);
464 + }, 500);
588 465 }
466 + });
467 + }
468 +
469 + // Function to finish processing and show results
470 + function finishProcessing() {
471 + // Remove progress modal
472 + $progressModal.remove();
473 +
474 + // Determine notification type based on results
475 + let notificationClass = 'success';
476 + if (failed > 0) {
477 + notificationClass = processed > 0 || updated > 0 ? 'warning' : 'error';
478 + }
479 +
480 + // Create summary message
481 + let resultHTML = '<div class="mxchat-kb-notification ' + notificationClass + '">' +
482 + '<h4>';
483 +
484 + if (processed > 0 && updated > 0) {
485 + resultHTML += 'Processed ' + processed + ' new items and updated ' + updated + ' existing items';
486 + } else if (processed > 0) {
487 + resultHTML += 'Processed ' + processed + ' items successfully';
488 + } else if (updated > 0) {
489 + resultHTML += 'Updated ' + updated + ' items successfully';
490 + } else {
491 + resultHTML += 'No items were processed successfully';
492 + }
493 +
494 + if (failed > 0) {
495 + resultHTML += ' with ' + failed + ' failures';
496 + }
497 +
498 + resultHTML += '</h4>';
499 +
500 + // Add details if there were failures
501 + if (failed > 0) {
502 + resultHTML += '<div class="mxchat-kb-results-details">';
503 + resultHTML += '<h5>Failed Items:</h5><ul>';
589 504
590 - // Process next post
591 - setTimeout(function() {
592 - processNext(index + 1);
593 - }, 500); // Small delay between requests
594 - },
595 - error: function(xhr, status, error) {
596 - failed++;
597 - results.failed.push({
598 - id: postId,
599 - error: error || 'Server error'
505 + results.failed.forEach(function(item) {
506 + resultHTML += '<li><strong>ID: ' + item.id + '</strong>: ' + item.error + '</li>';
600 507 });
601 508
602 - $progressModal.find('.mxchat-kb-current-item')
603 - .text('Error ' + (isUpdate ? 'updating' : 'processing') + ' ID: ' + postId);
604 -
605 - // Process next post
606 - setTimeout(function() {
607 - processNext(index + 1);
608 - }, 500);
509 + resultHTML += '</ul></div>';
609 510 }
610 - });
611 - }
612 -
613 - // Function to finish processing and show results
614 - function finishProcessing(wasAborted) {
615 - // Remove progress modal
616 - $progressModal.remove();
617 -
618 - // Determine notification type based on results
619 - let notificationClass = 'success';
620 - if (wasAborted) {
621 - notificationClass = processed > 0 || updated > 0 ? 'warning' : 'info';
622 - } else if (failed > 0) {
623 - notificationClass = processed > 0 || updated > 0 ? 'warning' : 'error';
624 - }
625 -
626 - // Create summary message
627 - let resultHTML = '<div class="mxchat-kb-notification ' + notificationClass + '">' +
628 - '<h4>';
629 -
630 - if (wasAborted) {
631 - resultHTML += 'Processing stopped. ';
511 +
512 + resultHTML += '</div>';
513 +
514 + // Show results in modal
515 + $modal.find('.mxchat-kb-modal-content').prepend($(resultHTML));
516 +
517 + // Clear selection
518 + selectedItems.clear();
519 + updateSelection();
520 +
521 + // Enable button
522 + $button.prop('disabled', false)
523 + .text('Process Selected Content')
524 + .removeClass('update-mode mixed-mode');
525 + $('.mxchat-kb-selected-count').text('(0)');
526 +
527 + // Only reload if there were successful operations
632 528 if (processed > 0 || updated > 0) {
633 - resultHTML += 'Completed ' + (processed + updated) + ' of ' + totalToProcess + ' items before stopping';
634 - } else {
635 - resultHTML += 'No items were processed before stopping';
529 + // Reload after delay
530 + setTimeout(function() {
531 + // Reload the knowledge base table - if this function exists
532 + if (typeof reloadKnowledgeBaseTable === 'function') {
533 + reloadKnowledgeBaseTable();
534 + } else {
535 + // Fallback: reload content list instead of full page reload
536 + loadContent();
537 + }
538 + }, 3000);
636 539 }
637 - } else if (processed > 0 && updated > 0) {
638 - resultHTML += 'Processed ' + processed + ' new items and updated ' + updated + ' existing items';
639 - } else if (processed > 0) {
640 - resultHTML += 'Processed ' + processed + ' items successfully';
641 - } else if (updated > 0) {
642 - resultHTML += 'Updated ' + updated + ' items successfully';
643 - } else {
644 - resultHTML += 'No items were processed successfully';
645 540 }
646 -
647 - if (failed > 0 && !wasAborted) {
648 - resultHTML += ' with ' + failed + ' failures';
649 - }
650 541
651 - resultHTML += '</h4>';
652 -
653 - // Add details if there were failures
654 - if (failed > 0) {
655 - resultHTML += '<div class="mxchat-kb-results-details">';
656 - resultHTML += '<h5>Failed Items:</h5><ul>';
657 -
658 - results.failed.forEach(function(item) {
659 - resultHTML += '<li><strong>ID: ' + item.id + '</strong>: ' + item.error + '</li>';
660 - });
661 -
662 - resultHTML += '</ul></div>';
663 - }
664 -
665 - resultHTML += '</div>';
666 -
667 - // Show results in modal
668 - $modal.find('.mxchat-kb-modal-content').prepend($(resultHTML));
669 -
670 - // Clear selection
671 - selectedItems.clear();
672 - updateSelection();
673 -
674 - // Enable button
675 - $button.prop('disabled', false)
676 - .text('Process Selected Content')
677 - .removeClass('update-mode mixed-mode');
678 - $('.mxchat-kb-selected-count').text('(0)');
542 + // Start processing the first post
543 + processNext(0);
544 + });
679 545
680 - // Only reload if there were successful operations
681 - if (processed > 0 || updated > 0) {
682 - // Refresh the knowledge base table with properly grouped entries
683 - if (typeof window.refreshKnowledgeBaseTable === 'function') {
684 - window.refreshKnowledgeBaseTable();
685 - }
686 -
687 - // Reload content list to update "already processed" status
688 - setTimeout(function() {
689 - loadContent();
690 - }, 1000);
691 - }
692 - }
693 -
694 - // Start processing the first post
695 - processNext(0);
696 -});
697 -
698 546 // Initialize - Set WordPress as the active option by default
699 547 $('.mxchat-import-box[data-option="wordpress"]').addClass('active');
700 548 });
701 549
702 -// Navigation functionality for Knowledge Base page
550 +// Tab switching functionality - Keep this separate
703 551 jQuery(document).ready(function($) {
704 -
705 - // Hook into the new navigation system using .mxch-nav-link
706 - $(document).on('click', '.mxch-nav-link[data-target], .mxch-mobile-nav-link[data-target]', function() {
707 - var target = $(this).data('target');
708 -
709 - // Initialize Pinecone functionality when Pinecone section is activated
710 - if (target === 'pinecone') {
711 - setTimeout(function() {
712 - if (typeof initPineconeFeatures === 'function') {
713 - initPineconeFeatures();
714 - }
715 - }, 100);
552 +
553 +// Tab switching functionality
554 +// Modified tab switching to check for Pinecone changes
555 +$('.mxchat-kb-tab-button').on('click', function() {
556 + var tabId = $(this).data('tab');
557 + var $button = $(this);
558 +
559 + // Switch tabs immediately for all tabs
560 + $('.mxchat-kb-tab-button').removeClass('active');
561 + $('.mxchat-kb-tab-content').removeClass('active');
562 + $button.addClass('active');
563 + $('#mxchat-kb-tab-' + tabId).addClass('active');
564 +
565 + // Check if Pinecone was changed and we're going to import tab
566 + if (tabId === 'import' && sessionStorage.getItem('mxchat_pinecone_changed') === 'true') {
567 + sessionStorage.removeItem('mxchat_pinecone_changed');
568 +
569 + // Show refresh notice
570 + var $knowledgeCard = $('#mxchat-kb-tab-import .mxchat-card').eq(1);
571 + if ($knowledgeCard.length > 0 && $knowledgeCard.find('.notice-warning').length === 0) {
572 + var refreshNotice = $('<div class="notice notice-warning" style="margin: 15px 0; padding: 10px 15px;">' +
573 + '<p style="margin: 0;">' +
574 + '<span class="dashicons dashicons-info" style="color: #f0ad4e; margin-right: 5px;"></span>' +
575 + 'Database settings have changed. ' +
576 + '<a href="#" onclick="location.reload(); return false;" style="font-weight: bold;">Click here to refresh</a> to see the updated knowledge base.' +
577 + '</p></div>');
578 +
579 + $knowledgeCard.prepend(refreshNotice);
716 580 }
717 -
718 - // Initialize OpenAI Vector Store functionality when Vector Store section is activated
719 - if (target === 'openai-vectorstore') {
720 - setTimeout(function() {
721 - if (typeof initVectorStoreFeatures === 'function') {
722 - initVectorStoreFeatures();
723 - }
724 - }, 100);
725 - }
726 -
727 - // Check if Pinecone was changed and we're going to import section
728 - if (target === 'import' && sessionStorage.getItem('mxchat_pinecone_changed') === 'true') {
729 - sessionStorage.removeItem('mxchat_pinecone_changed');
730 -
731 - // Show refresh notice
732 - var $knowledgeCard = $('#import .mxch-card').eq(1);
733 - if ($knowledgeCard.length > 0 && $knowledgeCard.find('.notice-warning').length === 0) {
734 - var refreshNotice = $('<div class="notice notice-warning" style="margin: 15px 0; padding: 10px 15px;">' +
735 - '<p style="margin: 0;">' +
736 - '<span class="dashicons dashicons-info" style="color: #f0ad4e; margin-right: 5px;"></span>' +
737 - 'Database settings have changed. ' +
738 - '<a href="#" onclick="location.reload(); return false;" style="font-weight: bold;">Click here to refresh</a> to see the updated knowledge base.' +
739 - '</p></div>');
740 -
741 - $knowledgeCard.prepend(refreshNotice);
742 - }
743 - }
744 - });
745 -
746 - // Also check on page load if we're already on one of these sections
747 - setTimeout(function() {
748 - if ($('#pinecone').is(':visible') || $('#pinecone.active').length > 0) {
749 - if (typeof initPineconeFeatures === 'function') {
750 - initPineconeFeatures();
751 - }
752 - }
753 -
754 - if ($('#openai-vectorstore').is(':visible') || $('#openai-vectorstore.active').length > 0) {
755 - if (typeof initVectorStoreFeatures === 'function') {
756 - initVectorStoreFeatures();
757 - }
758 - }
759 - }, 200);
581 + }
582 +
583 + // Initialize Pinecone functionality when Pinecone tab is activated
584 + if (tabId === 'pinecone') {
585 + setTimeout(function() {
586 + initPineconeFeatures();
587 + }, 100);
588 + }
760 589 });
761 590
762 -// Pinecone and Vector Store functionality - global functions
763 -var initPineconeFeatures, initVectorStoreFeatures;
764 591
765 -(function($) {
766 -
767 - // Helper function to update sidebar badge when integration is toggled
768 - function updateSidebarBadge(section, isActive) {
769 - // Find the nav item for this section (both desktop and mobile)
770 - var $desktopNavItem = $('.mxch-nav-item[data-section="' + section + '"] .mxch-nav-link');
771 - var $mobileNavItem = $('.mxch-mobile-nav-link[data-target="' + section + '"]');
772 -
773 - // Remove existing badge if any
774 - $desktopNavItem.find('.mxch-active-badge').remove();
775 - $mobileNavItem.find('.mxch-active-badge').remove();
776 -
777 - // Add badge if active
778 - if (isActive) {
779 - var badgeHtml = '<span class="mxch-nav-link-badge mxch-active-badge">Active</span>';
780 - $desktopNavItem.append(badgeHtml);
781 - $mobileNavItem.append(badgeHtml);
782 - }
783 - }
784 -
785 592 // Pinecone functionality
786 - initPineconeFeatures = function() {
787 - // Check for either old or new section ID
788 - if ($('#pinecone').length === 0 && $('#mxchat-kb-tab-pinecone').length === 0) {
593 + function initPineconeFeatures() {
594 + //console.log('Initializing Pinecone features...');
595 +
596 + if ($('#mxchat-kb-tab-pinecone').length === 0) {
789 597 return;
790 598 }
791 -
599 +
792 600 initPineconeToggle();
793 601 initPineconeConnectionTest();
794 602 checkPineconeCompatibility();
795 - };
796 -
603 + }
604 +
797 605 function initPineconeToggle() {
798 606 // Remove any existing handlers to prevent duplicates
799 - var $toggleInput = $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]');
800 - $toggleInput.off('change.pineconeToggle');
801 -
802 - // Ensure the success notice exists in the settings div (add if not present)
803 - // Check for both the JS-added class and any existing PHP-rendered success notice
804 - var settingsDiv = $('.mxchat-pinecone-settings');
805 - if (settingsDiv.length > 0 && settingsDiv.find('.mxch-notice-success').length === 0) {
806 - var successNotice = $('<div class="mxch-notice mxch-notice-success mxchat-pinecone-enabled-notice" style="margin-bottom: 20px; display: none;">' +
807 - '<svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' +
808 - '<span>Pinecone is enabled. All new knowledge base content will be stored in Pinecone.</span>' +
809 - '</div>');
810 - settingsDiv.prepend(successNotice);
811 - }
812 -
607 + $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').off('change.pineconeToggle');
608 +
813 609 // Add the toggle handler for UI only (auto-save will handle the actual saving)
814 - $toggleInput.on('change.pineconeToggle', function() {
610 + $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]').on('change.pineconeToggle', function() {
815 611 var $checkbox = $(this);
816 612 var isChecked = $checkbox.is(':checked');
817 613 var settingsDiv = $('.mxchat-pinecone-settings');
818 - var enabledNotice = settingsDiv.find('.mxchat-pinecone-enabled-notice, .mxch-notice-success');
819 -
614 +
615 + //console.log('Pinecone toggle changed to:', isChecked);
616 +
820 617 // Update the UI immediately
821 618 if (isChecked) {
822 619 settingsDiv.slideDown(300);
823 - enabledNotice.slideDown(300);
824 620 } else {
825 - enabledNotice.slideUp(300);
826 621 settingsDiv.slideUp(300);
827 622 }
828 -
829 - // Update sidebar badge for Pinecone
830 - updateSidebarBadge('pinecone', isChecked);
831 623 });
832 -
624 +
833 625 // Set initial state based on current checkbox value
834 626 var currentToggle = $('input[name="mxchat_pinecone_addon_options[mxchat_use_pinecone]"]');
835 627 if (currentToggle.length > 0) {
836 628 var settingsDiv = $('.mxchat-pinecone-settings');
837 - var enabledNotice = settingsDiv.find('.mxchat-pinecone-enabled-notice, .mxch-notice-success');
838 629 if (currentToggle.is(':checked')) {
839 630 settingsDiv.show();
840 - enabledNotice.show();
841 631 } else {
842 632 settingsDiv.hide();
843 - enabledNotice.hide();
844 633 }
845 634 }
846 635 }
847 636
@@ -938,68 +727,6 @@
938 727 }
939 728 });
940 729 }
941 730 }
942 -
943 - // ============================================
944 - // OpenAI Vector Store functionality
945 - // ============================================
946 - initVectorStoreFeatures = function() {
947 - if ($('#openai-vectorstore').length === 0) {
948 - return;
949 - }
950 -
951 - initVectorStoreToggle();
952 - };
953 -
954 - function initVectorStoreToggle() {
955 - // Remove any existing handlers to prevent duplicates
956 - var $toggleInput = $('input[name="mxchat_openai_vectorstore_options[mxchat_use_openai_vectorstore]"]');
957 - $toggleInput.off('change.vectorstoreToggle');
958 -
959 - // Ensure the success notice exists in the settings div (add if not present)
960 - // Check for both the JS-added class and any existing PHP-rendered success notice
961 - var settingsDiv = $('.mxchat-vectorstore-settings');
962 - if (settingsDiv.length > 0 && settingsDiv.find('.mxch-notice-success').length === 0) {
963 - var successNotice = $('<div class="mxch-notice mxch-notice-success mxchat-vectorstore-enabled-notice" style="margin-bottom: 20px; display: none;">' +
964 - '<svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' +
965 - '<span>OpenAI Vector Store is enabled. Queries will search your Vector Store for relevant content.</span>' +
966 - '</div>');
967 - settingsDiv.prepend(successNotice);
968 - }
969 -
970 - // Add the toggle handler for UI only (form submit will handle the actual saving)
971 - $toggleInput.on('change.vectorstoreToggle', function() {
972 - var $checkbox = $(this);
973 - var isChecked = $checkbox.is(':checked');
974 - var settingsDiv = $('.mxchat-vectorstore-settings');
975 - var enabledNotice = settingsDiv.find('.mxchat-vectorstore-enabled-notice, .mxch-notice-success');
976 -
977 - // Update the UI immediately
978 - if (isChecked) {
979 - settingsDiv.slideDown(300);
980 - enabledNotice.slideDown(300);
981 - } else {
982 - enabledNotice.slideUp(300);
983 - settingsDiv.slideUp(300);
984 - }
985 -
986 - // Update sidebar badge for OpenAI Vector Store
987 - updateSidebarBadge('openai-vectorstore', isChecked);
988 - });
989 -
990 - // Set initial state based on current checkbox value
991 - var currentToggle = $('input[name="mxchat_openai_vectorstore_options[mxchat_use_openai_vectorstore]"]');
992 - if (currentToggle.length > 0) {
993 - var settingsDiv = $('.mxchat-vectorstore-settings');
994 - var enabledNotice = settingsDiv.find('.mxchat-vectorstore-enabled-notice, .mxch-notice-success');
995 - if (currentToggle.is(':checked')) {
996 - settingsDiv.show();
997 - enabledNotice.show();
998 - } else {
999 - settingsDiv.hide();
1000 - enabledNotice.hide();
1001 - }
1002 - }
1003 - }
1004 -
1005 -})(jQuery);
731 +
732 +});