/**
* 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 + '