/** * Theme Options Admin JavaScript * * @package ROI_Theme * @since 1.0.0 */ (function($) { 'use strict'; var ROIThemeOptions = { /** * Initialize */ init: function() { this.tabs(); this.imageUpload(); this.resetOptions(); this.exportOptions(); this.importOptions(); this.formValidation(); this.conditionalFields(); }, /** * Tab Navigation */ tabs: function() { // Tab click handler $('.roi-tabs-nav a').on('click', function(e) { e.preventDefault(); var tabId = $(this).attr('href'); // Update active states $('.roi-tabs-nav li').removeClass('active'); $(this).parent().addClass('active'); // Show/hide tab content $('.roi-tab-pane').removeClass('active'); $(tabId).addClass('active'); // Update URL hash without scrolling if (history.pushState) { history.pushState(null, null, tabId); } else { window.location.hash = tabId; } }); // Load tab from URL hash on page load if (window.location.hash) { var hash = window.location.hash; if ($(hash).length) { $('.roi-tabs-nav a[href="' + hash + '"]').trigger('click'); } } // Handle browser back/forward buttons $(window).on('hashchange', function() { if (window.location.hash) { $('.roi-tabs-nav a[href="' + window.location.hash + '"]').trigger('click'); } }); }, /** * Image Upload */ imageUpload: function() { var self = this; var mediaUploader; // Upload button click $(document).on('click', '.roi-upload-image', function(e) { e.preventDefault(); var button = $(this); var container = button.closest('.roi-image-upload'); var preview = container.find('.roi-image-preview'); var input = container.find('.roi-image-id'); var removeBtn = container.find('.roi-remove-image'); // If the media uploader already exists, reopen it if (mediaUploader) { mediaUploader.open(); return; } // Create new media uploader mediaUploader = wp.media({ title: roiAdminOptions.strings.selectImage, button: { text: roiAdminOptions.strings.useImage }, multiple: false }); // When an image is selected mediaUploader.on('select', function() { var attachment = mediaUploader.state().get('selection').first().toJSON(); // Set image ID input.val(attachment.id); // Show preview var imgUrl = attachment.sizes && attachment.sizes.medium ? attachment.sizes.medium.url : attachment.url; preview.html(''); // Show remove button removeBtn.show(); }); // Open the uploader mediaUploader.open(); }); // Remove button click $(document).on('click', '.roi-remove-image', function(e) { e.preventDefault(); var button = $(this); var container = button.closest('.roi-image-upload'); var preview = container.find('.roi-image-preview'); var input = container.find('.roi-image-id'); // Clear values input.val(''); preview.empty(); button.hide(); }); }, /** * Reset Options */ resetOptions: function() { $('#roi-reset-options').on('click', function(e) { e.preventDefault(); if (!confirm(roiAdminOptions.strings.confirmReset)) { return; } var button = $(this); button.prop('disabled', true).addClass('updating-message'); $.ajax({ url: roiAdminOptions.ajaxUrl, type: 'POST', data: { action: 'roi_reset_options', nonce: roiAdminOptions.nonce }, success: function(response) { if (response.success) { // Show success message ROIThemeOptions.showNotice('success', response.data.message); // Reload page after 1 second setTimeout(function() { window.location.reload(); }, 1000); } else { ROIThemeOptions.showNotice('error', response.data.message); button.prop('disabled', false).removeClass('updating-message'); } }, error: function() { ROIThemeOptions.showNotice('error', roiAdminOptions.strings.error); button.prop('disabled', false).removeClass('updating-message'); } }); }); }, /** * Export Options */ exportOptions: function() { $('#roi-export-options').on('click', function(e) { e.preventDefault(); var button = $(this); button.prop('disabled', true).addClass('updating-message'); $.ajax({ url: roiAdminOptions.ajaxUrl, type: 'POST', data: { action: 'roi_export_options', nonce: roiAdminOptions.nonce }, success: function(response) { if (response.success) { // Create download link var blob = new Blob([response.data.data], { type: 'application/json' }); var url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = response.data.filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); ROIThemeOptions.showNotice('success', 'Options exported successfully!'); } else { ROIThemeOptions.showNotice('error', response.data.message); } button.prop('disabled', false).removeClass('updating-message'); }, error: function() { ROIThemeOptions.showNotice('error', roiAdminOptions.strings.error); button.prop('disabled', false).removeClass('updating-message'); } }); }); }, /** * Import Options */ importOptions: function() { var modal = $('#roi-import-modal'); var importData = $('#roi-import-data'); // Show modal $('#roi-import-options').on('click', function(e) { e.preventDefault(); modal.show(); }); // Close modal $('.roi-modal-close, #roi-import-cancel').on('click', function() { modal.hide(); importData.val(''); }); // Close modal on outside click $(window).on('click', function(e) { if ($(e.target).is(modal)) { modal.hide(); importData.val(''); } }); // Submit import $('#roi-import-submit').on('click', function(e) { e.preventDefault(); var data = importData.val().trim(); if (!data) { alert('Please paste your import data.'); return; } var button = $(this); button.prop('disabled', true).addClass('updating-message'); $.ajax({ url: roiAdminOptions.ajaxUrl, type: 'POST', data: { action: 'roi_import_options', nonce: roiAdminOptions.nonce, import_data: data }, success: function(response) { if (response.success) { ROIThemeOptions.showNotice('success', response.data.message); modal.hide(); importData.val(''); // Reload page after 1 second setTimeout(function() { window.location.reload(); }, 1000); } else { ROIThemeOptions.showNotice('error', response.data.message); button.prop('disabled', false).removeClass('updating-message'); } }, error: function() { ROIThemeOptions.showNotice('error', roiAdminOptions.strings.error); button.prop('disabled', false).removeClass('updating-message'); } }); }); }, /** * Form Validation */ formValidation: function() { $('.roi-options-form').on('submit', function(e) { var valid = true; var firstError = null; // Validate required fields $(this).find('[required]').each(function() { if (!$(this).val()) { valid = false; $(this).addClass('error'); if (!firstError) { firstError = $(this); } } else { $(this).removeClass('error'); } }); // Validate number fields $(this).find('input[type="number"]').each(function() { var val = $(this).val(); var min = $(this).attr('min'); var max = $(this).attr('max'); if (val && min && parseInt(val) < parseInt(min)) { valid = false; $(this).addClass('error'); if (!firstError) { firstError = $(this); } } if (val && max && parseInt(val) > parseInt(max)) { valid = false; $(this).addClass('error'); if (!firstError) { firstError = $(this); } } }); // Validate URL fields $(this).find('input[type="url"]').each(function() { var val = $(this).val(); if (val && !ROIThemeOptions.isValidUrl(val)) { valid = false; $(this).addClass('error'); if (!firstError) { firstError = $(this); } } }); if (!valid) { e.preventDefault(); if (firstError) { // Scroll to first error $('html, body').animate({ scrollTop: firstError.offset().top - 100 }, 500); firstError.focus(); } ROIThemeOptions.showNotice('error', 'Please fix the errors in the form.'); return false; } // Add saving animation $(this).find('.submit .button-primary').addClass('updating-message'); }); // Remove error class on input $('.roi-options-form input, .roi-options-form select, .roi-options-form textarea').on('change input', function() { $(this).removeClass('error'); }); }, /** * Conditional Fields */ conditionalFields: function() { // Enable/disable related posts options based on checkbox $('#enable_related_posts').on('change', function() { var checked = $(this).is(':checked'); var fields = $('#related_posts_count, #related_posts_taxonomy, #related_posts_title, #related_posts_columns'); fields.closest('tr').toggleClass('roi-field-dependency', !checked); fields.prop('disabled', !checked); }).trigger('change'); // Enable/disable breadcrumb separator based on breadcrumbs checkbox $('#enable_breadcrumbs').on('change', function() { var checked = $(this).is(':checked'); var field = $('#breadcrumb_separator'); field.closest('tr').toggleClass('roi-field-dependency', !checked); field.prop('disabled', !checked); }).trigger('change'); }, /** * Show Notice */ showNotice: function(type, message) { var notice = $('

' + message + '

'); $('.roi-theme-options h1').after(notice); // Auto-dismiss after 5 seconds setTimeout(function() { notice.fadeOut(function() { $(this).remove(); }); }, 5000); // Scroll to top $('html, body').animate({ scrollTop: 0 }, 300); }, /** * Validate URL */ isValidUrl: function(url) { try { new URL(url); return true; } catch (e) { return false; } } }; // Initialize on document ready $(document).ready(function() { ROIThemeOptions.init(); }); // Make it globally accessible window.ROIThemeOptions = ROIThemeOptions; })(jQuery);