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