File: /var/www/html/www.winghung.com/wp-content/plugins/upkyk-assistant-ai/admin/js/admin-script.js
jQuery(document).ready(function($) {
// Check if we're on the plugin's admin page
if (!$('.upkyk-assistant-ai-admin').length) {
// Not on our admin page, exit early
return;
}
// Initialize settings on page load
if ($('#upkyk-assistant-ai-preview').length) {
generatePreview();
}
// Function to animate the preview - needed for live preview
function animatePreview() {
// Add animation class to preview container
const $container = $('#upkyk-preview-container');
if ($container.length) {
// Use fade animation for preview
$container.addClass('upkyk-animation-fade');
// Reset animation by removing and re-adding class
setTimeout(function() {
$container.removeClass('upkyk-animation-fade');
setTimeout(function() {
$container.addClass('upkyk-animation-fade');
}, 50);
}, 50);
}
}
// START: Show Post-Save Notice
// Check if the settings were just saved (using sessionStorage flag)
if (sessionStorage.getItem('upkykSettingsSaved') === 'true') {
// Determine which tab was likely saved (optional, could just show generic message)
const activeTab = localStorage.getItem('upkyk_active_tab') || '#assistant-ai-settings'; // Get last known active tab
let settingType = 'Settings';
if (activeTab === '#assistant-ai-settings') settingType = 'Assistant AI Settings';
if (activeTab === '#appearance') settingType = 'Appearance Settings';
// Note: API Key tab uses AJAX, so won't trigger this normally
showNotice('success', `${settingType} saved successfully.`); // Use existing showNotice function
// Clear the flag so it doesn't show again on refresh
sessionStorage.removeItem('upkykSettingsSaved');
}
// END: Show Post-Save Notice
// Initialize color pickers
if ($.fn.wpColorPicker) {
$('.upkyk-color-picker').wpColorPicker({
change: function(event, ui) {
// Delay to ensure color is updated
setTimeout(function() {
generatePreview();
}, 100);
}
});
}
// Tab navigation - ONLY run if NOT on the training page
if (!$('.upkyk-training-tabs').length) {
$('.upkyk-tab-link').on('click', function(e) {
e.preventDefault();
var targetId = $(this).attr('href').substring(1); // Remove the # from the beginning
// Update active tab
$('.upkyk-tab-link').removeClass('active');
$(this).addClass('active');
// Show target content - both methods for backwards compatibility
$('.upkyk-tab-pane').removeClass('active').hide();
$('#' + targetId).addClass('active').show();
// Save active tab to localStorage
localStorage.setItem('upkyk_active_tab', '#' + targetId);
// Load preview if on appearance tab
if (targetId === 'appearance') {
if (typeof generatePreview === 'function') {
generatePreview();
}
}
});
// Restore active tab from localStorage
var activeTab = localStorage.getItem('upkyk_active_tab');
if (activeTab && $(activeTab).length) {
var targetId = activeTab.substring(1);
// Update active tab classes
$('.upkyk-tab-link').removeClass('active');
$('.upkyk-tab-link[href="' + activeTab + '"]').addClass('active');
// Show the active tab
$('.upkyk-tab-pane').removeClass('active').hide();
$('#' + targetId).addClass('active').show();
} else {
// Default to first tab
var firstTabHref = $('.upkyk-tab-link').first().attr('href');
var firstTabId = firstTabHref.substring(1);
// Set active classes
$('.upkyk-tab-link').first().addClass('active');
$('.upkyk-tab-pane').removeClass('active').hide();
$('#' + firstTabId).addClass('active').show();
}
}
// END Conditional Tab Logic
// Media uploader for avatar
if ($('#upkyk_upload_avatar').length) {
$('#upkyk_upload_avatar').on('click', function(e) {
e.preventDefault();
var imageFrame;
if (imageFrame) {
imageFrame.open();
return;
}
imageFrame = wp.media({
title: 'Select Avatar Image',
button: {
text: 'Use this image'
},
multiple: false,
library: {
type: 'image'
}
});
imageFrame.on('select', function() {
var attachment = imageFrame.state().get('selection').first().toJSON();
$('#upkyk_assistant_ai_avatar').val(attachment.url);
$('#upkyk_avatar_preview').html('<img src="' + attachment.url + '" alt="Avatar">');
// Update preview
generatePreview();
});
imageFrame.open();
});
// Remove avatar button
$('#upkyk_remove_avatar').on('click', function(e) {
e.preventDefault();
$('#upkyk_assistant_ai_avatar').val('');
$('#upkyk_avatar_preview').html('<div class="upkyk-no-avatar">No Avatar</div>');
// Update preview
generatePreview();
});
}
// Icon Selector Modal Functionality
jQuery(document).ready(function($) {
// Define available icons
const availableIcons = ['chat-balloon', 'comment', 'comments', 'robot', 'question', 'envelope'];
// Function to open the icon selector modal
function openIconSelector(selectedIcon, targetInput) {
// First, remove any existing modal to avoid duplicates
$('#upkyk-icon-modal').remove();
// Create a fresh modal each time
const modalHTML = `
<div id="upkyk-icon-modal" class="upkyk-modal">
<div class="upkyk-modal-content">
<div class="upkyk-modal-header">
<h3>Selecteer icoon</h3>
<span class="upkyk-modal-close">×</span>
</div>
<div class="upkyk-icon-grid"></div>
</div>
</div>
`;
$('body').append(modalHTML);
// Store the target input
$('#upkyk-icon-modal').data('target', targetInput);
// Populate the icon grid
const $iconGrid = $('.upkyk-icon-grid');
availableIcons.forEach(icon => {
const isSelected = (icon === selectedIcon) ? 'selected' : '';
const iconItem = $(`
<div class="upkyk-icon-item ${isSelected}" data-value="${icon}">
<div class="upkyk-icon-preview ${icon}"></div>
<span>${icon.charAt(0).toUpperCase() + icon.slice(1)}</span>
</div>
`);
$iconGrid.append(iconItem);
// Add direct click handler to each icon item
iconItem.on('click', function() {
// First hide the modal
$('#upkyk-icon-modal').hide().remove();
// Then update the input and preview
$(targetInput).val(icon);
const $button = $(targetInput).siblings('.upkyk-icon-select-button');
$button.html(`
<div class="upkyk-icon-preview ${icon}"></div>
${icon.charAt(0).toUpperCase() + icon.slice(1)}
`);
// Trigger change event
$(targetInput).trigger('change');
});
});
// Close button handler
$('.upkyk-modal-close').on('click', function() {
$('#upkyk-icon-modal').hide().remove();
});
// Close when clicking outside
$('#upkyk-icon-modal').on('click', function(e) {
if (e.target === this) {
$(this).hide().remove();
}
});
// Show the modal
$('#upkyk-icon-modal').show();
}
// Add click handler to icon selector buttons
$(document).on('click', '.upkyk-icon-select-button', function() {
const targetInput = $(this).siblings('input[type="hidden"]');
const currentIcon = targetInput.val();
openIconSelector(currentIcon, targetInput);
});
// Initialize icon buttons with their current values
$('.upkyk-icon-select-button').each(function() {
const $input = $(this).siblings('input[type="hidden"]');
const currentIcon = $input.val();
if (currentIcon) {
$(this).html(`
<div class="upkyk-icon-preview ${currentIcon}"></div>
${currentIcon.charAt(0).toUpperCase() + currentIcon.slice(1)}
`);
}
});
});
// Custom SVG Icon Upload (PRO Feature)
$('#upkyk_upload_svg').on('click', function(e) {
e.preventDefault();
// Show upgrade message
alert('This feature is only available in the PRO version.');
// Redirect to upgrade page (optional)
if (confirm('Would you like to learn more about the PRO version?')) {
window.open('https://upkyk.com/assistant-ai', '_blank');
}
});
// Remove Custom SVG Icon (PRO Feature)
$('#upkyk_remove_svg').on('click', function(e) {
e.preventDefault();
// Show upgrade message
alert('This feature is only available in the PRO version.');
// Redirect to upgrade page (optional)
if (confirm('Would you like to learn more about the PRO version?')) {
window.open('https://upkyk.com/assistant-ai', '_blank');
}
});
// Initialize custom icon preview if there's a value
if ($('#upkyk_assistant_ai_custom_icon').val()) {
const iconUrl = $('#upkyk_assistant_ai_custom_icon').val();
const backgroundColor = $('#upkyk_assistant_ai_color').val() || '#0084ff';
// Preview is already handled in the PHP side
}
// Update settings data for preview to include custom icon
function generatePreview() {
// Check if we have the preview nonce
if (!upkykAssistantAIAdmin.previewNonce) {
$('#upkyk-assistant-ai-preview').html('<div class="upkyk-preview-error">Error: Preview nonce is missing.</div>');
return;
}
const settings = {
color: $('#upkyk_assistant_ai_color').val() || '#0084ff',
user_color: $('#upkyk_assistant_ai_user_color').val() || '#e9ecef',
font: $('#upkyk_assistant_ai_font').val() || 'Roboto, sans-serif',
avatar: $('#upkyk_assistant_ai_avatar').val() || '',
assistant_ai_name: $('#upkyk_assistant_ai_name').val() || 'Chat Support',
button_shape: $('#upkyk_assistant_ai_button_shape').val() || 'circle',
button_size: $('#upkyk_assistant_ai_button_size').val() || 'medium',
font_size: $('#upkyk_assistant_ai_font_size').val() || 'medium',
message_padding: $('#upkyk_assistant_ai_message_padding').val() || 'normal',
input_placeholder: $('#upkyk_assistant_ai_input_placeholder').val() || 'Type your message...',
button_icon: $('#upkyk_assistant_ai_button_icon').val() || 'chat',
custom_icon: $('#upkyk_assistant_ai_custom_icon').val() || '',
custom_icon_size: $('#upkyk_assistant_ai_custom_icon_size').val() || 'medium',
animation_style: $('#upkyk_assistant_ai_animation_style').val() || 'fade',
window_size: $('#upkyk_assistant_ai_window_size').val() || 'medium',
window_width: $('#upkyk_assistant_ai_window_width').val() || '380',
window_height: $('#upkyk_assistant_ai_window_height').val() || '600',
window_width_mobile: $('#upkyk_assistant_ai_window_width_mobile').val() || '95',
window_height_mobile: $('#upkyk_assistant_ai_window_height_mobile').val() || '80'
};
// Show loading state
$('#upkyk-assistant-ai-preview').html('<div class="upkyk-preview-loading">Loading preview...</div>');
// Helper function to adjust color brightness
function adjustColor(color, amount) {
// Default to returning the original color if there's an error
if (!color) return '#0084ff';
try {
// Convert hex to RGB
let hex = color;
if (hex.startsWith('#')) {
hex = hex.slice(1);
}
// Convert 3-char hex to 6-char
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
// Parse the hex values to rgb
let r = parseInt(hex.substr(0, 2), 16);
let g = parseInt(hex.substr(2, 2), 16);
let b = parseInt(hex.substr(4, 2), 16);
// Adjust the values
r = Math.max(0, Math.min(255, r + amount));
g = Math.max(0, Math.min(255, g + amount));
b = Math.max(0, Math.min(255, b + amount));
// Convert back to hex
return '#' +
((1 << 24) + (r << 16) + (g << 8) + b)
.toString(16)
.slice(1);
} catch (e) {
return color; // Return original if there's an error
}
}
$.ajax({
url: upkykAssistantAIAdmin.ajax_url,
type: 'POST',
data: {
action: 'upkyk_generate_preview',
nonce: upkykAssistantAIAdmin.previewNonce,
settings: settings
},
success: function(response) {
if (response.success && response.data && response.data.preview) {
$('#upkyk-assistant-ai-preview').html(response.data.preview);
// Animate the preview after updating
animatePreview();
} else {
let errorMessage = 'Failed to load preview.';
if (response.data && response.data.message) {
errorMessage += ' Error: ' + response.data.message;
}
$('#upkyk-assistant-ai-preview').html('<div class="upkyk-preview-error">' + errorMessage + '</div>');
}
},
error: function(xhr, status, error) {
try {
// Try to parse the response to get more detailed error
const jsonResponse = JSON.parse(xhr.responseText);
$('#upkyk-assistant-ai-preview').html('<div class="upkyk-preview-error">Error: ' + (jsonResponse.data?.message || error) + '</div>');
} catch (e) {
$('#upkyk-assistant-ai-preview').html('<div class="upkyk-preview-error">Error: ' + error + '</div>');
}
}
});
}
// Test API connection
$('#test_ai_connection').on('click', function() {
// Set up variables
let $button = $(this);
let $status = $('#connection_status');
let currentApiKey = $('#upkyk_assistant_ai_api_key').val();
let provider = $('#upkyk_assistant_ai_provider').val();
// Validate API key
if (!currentApiKey) {
$status.html('<span style="color: red;">✗ Please enter an API key first</span>');
return;
}
$button.prop('disabled', true);
$status.html('<span style="color: #666;">Testing connection...</span>');
$.ajax({
url: upkykAssistantAIAdmin.ajax_url,
type: 'POST',
data: {
action: 'upkyk_test_connection',
nonce: upkykAssistantAIAdmin.nonce,
api_key: currentApiKey,
provider: provider
},
success: function(response) {
if (response.success) {
$status.html('<span style="color: green;">✓ ' + response.data.message + '</span>');
} else {
$status.html('<span style="color: red;">✗ ' + response.data.message + '</span>');
}
},
error: function() {
$status.html('<span style="color: red;">✗ Connection test failed</span>');
},
complete: function() {
$button.prop('disabled', false);
}
});
});
// Toggle model fields based on selected AI provider
$('#upkyk_assistant_ai_provider').on('change', function() {
const provider = $(this).val();
// Hide all model rows first
$('.openai-model-row, tr:has([name="upkyk_assistant_ai_deepseek_model"])').hide();
// Show the appropriate row based on selection
if (provider === 'openai') {
$('.openai-model-row').show();
} else if (provider === 'deepseek') {
$('tr:has([name="upkyk_assistant_ai_deepseek_model"])').show();
}
});
// Function to show notification
function showNotification(message, type = 'success') {
// Create notification element
const notification = document.createElement('div');
notification.className = `upkyk-admin-notification ${type} show`;
notification.innerHTML = `
<div class="upkyk-notification-message">${message}</div>
<div class="upkyk-notification-close">×</div>
`;
document.body.appendChild(notification);
// Add close handler
notification.querySelector('.upkyk-notification-close').addEventListener('click', function() {
notification.classList.remove('show');
setTimeout(() => {
notification.remove();
}, 300);
});
// Auto-remove after 5 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
notification.remove();
}, 300);
}, 5000);
}
// Generic function to show notices in admin
function showNotice(type, message) {
// Create notice element using WP style
const noticeClass = type === 'success' ? 'notice-success' : 'notice-error';
const $notice = $(`<div class="notice ${noticeClass} is-dismissible"><p>${message}</p></div>`);
// Add to the page
$('#wpbody-content > .wrap > h1, .wrap > .upkyk-admin-header').first().after($notice);
// Auto-dismiss after 5 seconds
setTimeout(function() {
$notice.fadeOut(function() {
$(this).remove();
});
}, 5000);
}
// Watch for form submissions
$('.upkyk-form').on('submit', function(e) {
const $form = $(this);
// Show notification after form submission
setTimeout(() => {
let message = 'Settings saved successfully!';
// Customize message based on form
if ($form.hasClass('api-settings-form')) {
message = 'AI Provider settings saved successfully!';
} else if ($form.closest('#settings').length) {
message = 'Assistant AI settings saved successfully!';
} else if ($form.closest('#appearance').length) {
message = 'Appearance settings saved successfully!';
}
showNotification(message);
}, 500);
});
// Make sure API settings form has the right class
$('#api-key .upkyk-form').addClass('api-settings-form');
// Add this with the other event handlers for the API tab
$('#delete_api_key').on('click', function() {
if (confirm('Are you sure you want to delete your API key? This action cannot be undone.')) {
// Get button reference
const $button = $(this);
// Show loading state
$button.attr('disabled', true).text('Deleting...');
// Always clear the field on user confirmation, regardless of server response
$('#upkyk_assistant_ai_api_key').val('');
// Call AJAX to delete the key from the database
$.ajax({
url: upkykAssistantAIAdmin.ajax_url,
type: 'POST',
data: {
action: 'upkyk_delete_api_key',
nonce: upkykAssistantAIAdmin.nonce
},
success: function(response) {
if (response.success) {
showNotice('success', 'API key successfully deleted.');
} else {
showNotice('error', response.data.message);
}
},
error: function(xhr, status, error) {
showNotice('error', 'An error occurred: ' + error);
},
complete: function() {
$button.attr('disabled', false).text('Delete API Key');
}
});
}
});
// Find all settings forms in tabs
$('.upkyk-tab-content form').each(function() {
// Only target forms posting to options.php (exclude potential AJAX forms if any)
if ($(this).attr('action') === 'options.php') {
$(this).addClass('upkyk-settings-form');
// Add submit event handler for standard WP settings forms
$(this).on('submit', function() {
// Set a flag in sessionStorage before the page reloads
sessionStorage.setItem('upkykSettingsSaved', 'true');
// Allow the form to submit normally, which causes the reload
});
}
});
// Handle API settings form submission
$('.api-settings-form').on('submit', function() {
// Store the value of the tab we're on before submitting
localStorage.setItem('upkyk_active_tab', '#api-key');
// Show the API key saved notification (for Ajax-less approach)
$('#api_save_notification').slideDown().delay(3000).slideUp();
});
// Initialize preview generator
function initAssistantAIPreview() {
const $previewSection = $('#assistant-ai-preview');
// Create update preview function
function updatePreview() {
const settings = {
color: $('#upkyk_assistant_ai_color').val(),
user_color: $('#upkyk_assistant_ai_user_message_color').val(),
font: $('#upkyk_assistant_ai_font').val(),
avatar: $('#upkyk_assistant_ai_avatar_url').val(),
assistant_ai_name: $('#upkyk_assistant_ai_name').val() || 'Chat Support',
button_shape: $('#upkyk_assistant_ai_button_shape').val(),
button_size: $('#upkyk_assistant_ai_button_size').val(),
font_size: $('#upkyk_assistant_ai_font_size').val(),
message_padding: $('#upkyk_assistant_ai_message_padding').val(),
input_placeholder: $('#upkyk_assistant_ai_input_placeholder').val() || 'Type your message...',
button_icon: $('#upkyk_assistant_ai_button_icon').val(),
custom_icon: $('#upkyk_assistant_ai_custom_icon').val(),
custom_icon_size: $('#upkyk_assistant_ai_custom_icon_size').val() || 'medium',
animation_style: $('#upkyk_assistant_ai_animation_style').val() || 'default'
};
$.ajax({
url: upkykAssistantAIAdmin.ajax_url,
type: 'post',
data: {
action: 'upkyk_generate_preview',
settings: settings,
nonce: upkykAssistantAIAdmin.previewNonce,
},
success: function(response) {
if (response.success && response.data && response.data.preview) {
$previewSection.html(response.data.preview);
animatePreview();
} else {
$previewSection.html('<p class="upkyk-error">Error generating preview</p>');
}
},
error: function() {
$previewSection.html('<p class="upkyk-error">Error generating preview</p>');
}
});
}
// Update preview when settings change
$('.upkyk-preview-control').on('change input', function() {
updatePreview();
});
// Generate initial preview
updatePreview();
}
// Listen for changes to custom icon size and update preview
$('#upkyk_assistant_ai_custom_icon_size').on('change', function() {
const iconUrl = $('#upkyk_assistant_ai_custom_icon').val();
if (iconUrl) {
const backgroundColor = $('#upkyk_assistant_ai_color').val() || '#0084ff';
const iconSize = $(this).val() || 'medium';
// Calculate dimensions based on size
let dimensions = 24; // Default for medium
if (iconSize === 'small') {
dimensions = 18;
} else if (iconSize === 'large') {
dimensions = 32;
}
$('#upkyk_svg_preview').html(`
<div class="upkyk-svg-preview-container" style="width: 60px; height: 60px; background-color: ${backgroundColor}; display: flex; align-items: center; justify-content: center; border-radius: 50%;">
<img src="${iconUrl}" alt="Custom Icon" style="width: ${dimensions}px; height: ${dimensions}px; filter: brightness(0) invert(1);">
</div>
`);
// Update the preview
generatePreview();
}
});
// Handle changes to button shape
$('#upkyk_assistant_ai_button_shape').on('change', function() {
generatePreview();
});
// Handle changes to button size
$('#upkyk_assistant_ai_button_size').on('change', function() {
generatePreview();
});
// Handle changes to animation style
$('#upkyk_assistant_ai_animation_style').on('change', function() {
generatePreview();
// Show animation effect in the preview
setTimeout(function() {
const animationStyle = $('#upkyk_assistant_ai_animation_style').val();
const $previewChat = $('.upkyk-preview-chat');
// First reset to trigger animation
$previewChat.removeClass('animated');
// Force reflow to make sure the animation replays
void $previewChat[0].offsetWidth;
// Add animation class
$previewChat.addClass('animated');
}, 300); // Small delay to ensure preview is updated first
});
// Handle changes to button icon or style
$('#upkyk_assistant_ai_button_icon').on('change', function() {
generatePreview();
});
// Handle changes to font and other appearance options
// Handle window size preset selection
$('#upkyk_assistant_ai_window_size').on('change', function() {
const selectedSize = $(this).val();
const $customFields = $('.custom-size-field');
const $widthInput = $('#upkyk_assistant_ai_window_width');
const $heightInput = $('#upkyk_assistant_ai_window_height');
// Set width and height values based on preset
if (selectedSize === 'small') {
$widthInput.val('320');
$heightInput.val('450');
$customFields.hide();
} else if (selectedSize === 'medium') {
$widthInput.val('380');
$heightInput.val('600');
$customFields.hide();
} else if (selectedSize === 'large') {
$widthInput.val('450');
$heightInput.val('650');
$customFields.hide();
} else if (selectedSize === 'extra-large') {
$widthInput.val('550');
$heightInput.val('700');
$customFields.hide();
} else if (selectedSize === 'custom') {
$customFields.show();
}
// Update preview if it exists
if (typeof generatePreview === 'function') {
generatePreview();
}
});
// Trigger change event to set initial state
$('#upkyk_assistant_ai_window_size').trigger('change');
// Handle Icon Selector Modal in settings page
jQuery(document).ready(function($) {
// Open icon selector modal
$('#open_icon_selector').on('click', function() {
$('#upkyk_icon_selector_modal').show();
// Highlight currently selected icon
const currentValue = $('#upkyk_assistant_ai_button_icon').val();
$('.upkyk-icon-item').removeClass('selected');
$(`.upkyk-icon-item[data-value="${currentValue}"]`).addClass('selected');
});
// Close icon selector modal
$('#close_icon_selector').on('click', function() {
$('#upkyk_icon_selector_modal').hide();
});
// Close when clicking outside the modal content
$('#upkyk_icon_selector_modal').on('click', function(e) {
if (e.target === this) {
$(this).hide();
}
});
// Handle icon selection
$('.upkyk-icon-item').on('click', function() {
const iconValue = $(this).data('value');
const iconName = $(this).find('span').text();
// Update the hidden input value
$('#upkyk_assistant_ai_button_icon').val(iconValue).trigger('change');
// Get the correct file name based on icon value
let iconFile = iconValue;
if (iconValue === 'chat' || iconValue === 'comment') {
iconFile = 'comment';
} else if (iconValue === 'question') {
iconFile = 'question-circle';
}
// Get the plugin URL
const pluginUrl = upkykAssistantAIAdmin?.plugin_url || '';
// Update the selected icon preview
const iconHtml = `<img src="${pluginUrl}assets/images/chat-icons/${iconFile}.svg" alt="${iconValue}" style="width:24px; height:24px; filter:brightness(0) invert(1);">`;
$('.upkyk-selected-icon-preview .upkyk-icon-preview').attr('class', 'upkyk-icon-preview ' + iconValue).html(iconHtml);
$('.upkyk-selected-icon-preview span').text(iconName);
// Highlight the selected icon
$('.upkyk-icon-item').removeClass('selected');
$(this).addClass('selected');
// Close the modal
$('#upkyk_icon_selector_modal').hide();
// Update the preview if available
if (typeof generatePreview === 'function') {
generatePreview();
}
});
});
// Update preview when any appearance setting changes
$('#upkyk_assistant_ai_color, #upkyk_assistant_ai_user_color, #upkyk_assistant_ai_link_bg_color, #upkyk_assistant_ai_link_text_color, #upkyk_assistant_ai_font, #upkyk_assistant_ai_avatar, #upkyk_assistant_ai_position, #upkyk_assistant_ai_button_shape, #upkyk_assistant_ai_button_size, #upkyk_assistant_ai_font_size, #upkyk_assistant_ai_message_padding, #upkyk_assistant_ai_input_placeholder, #upkyk_assistant_ai_button_icon, #upkyk_assistant_ai_custom_icon, #upkyk_assistant_ai_custom_icon_size, #upkyk_assistant_ai_window_size, #upkyk_assistant_ai_window_width, #upkyk_assistant_ai_window_height').on('change', function() {
generatePreview();
setTimeout(animatePreview, 300);
});
// START: Save Button Feedback
// Add a handler for the standard WordPress settings forms in our tabs
$('#assistant-ai-settings form, #appearance form').on('submit', function(e) {
const $form = $(this);
const $submitButton = $form.find('input[type="submit"].button-primary'); // Find the primary save button
if ($submitButton.length) {
// Add a spinner icon next to the button
// Ensure the spinner doesn't already exist
if (!$submitButton.next('.upkyk-spinner').length) {
$submitButton.after('<span class="upkyk-spinner spinner is-active" style="display: inline-block; float: none; vertical-align: middle; margin-left: 5px;"></span>');
}
// The spinner will automatically disappear on page reload after save
}
// Allow the form to submit normally
});
// END: Save Button Feedback
});