first commit

This commit is contained in:
User A0264400
2026-04-01 23:20:16 +03:00
commit a766acdc90
23071 changed files with 4933189 additions and 0 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,470 @@
jQuery(function ($) {
/**
* Factory function to create a bulk conversion handler for a specific format.
*
* @param {string} format - The conversion format ('webp' or 'avif')
* @param {string} buttonSelector - jQuery selector for the start button
* @returns {Object} - Bulk conversion handler object
*/
function createBulkConversion(format, buttonSelector) {
return {
format: format,
inprogress: false,
serverDown: false,
i18n: {},
settings: {},
startConvertButton: $(buttonSelector),
startOptButton: $('#wrio-start-optimization'),
startWebpButton: $('#wrio-start-conversion'),
startAvifButton: $('#wrio-start-avif-conversion'),
init: function () {
this.i18n = wrio_l18n_bulk_page;
this.settings = wrio_settings_bulk_page;
if (this.startConvertButton.length) {
this.registerEvents();
this.checkInitialRunningState();
}
},
checkInitialRunningState: function () {
// If this conversion button is already running on page load, disable other buttons
if (this.startConvertButton.hasClass('wio-running')) {
this.startOptButton.prop('disabled', true);
// Disable the other conversion button (not this one)
if (this.format === 'webp') {
this.startAvifButton.prop('disabled', true);
} else {
this.startWebpButton.prop('disabled', true);
}
}
},
registerEvents: function () {
var self = this;
this.startConvertButton.on('click', function () {
if ($(this).hasClass('wio-running')) {
self.startOptButton.prop('disabled', false);
self.startWebpButton.prop('disabled', false);
self.startAvifButton.prop('disabled', false);
self.stop();
return;
}
self.showModal();
return false;
});
},
showModal: function () {
var self = this;
var infosModal = $('#wrio-tmpl-' + this.format + '-conversion');
// Fall back to webp template if format-specific one doesn't exist
if (!infosModal.length) {
infosModal = $('#wrio-tmpl-webp-conversion');
}
if (!infosModal.length) {
console.log('[Error]: Html template for modal not found.');
return;
}
var modalTitle = this.format === 'avif'
? (this.i18n.modal_avif_conversion_title || this.i18n.modal_conversion_title)
: this.i18n.modal_conversion_title;
// Swal Information before loading the optimize process.
swal({
title: modalTitle,
html: infosModal.html(),
type: '',
customClass: 'wrio-modal wrio-modal-optimization-way',
showCancelButton: true,
showCloseButton: true,
padding: 0,
width: 740,
confirmButtonText: this.i18n.modal_conversion_manual_button,
cancelButtonText: this.i18n.modal_conversion_cron_button,
reverseButtons: true,
}).then(function (result) {
self.startOptButton.prop('disabled', true);
self.startWebpButton.prop('disabled', true);
self.startAvifButton.prop('disabled', true);
self.startConvertButton.prop('disabled', false); // Re-enable current button for stop
self.process();
window.onbeforeunload = function () {
return self.i18n.leave_page_warning;
}
}, function (dismiss) {
if (dismiss === 'cancel') { // you might also handle 'close' or 'timer' if you used those
self.startOptButton.prop('disabled', true);
self.startWebpButton.prop('disabled', true);
self.startAvifButton.prop('disabled', true);
self.startConvertButton.prop('disabled', false); // Re-enable current button for stop
self.process('cron');
} else {
throw dismiss;
}
});
},
/**
* Start conversion
* @param {string} type - 'cron' or undefined for manual
*/
process: function (type) {
var self = this;
this.inprogress = true;
var sendData = {
'action': 'wrio-bulk-conversion-process',
'scope': this.settings.scope,
'format': this.format,
'multisite': 0,
'_wpnonce': this.settings.conversion_nonce,
};
this.setButtonStyleRun(type);
if ('cron' === type) {
this.startConvertButton.addClass('wrio-cron-mode');
sendData['action'] = 'wrio-' + this.format + '-cron-start';
$.post(ajaxurl, sendData, function (response) {
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Start cron).');
console.log(sendData);
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
} else {
if (response.data && response.data.stop) {
self.stop();
}
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
return;
}
this.showMessage(this.i18n.conversion_inprogress.replace("%s", parseInt($('#wio-unoptimized-num').text())));
sendData['reset_current_errors'] = 1;
this.sendRequest(sendData);
},
stop: function () {
var self = this;
this.inprogress = false;
window.onbeforeunload = null;
self.setButtonStyleStop();
self.destroyMessages();
if (this.startConvertButton.hasClass('wrio-cron-mode')) {
this.startConvertButton.removeClass('wrio-cron-mode');
$.post(ajaxurl, {
'action': 'wrio-' + this.format + '-cron-stop',
'_wpnonce': self.settings.conversion_nonce,
'scope': self.settings.scope
}, function (response) {
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Stop cron).');
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
} else {
self.startOptButton.prop('disabled', false);
self.startWebpButton.prop('disabled', false);
self.startAvifButton.prop('disabled', false);
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
}
},
complete: function () {
this.inprogress = false;
window.onbeforeunload = null;
this.setButtonStyleComplete();
},
setButtonStyleRun: function (mode) {
this.startConvertButton.addClass('wio-running');
if ("cron" === mode) {
this.startConvertButton.text(this.i18n.modal_conversion_cron_button_stop);
return;
}
this.startConvertButton.text(this.i18n.button_stop);
},
setButtonStyleComplete: function () {
this.showMessage(this.i18n.conversion_complete);
this.startConvertButton.text(this.i18n.button_completed);
this.startConvertButton.removeClass('wio-running');
this.startConvertButton.prop('disabled', true);
this.startOptButton.prop('disabled', false);
this.startWebpButton.prop('disabled', false);
this.startAvifButton.prop('disabled', false);
},
setButtonStyleStop: function () {
this.startConvertButton.removeClass('wio-running');
var buttonText = this.format === 'avif'
? (this.i18n.avif_button_start || 'Convert to AVIF')
: this.i18n.webp_button_start;
this.startConvertButton.text(buttonText);
},
showMessage: function (text) {
var contanier = $('.wio-page-statistic'),
message;
if (contanier.find('.wrio-statistic-message').length) {
message = contanier.find('.wrio-statistic-message');
} else {
message = $('<div>');
message.addClass('wrio-statistic-message');
contanier.append(message);
}
message.html(text);
},
throwError: function (error_message) {
this.stop();
var noticeId = $.wbcr_factory_templates_759.app.showNotice(error_message, 'danger');
setTimeout(function () {
$.wbcr_factory_templates_759.app.hideNotice(noticeId);
}, 10000);
},
destroyMessages: function () {
$('.wio-page-statistic').find('.wrio-statistic-message').empty();
},
sendRequest: function (data) {
var self = this;
if (!this.inprogress) {
return;
}
$.post(ajaxurl, data, function (response) {
if (!self.inprogress) {
return;
}
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Try to optimize images).');
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
return;
}
data.reset_current_errors = 0;
if (!response.data.end) {
$('#wio-total-unoptimized').text(parseInt(response.data.remain));
self.showMessage(self.i18n.conversion_inprogress.replace("%s", parseInt(response.data.remain)));
self.sendRequest(data);
} else {
$('#wio-total-unoptimized').text(response.data.remain);
self.complete();
}
redraw_statistics(response.data.statistic);
if (response.data.last_optimized) {
self.updateLog(response.data.last_optimized);
}
if (response.data.last_converted) {
self.updateLog(response.data.last_converted);
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
},
updateLog: function (new_item_data) {
var self = this;
var limit = 100,
tableEl = $('.wrio-optimization-progress .wrio-table');
if (!tableEl.length || !new_item_data) {
return;
}
// Clear empty table state
if ($('.wrio-table-container-empty').length) {
$('.wrio-table-container-empty').addClass('wrio-table-container').removeClass('wrio-table-container-empty');
if (tableEl.find('tbody').length) {
tableEl.find('tbody').empty();
}
}
$.each(new_item_data, function (index, value) {
var trEl = $('<tr>'),
tdEl = $('<td>'),
webpSize = value.webp_size ? value.webp_size : '-',
avifSize = value.avif_size ? value.avif_size : '-';
if (tableEl.find('.wrio-row-id-' + value.id).length) {
tableEl.find('.wrio-row-id-' + value.id).remove();
}
trEl.addClass('flash').addClass('wrio-table-item').addClass('wrio-row-id-' + value.id);
if ('error' === value.type) {
trEl.addClass('wrio-error');
}
var preview = $('<img width="40" height="40" src="' + value.thumbnail_url + '" alt="">'),
previewUrl = $('<a href="' + value.url + '" target="_blank">' + value.file_name + '</a>');
tableEl.prepend(trEl);
trEl.append(tdEl.clone().append(preview));
trEl.append(tdEl.clone().append(previewUrl));
if ('error' === value.type) {
var colspan = value.scope !== 'custom-folders' ? '7' : '6';
trEl.append(tdEl.clone().attr('colspan', colspan).text("Error: " + value.error_msg));
} else {
trEl.append(tdEl.clone().text(value.original_size));
trEl.append(tdEl.clone().text(value.optimized_size));
trEl.append(tdEl.clone().text(webpSize));
trEl.append(tdEl.clone().text(avifSize));
trEl.append(tdEl.clone().text(value.original_saving));
if ("custom-folders" !== self.settings.scope) {
trEl.append(tdEl.clone().text(value.thumbnails_count));
}
trEl.append(tdEl.clone().text(value.total_saving));
}
});
if (tableEl.find('tr').length > limit) {
var diff = tableEl.find('tr').length - limit;
for (var i = 0; i < diff; i++) {
tableEl.find('tr:last').remove();
}
}
}
};
}
// Create WebP conversion handler
var bulkConversionWebp = createBulkConversion('webp', '#wrio-start-conversion');
// Create AVIF conversion handler
var bulkConversionAvif = createBulkConversion('avif', '#wrio-start-avif-conversion');
$(document).ready(function () {
bulkConversionWebp.init();
bulkConversionAvif.init();
$('[data-toggle="tooltip"]').tooltip();
});
var ajaxUrl = ajaxurl;
var ai_data;
function redraw_statistics(statistic) {
// Update WebP stats - chart data attributes
$('#wio-webp-chart').attr('data-unoptimized', statistic.unconverted)
.attr('data-optimized', statistic.converted)
.attr('data-errors', statistic.webp_error);
// Update WebP percent display
$('#wio-overview-chart-percent-webp').text(statistic.webp_percent_line);
// Update WebP legend
$('#wio-webp-pending').text(statistic.unconverted);
$('#wio-webp-converted').text(statistic.converted);
$('#wio-webp-error').text(statistic.webp_error);
$('#wio-webp-done').text(statistic.converted);
// Update AVIF stats (if available)
if (statistic.avif_unconverted !== undefined) {
$('#wio-avif-chart').attr('data-unoptimized', statistic.avif_unconverted)
.attr('data-optimized', statistic.avif_converted)
.attr('data-errors', statistic.avif_error);
// Update AVIF percent display
$('#wio-overview-chart-percent-avif').text(statistic.avif_percent_line);
// Update AVIF legend
$('#wio-avif-pending').text(statistic.avif_unconverted);
$('#wio-avif-converted').text(statistic.avif_converted);
$('#wio-avif-error').text(statistic.avif_error);
$('#wio-avif-done').text(statistic.avif_converted);
}
var credits = $('.wrio-premium-user-balance');
if (credits.attr('data-server') !== "server_5") {
credits.text(statistic.credits);
}
if (window.wio_chart_webp) {
window.wio_chart_webp.data.datasets[0].data[0] = statistic.webp_error; // errors
window.wio_chart_webp.data.datasets[0].data[1] = statistic.converted; // optimized
window.wio_chart_webp.data.datasets[0].data[2] = statistic.unconverted; // unoptimized
window.wio_chart_webp.update();
}
if (window.wio_chart_avif && statistic.avif_unconverted !== undefined) {
window.wio_chart_avif.data.datasets[0].data[0] = statistic.avif_error; // errors
window.wio_chart_avif.data.datasets[0].data[1] = statistic.avif_converted; // optimized
window.wio_chart_avif.data.datasets[0].data[2] = statistic.avif_unconverted; // unoptimized
window.wio_chart_avif.update();
}
if ($('#wio-overview-chart-percent-webp').text() == '100') {
window.onbeforeunload = null;
}
}
});

View File

@@ -0,0 +1,646 @@
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes === 0) {
return '0 Byte';
}
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
if (i === 0) {
return bytes + ' ' + sizes[i];
}
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
}
jQuery(function ($) {
var bulkOptimization = {
inprogress: false,
serverDown: false,
i18n: {},
settings: {},
init: function () {
if (wrio_l18n_bulk_page === undefined || wrio_settings_bulk_page === undefined) {
console.log('[Error]: Required global variables are not declared.');
return;
}
this.i18n = wrio_l18n_bulk_page;
this.settings = wrio_settings_bulk_page;
this.startOptButton = $('#wrio-start-optimization');
this.registerEvents();
this.checkServerStatus();
//this.calculateTotalImages();
this.checkPremiumUserBalance();
},
registerEvents: function () {
var self = this;
this.startOptButton.on('click', function () {
self.startOptButton = $(this);
if ($(this).hasClass('wio-running')) {
self.stop();
return;
}
if (self.serverDown) {
$.wrio_modal.showErrorModal(self.i18n.server_down_warning);
return;
}
if ("1" === self.settings.need_migration) {
$.wrio_modal.showErrorModal(self.i18n.need_migrations);
return;
}
if ("0" === self.settings.images_backup) {
$.wrio_modal.showWarningModal(self.i18n.process_without_backup, function () {
self.showModal();
});
return;
}
self.showModal();
return false;
});
},
checkPremiumUserBalance: function () {
var self = this,
userBalance = $('.wrio-premium-user-balance'),
balanceResetAt = $('.wrio-premium-user-update'),
data = {
'action': 'wbcr-rio-check-user-balance',
'_wpnonce': self.settings.optimization_nonce
};
userBalance.addClass('wrio-premium-user-balance-check-proccess');
userBalance.text('');
balanceResetAt.addClass('wrio-premium-user-update-check-proccess');
balanceResetAt.text('');
$.post(ajaxurl, data, function (response) {
userBalance.removeClass('wrio-premium-user-balance-check-proccess');
balanceResetAt.removeClass('wrio-premium-user-update-check-proccess');
if (!response || !response.data || !response.success) {
console.log('[Error]: Response error');
response.data && response.data.error && console.log(response.data.error);
if (!response || !response.data) {
console.log(response);
}
userBalance.text('error');
balanceResetAt.text('error');
} else {
userBalance.text(response.data?.balance);
balanceResetAt.text(response.data?.reset_at);
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
},
checkServerStatus: function () {
var self = this,
serverStatus = $('.wrio-server-status'),
data = {
'action': 'wbcr-rio-check-servers-status',
'_wpnonce': self.settings.optimization_nonce
};
self.serverDown = false;
serverStatus.addClass('wrio-server-check-proccess');
serverStatus.text('');
serverStatus.removeClass('wrio-down').removeClass('wrio-stable');
self.startOptButton.prop('disabled', true);
$.post(ajaxurl, data, function (response) {
serverStatus.removeClass('wrio-server-check-proccess');
if (!response || !response.data || !response.success) {
console.log('[Error]: Response error');
response.data && response.data.error && console.log(response.data.error);
if (!response || !response.data) {
console.log(response);
}
serverStatus.addClass('wrio-down');
serverStatus.text(self.i18n.server_status_down);
self.serverDown = true;
return;
} else {
serverStatus.addClass('wrio-stable');
serverStatus.text(self.i18n.server_status_stable);
}
self.startOptButton.prop('disabled', false);
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
},
calculateTotalImages: function () {
var self = this,
total_num = $('#wio-total-num'),
data = {
'action': 'wbcr-rio-calculate-total-images',
'_wpnonce': self.settings.optimization_nonce
};
total_num.addClass('wrio-calculate-process');
total_num.text('');
$.post(ajaxurl, data, function (response) {
total_num.removeClass('wrio-calculate-process');
if (!response || !response.data || !response.success) {
console.log('[Error]: Response error');
response.data && response.data.error && console.log(response.data.error);
if (!response || !response.data) {
console.log(response);
}
total_num.text('');
return;
} else {
if (typeof (response.data.total) !== "undefined") {
total_num.addClass('wrio-total-images');
total_num.text(response.data.total);
}
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
},
showModal: function () {
var self = this;
var infosModal = $('#wrio-tmpl-bulk-optimization');
if (!infosModal.length) {
console.log('[Error]: Html template for modal not found.');
return;
}
// Swal Information before loading the optimize process.
swal({
title: this.i18n.modal_optimization_title,
html: infosModal.html(),
type: '',
customClass: 'wrio-modal wrio-modal-optimization-way',
showCancelButton: true,
showCloseButton: true,
padding: 0,
width: 740,
confirmButtonText: this.i18n.modal_optimization_manual_button,
cancelButtonText: this.i18n.modal_optimization_cron_button,
reverseButtons: true,
}).then(function (result) {
self.process();
window.onbeforeunload = function () {
return self.i18n.leave_page_warning;
}
}, function (dismiss) {
if (dismiss === 'cancel') { // you might also handle 'close' or 'timer' if you used those
self.process('cron');
} else {
throw dismiss;
}
});
},
/**
* Start optimization
* @param {string} type
*/
process: function (type) {
var self = this;
this.inprogress = true;
var sendData = {
'action': 'wrio-bulk-optimization-process',
'scope': this.settings.scope,
'multisite': 0,
'_wpnonce': this.settings.optimization_nonce,
};
this.setButtonStyleRun(type);
if ('cron' === type) {
this.startOptButton.addClass('wrio-cron-mode');
sendData['action'] = 'wrio-cron-start';
$.post(ajaxurl, sendData, function (response) {
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Start cron).');
console.log(sendData);
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
} else {
if (response.data && response.data.stop) {
self.stop();
}
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
return;
}
this.showMessage(this.i18n.optimization_inprogress.replace("%s", parseInt($('#wio-unoptimized-num').text())));
// show message: Optimization remined
/*if( "1" === this.settings.is_network_admin ) {
sendData['multisite'] = 1;
}*/
sendData['reset_current_errors'] = 1;
this.sendRequest(sendData);
},
stop: function () {
var self = this;
this.inprogress = false;
window.onbeforeunload = null;
self.setButtonStyleStop();
self.destroyMessages();
if (this.startOptButton.hasClass('wrio-cron-mode')) {
this.startOptButton.removeClass('wrio-cron-mode');
$.post(ajaxurl, {
'action': 'wrio-cron-stop',
'_wpnonce': self.settings.optimization_nonce,
'scope': self.settings.scope
}, function (response) {
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Stop cron).');
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
}
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
}
},
complete: function () {
this.inprogress = false;
window.onbeforeunload = null;
this.setButtonStyleComplete();
},
setButtonStyleRun: function (mode) {
this.startOptButton.addClass('wio-running');
if ("cron" === mode) {
this.startOptButton.text(this.i18n.modal_optimization_cron_button_stop);
return;
}
this.startOptButton.text(this.i18n.button_stop);
},
setButtonStyleComplete: function () {
this.showMessage(this.i18n.optimization_complete);
this.startOptButton.text(this.i18n.button_completed);
this.startOptButton.removeClass('wio-running');
this.startOptButton.prop('disabled', true);
},
setButtonStyleStop: function () {
this.startOptButton.removeClass('wio-running');
this.startOptButton.text(this.i18n.button_start);
},
showMessage: function (text) {
var contanier = $('.wio-page-statistic'),
message;
if (contanier.find('.wrio-statistic-message').length) {
message = contanier.find('.wrio-statistic-message');
} else {
message = $('<div>');
message.addClass('wrio-statistic-message');
contanier.append(message);
}
message.html(text);
},
throwError: function (error_message) {
this.stop();
var noticeId = $.wbcr_factory_templates_759.app.showNotice(error_message, 'danger');
setTimeout(function () {
$.wbcr_factory_templates_759.app.hideNotice(noticeId);
}, 10000);
},
destroyMessages: function () {
$('.wio-page-statistic').find('.wrio-statistic-message').empty();
},
sendRequest: function (data) {
var self = this;
if (!this.inprogress) {
return;
}
$.post(ajaxurl, data, function (response) {
if (!self.inprogress) {
return;
}
console.log(response);
if (!response || !response.success) {
console.log('[Error]: Failed ajax request (Try to optimize images).');
console.log(response);
if (response.data && response.data.error_message) {
self.throwError(response.data.error_message);
}
return;
}
data.reset_current_errors = 0;
if (!response.data.end) {
$('#wio-total-unoptimized').text(parseInt(response.data.remain));
self.showMessage(self.i18n.optimization_inprogress.replace("%s", parseInt(response.data.remain)));
self.sendRequest(data);
} else {
$('#wio-total-unoptimized').text(response.data.remain);
self.complete();
// если мультисайт режим, то не скрываем кнопку запуска оптимизации
/*if( $('#wbcr-rio-current-blog').length ) {
$('#wio-start-optimization').toggleClass('wio-running');
} else {
$('#wio-start-optimization').hide();
}*/
}
redraw_statistics(response.data.statistic);
self.updateLog(response.data.last_optimized);
}).fail(function (xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
self.throwError(error);
});
},
updateLog: function (new_item_data) {
const self = this;
const limit = 100;
const tableEl = $('.wrio-optimization-progress .wrio-table');
if (!tableEl.length || !new_item_data) {
return;
}
// Handle empty table state
if ($('.wrio-table-container-empty').length) {
$('.wrio-table-container-empty').addClass('wrio-table-container').removeClass('wrio-table-container-empty');
if (tableEl.find('tbody').length) {
tableEl.find('tbody').empty();
}
}
$.each(new_item_data, function (index, value) {
const attachmentId = value.attachment_id || value.id;
const existingRow = tableEl.find('[data-attachment-id="' + attachmentId + '"]');
if (existingRow.length) {
// Update existing row data
self.updateRowData(existingRow, value);
// Move existing row to top of the table
existingRow.detach();
tableEl.find('tbody').prepend(existingRow);
// Re-trigger flash animation
existingRow.removeClass('flash');
// Force reflow to restart animation
existingRow[0].offsetWidth;
existingRow.addClass('flash');
} else {
// Create new row and add to top
const trEl = self.buildLogRow(value);
tableEl.find('tbody').prepend(trEl);
}
});
// Enforce row limit
self.enforceRowLimit(tableEl, limit);
},
updateRowData: function (row, data) {
// Update optimized size cell
row.find('.wrio-optimized-size').text(data.optimized_size);
// Update WebP size if present
if (data.webp_size) {
const webpCell = row.find('.wrio-webp-size');
if (webpCell.length) {
webpCell.text(data.webp_size);
}
}
// Update AVIF size if present
if (data.avif_size) {
const avifCell = row.find('.wrio-avif-size');
if (avifCell.length) {
avifCell.text(data.avif_size);
}
}
// Update total saving
row.find('.wrio-total-saving').text(data.total_saving);
// Update thumbnails count
if (data.thumbnails_count !== undefined) {
row.find('.wrio-thumbnails-count').text(data.thumbnails_count);
}
// Update error state if needed
if (data.type === 'error') {
row.addClass('wrio-error');
} else {
row.removeClass('wrio-error');
}
},
buildLogRow: function (value) {
const attachmentId = value.attachment_id || value.id;
const trEl = $('<tr>')
.addClass('flash wrio-table-item')
.addClass('wrio-row-id-' + value.id)
.attr('data-attachment-id', attachmentId);
if (value.type === 'error') {
trEl.addClass('wrio-error');
}
// Build cells with classes for easy updates
const preview = $('<img width="40" height="40" src="' + value.thumbnail_url + '" alt="">');
const previewUrl = $('<a href="' + value.url + '" target="_blank">' + value.file_name + '</a>');
trEl.append($('<td>').append(preview));
trEl.append($('<td>').append(previewUrl));
if (value.type === 'error') {
const colspan = this.settings.scope !== 'custom-folders' ? '4' : '3';
trEl.append($('<td>').attr('colspan', colspan).text("Error: " + value.error_msg));
} else {
trEl.append($('<td class="wrio-original-size">').text(value.original_size));
trEl.append($('<td class="wrio-optimized-size">').text(value.optimized_size));
if ("custom-folders" !== this.settings.scope) {
trEl.append($('<td class="wrio-thumbnails-count">').text(value.thumbnails_count));
}
trEl.append($('<td class="wrio-total-saving">').text(value.total_saving));
}
return trEl;
},
enforceRowLimit: function (tableEl, limit) {
const rows = tableEl.find('tbody tr');
if (rows.length > limit) {
rows.slice(limit).remove();
}
}
};
$(document).ready(function () {
bulkOptimization.init();
$('[data-toggle="tooltip"]').tooltip();
});
var ajaxUrl = ajaxurl;
var ai_data;
function redraw_statistics(statistic) {
$('#wio-main-chart').attr('data-unoptimized', statistic.unoptimized)
.attr('data-optimized', statistic.optimized)
.attr('data-errors', statistic.error);
$('#wio-total-optimized-attachments').text(statistic.optimized); // optimized
$('#wio-original-size').text(bytesToSize(statistic.original_size));
$('#wio-optimized-size').text(bytesToSize(statistic.optimized_size));
$('#wio-total-saved').text(statistic.save_size_percent + '%');
$('#wio-overview-chart-percent').text(statistic.optimized_percent);
$('.wio-total-percent').text(statistic.optimized_percent + '%');
$('#wio-optimized-bar').css('width', statistic.percent_line + '%');
$('#wio-unoptimized-num').text(statistic.unoptimized);
$('#wio-optimized-num').text(statistic.optimized);
$('#wio-error-num').text(statistic.error);
if(statistic.quota_limit) {
$('.wrio-premium-user-balance').text(statistic.quota_limit);
}
if ($('.wrio-statistic-nav li.active').length) {
$('.wrio-statistic-nav li.active').find('span.wio-statistic-tab-percent').text(statistic.optimized_percent + '%');
}
window.wio_chart.data.datasets[0].data[0] = statistic.error; // errors
window.wio_chart.data.datasets[0].data[1] = statistic.optimized; // optimized
window.wio_chart.data.datasets[0].data[2] = statistic.unoptimized; // unoptimized
window.wio_chart.update();
if ($('#wio-overview-chart-percent').text() == '100%') {
window.onbeforeunload = null;
}
}
/*$('#wbcr-rio-current-blog').on('change', function() {
var self = $(this);
$('#wio-start-msg-complete').hide();
$(this).attr('disabled', true);
$('#wio-start-optimization').attr('disabled', true);
var ai_data = {
'action': 'wbcr_rio_update_current_blog',
'wpnonce': $(this).data('nonce'),
'current_blog_id': $(this).find('option:selected').val(),
'context': $(this).attr('data-context')
};
$.post(ajaxUrl, ai_data, function(response) {
self.removeAttr('disabled');
$('#wio-start-optimization').removeAttr('disabled');
redraw_statistics(response.data.statistic);
});
});*/
// AVIF upsell banner dismiss handler
$(document).on('click', '.wrio-avif-banner-dismiss', function () {
var $banner = $(this).closest('.wrio-avif-upsell-banner');
$.post(ajaxurl, {
action: 'wrio_dismiss_avif_banner',
nonce: $banner.data('nonce')
}, function () {
$banner.slideUp(300, function () {
$(this).remove();
});
});
});
});

View File

@@ -0,0 +1,169 @@
(function ($) {
class BulkOptimization {
constructor(ajaxUrl, i18n, settings) {
if (!i18n || !settings) {
console.error('[Error]: Required global variables are missing.');
return;
}
this.ajaxUrl = ajaxUrl;
this.i18n = i18n;
this.settings = settings;
this.totalImages = 0;
this.countAttachments = 0;
this.countThumbs = 0;
}
/**
* Initializes the bulk optimization process by chaining multiple calculations.
* If any error occurs during the process, it will be caught and handled.
*/
init() {
this.calculateTotalAttachments()
.then(() => this.calculateTotalThumbs())
.then(() => this.calculateTotalImages())
.catch((error) => this.throwError(error));
}
/**
* Sends an AJAX POST request to the server.
*
* @param {string} action - The AJAX action to trigger on the server.
* @param {Object} additionalData - Additional data to send with the request.
* @returns {Promise<Object>} - A promise that resolves with the response data from the server.
* @throws Will throw an error if the response is invalid or the request fails.
*/
async postAjax(action, additionalData = {}) {
const data = {
action: action,
_wpnonce: this.settings.optimization_nonce,
...additionalData,
};
try {
const response = await $.post(this.ajaxUrl, data);
if (!response || !response.success || !response.data) {
console.error('[Error]: Invalid AJAX response.', response);
if (response?.data?.error) {
console.error(response.data.error);
}
throw new Error(this.i18n.ajaxError || 'AJAX Error Occurred');
}
return response.data;
} catch (xhr) {
console.error('[Error]: AJAX Request Failed.', xhr);
throw xhr;
}
}
/**
* Calculates the total number of attachments.
*
* This method sends an AJAX request to the server to fetch the total
* number of media attachments and updates the corresponding UI element with the result.
*
* @returns {Promise<void>} - A promise that resolves when the calculation is complete.
*/
async calculateTotalAttachments() {
try {
const data = await this.postAjax('wbcr-rio-calculate-total-attachments');
this.countAttachments = data.found_attachments;
$('#wio-stat-totals__originals')
.removeClass('wio-stat-totals__loading')
.text(data.found_attachments);
} catch (error) {
this.throwError(error);
}
}
/**
* Updates the total count of images by summing attachments and thumbnails.
*
* This method does not send an AJAX request. Instead, it calculates the total
* number of found images and updates the corresponding UI element.
*/
async calculateTotalImages() {
this.totalImages = this.countAttachments + this.countThumbs;
$('#wio-stat-totals__totals')
.removeClass('wio-stat-totals__loading')
.text(this.totalImages);
}
/**
* Calculates the total number of thumbnails in a paginated manner.
*
* This method sends multiple AJAX requests based on the `offset` returned
* from the server. It stops once the `done` parameter is `true` and accumulates
* the total number of thumbnails found during the process.
*
* @returns {Promise<void>} - A promise that resolves when all requests are complete.
* @throws Will throw an error if `next_offset` is missing or undefined in the response.
*/
async calculateTotalThumbs() {
try {
let offset = 0;
let totalThumbs = 0;
// Sequentially fetch thumbnail counts in batches
while (true) {
const data = await this.postAjax('wbcr-rio-calculate-total-thumbs', { offset });
// Update the total thumbnail counter
totalThumbs = data.found_thumbs;
// Update the thumbnails count in the UI
$('#wio-stat-totals__thumbnails')
.removeClass('wio-stat-totals__loading')
.text(totalThumbs);
// Break the loop if the server indicates the process is complete
if (data.done) {
break;
}
// Update the offset for the next request
offset = data.next_offset;
// Validate the offset to avoid infinite loops
if (offset === undefined || offset === null) {
console.error('[Error]: Missing offset in server response.');
throw new Error('Invalid server response: offset is undefined.');
}
}
this.countThumbs = totalThumbs;
} catch (error) {
this.throwError(error);
}
}
/**
* Handles errors by logging them to the console and displaying an alert.
*
* This method provides a standardized way to handle any unexpected errors
* that occur during the execution of the bulk optimization process.
*
* @param {Error|string} error - The error message or object to handle.
*/
throwError(error) {
console.error('[Error]:', error);
alert(this.i18n.generalError || 'An error occurred. Please try again.');
}
}
// Initialize the bulk optimization process on document ready
$(document).ready(() => {
const bulkOptimization = new BulkOptimization(
ajaxurl, // The URL for WordPress AJAX requests
window.wrio_l18n_bulk_page, // Localization data for the UI
window.wrio_settings_bulk_page // Settings data for the optimization
);
bulkOptimization.init();
});
})(jQuery);

View File

@@ -0,0 +1,2 @@
<?php
// silence is golden

View File

@@ -0,0 +1,52 @@
jQuery(function($) {
$('#wbcr-wio-meta-migration-action').on('click', function() {
var data = {
'action': 'wrio_meta_migrations',
'_wpnonce': $(this).data('nonce'),
};
$(this).addClass('disabled').text('Please wait...');
send_request($(this), data);
});
function send_request(button, data) {
$.post(window.ajaxurl, data, function(response) {
console.log(response);
if( !response || !response.data ) {
console.log('An unknown server error has occurred.');
console.log(response);
return false;
}
if( !response.data.need_more_time ) {
if( button.closest('.notice').length ) {
button.closest('.notice').remove();
}
if( button.closest('.alert').length ) {
button.closest('.alert').remove();
}
return false;
}
button.text(response.data.message);
send_request(button, data);
}).fail(function(xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
data.limit = 5;
data.error = 1;
setTimeout(function() {
send_request(button, data);
}, 2000);
});
}
});

View File

@@ -0,0 +1,57 @@
/**
* A set of tools for creating pop-ups. You can create a popup
* using a global method call.
*
* @version 1.0
*/
(function($) {
'use strict';
if( !$.wrio_modal ) {
$.wrio_modal = {};
}
$.wrio_modal = $.wrio_popup || {
showErrorModal: function(text) {
if( !text ) {
console.log('[Error]: Text required.');
return;
}
swal({
title: 'Error',
text: text,
type: 'error',
customClass: 'wrio-modal wrio-modal-error',
width: 500,
confirmButtonText: 'OK',
});
},
showWarningModal: function(text, callback) {
if( !text ) {
console.log('[Error]: Text required.');
return;
}
swal({
title: 'Warning',
text: text,
type: 'warning',
customClass: 'wrio-modal wrio-modal-warning',
width: 500,
showCancelButton: true,
showCloseButton: true,
confirmButtonText: 'OK',
}).then(function(result) {
if( callback ) {
callback();
}
}).catch(swal.noop);
},
};
})(jQuery);

View File

@@ -0,0 +1,209 @@
jQuery(function($){
var ajaxUrl = ajaxurl;
// Delivery Mode Toggle Handler
// Handles the visibility of the delivery mode options based on WebP and AVIF conversion toggles
var $webpToggle = $('input[name="wbcr_io_convert_webp_format"]');
var $avifToggle = $('input[name="wbcr_io_convert_avif_format"]');
var $deliveryModeSection = $('.wrio-conversion-delivery-options');
// Function to check if at least one toggle is enabled
function updateDeliveryModeVisibility() {
var isWebpEnabled = $webpToggle.val() === '1';
var isAvifEnabled = $avifToggle.val() === '1';
// Show delivery mode section only if at least one format is enabled
if (isWebpEnabled || isAvifEnabled) {
$deliveryModeSection.slideDown(300);
} else {
$deliveryModeSection.slideUp(300);
}
}
// Attach event listeners to both toggles
if ($webpToggle.length && $avifToggle.length && $deliveryModeSection.length) {
// Get the button containers for both toggles
var $webpButtons = $webpToggle.closest('.factory-checkbox').find('button');
var $avifButtons = $avifToggle.closest('.factory-checkbox').find('button');
// Initial check on page load
updateDeliveryModeVisibility();
// Listen for clicks on the factory buttons
$webpButtons.on('click', function() {
setTimeout(updateDeliveryModeVisibility, 50);
});
$avifButtons.on('click', function() {
setTimeout(updateDeliveryModeVisibility, 50);
});
// Also listen for direct changes on the hidden inputs (fallback)
$webpToggle.on('change', function() {
updateDeliveryModeVisibility();
});
$avifToggle.on('change', function() {
updateDeliveryModeVisibility();
});
}
$('#wio-restore-backup-btn').on('click', function() {
if ( $('#wio-multisite-mode').length ) {
$('#wio-multisite-mode').toggle();
$('#wio-multisite-confirm').attr('data-action', 'restore');
$('#wio-multisite-restore-progress').empty();
return false;
}
result = confirm( $(this).attr('data-confirm') );
if ( ! result ) {
return false;
}
$(this).hide();
$('#wio-restore-backup-progress').show();
var ai_data = {
'total' : '?',
'action': 'wio_restore_backup',
'_wpnonce': $('#wio-iph-nonce').val()
};
send_post_data(ai_data);
return false;
});
$('#wio-clear-backup-btn').on('click', function() {
$('#wio-restore-backup-msg').hide();
if ( $('#wio-multisite-mode').length ) {
$('#wio-multisite-mode').toggle();
$('#wio-multisite-confirm').attr('data-action', 'clear');
$('#wio-multisite-restore-progress').empty();
return false;
}
result = confirm( $(this).attr('data-confirm') );
if ( ! result ) {
return false;
}
var data = {
'action': 'wio_clear_backup',
'_wpnonce': $('#wio-iph-nonce').val()
};
$.post(ajaxUrl, data, function(response) {
$('#wio-clear-backup-msg').show();
});
});
$('#wio-multisite-confirm').on('click', function() {
var action = $(this).attr('data-action');
// если запущена очистка резервных копий
if ( action == 'clear' ) {
result = confirm( $('#wio-clear-backup-btn').attr('data-confirm') ); // берём сообщение из основной кнопки
if ( ! result ) {
return false;
}
var blogs = [];
$('.wbcr_io_multisite_blogs:checked').each(function() {
blogs.push( $(this).val() );
});
var data = {
'action': 'wio_clear_backup',
'_wpnonce': $('#wio-iph-nonce').val(),
'blogs': blogs
};
$.post(ajaxUrl, data, function(response) {
$('#wio-clear-backup-msg').show();
$('#wio-multisite-mode').toggle();
});
return false;
}
// если запущено восстановление из резервных копий
if ( action == 'restore' ) {
result = confirm( $('#wio-restore-backup-btn').attr('data-confirm') ); // берём сообщение из основной кнопки
if ( ! result ) {
return false;
}
$('#wio-multisite-mode').toggle();
$('#wio-multisite-restore-progress').empty();
$('.wbcr_io_multisite_blogs:checked').each(function() {
$('#wio-multisite-restore-progress').append('\
<label>'+$(this).attr('data-name')+'</label>\
<div class="progress">\
<div id="wio-restore-backup-progress-'+$(this).val()+'" class="wio-restore-backup-progressbar progress-bar progress-bar-success" data-id="'+$(this).val()+'" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%">\
</div>\
</div>\
');
});
$('#wio-multisite-restore-progress').show();
if ( ! $('.wio-restore-backup-progressbar').length ) {
$('#wio-restore-backup-msg').show();
return false;
}
var ai_data = {
'total' : '?',
'action': 'wio_restore_backup',
'_wpnonce': $('#wio-iph-nonce').val(),
'blog_id': $('.wio-restore-backup-progressbar:eq(0)').attr('data-id')
};
send_multisite_post_data(ai_data);
return false;
}
});
$('#wbcr_io_multisite_blog_all').on('change', function() {
if ( $(this).attr('checked') == 'checked' ) {
$('.wbcr_io_multisite_blogs').attr('checked', true);
} else {
$('.wbcr_io_multisite_blogs').removeAttr('checked');
}
});
$('.wbcr_io_multisite_blogs').on('change', function() {
var all_checked = true;
$('.wbcr_io_multisite_blogs').each(function() {
if ( $(this).attr('checked') != 'checked' ) {
all_checked = false;
}
});
if ( all_checked ) {
$('#wbcr_io_multisite_blog_all').attr('checked', true);
} else {
$('#wbcr_io_multisite_blog_all').removeAttr('checked');
}
});
function send_post_data(data){
$.post(ajaxUrl, data, function(response) {
if ( ! response.end ) {
data.total = response.total;
send_post_data(data);
$('#wio-restore-backup-progress').find('.progress-bar').css( 'width', response.percent + '%' );
} else {
$('#wio-restore-backup-progress').find('.progress-bar').css( 'width', '100%' );
$('#wio-restore-backup-msg').show();
}
});
}
function send_multisite_post_data(data){
$.post(ajaxUrl, data, function(response) {
if ( ! response.end ) {
data.total = response.total;
send_multisite_post_data(data);
$('#wio-restore-backup-progress-' + data.blog_id).css( 'width', response.percent + '%' );
} else {
$('#wio-restore-backup-progress-' + data.blog_id).css( 'width', '100%' ).removeClass('wio-restore-backup-progressbar');
if ( $('.wio-restore-backup-progressbar').length ) {
var ai_data = {
'total' : '?',
'action': 'wio_restore_backup',
'_wpnonce': $('#wio-iph-nonce').val(),
'blog_id': $('.wio-restore-backup-progressbar:eq(0)').attr('data-id')
};
send_multisite_post_data(ai_data);
} else {
$('#wio-restore-backup-msg').show();
}
}
});
}
});

View File

@@ -0,0 +1,5 @@
jQuery(document).ready(function($) {
// Disable premium dropdown buttons for non-licensed users
$('button[data-value="googlepage"]').attr('disabled', 'disabled');
$('button[data-value="background"]').attr('disabled', 'disabled');
});

View File

@@ -0,0 +1,102 @@
jQuery(function($) {
var ajaxUrl = ajaxurl;
$(document).on('click', '.wio-reoptimize', function() {
var ai_data = {
'action' : $(this).attr('data-action'),
'id' : $(this).attr('data-id'),
'level' : $(this).attr('data-level'),
'_wpnonce' : $(this).attr('data-nonce')
};
var td = $(this).closest('td');
var msg = $(this).attr( 'data-waiting-label' );
td.html('<p>'+msg+'</p>');
wio_reoptimize( ai_data, td );
return false;
});
$(document).on('click', '.wio-convert', function() {
var ai_data = {
'action' : $(this).attr('data-action'),
'id' : $(this).attr('data-id'),
'format' : $(this).attr('data-format'),
'_wpnonce' : $(this).attr('data-nonce')
};
var td = $(this).closest('td');
var msg = $(this).attr( 'data-waiting-label' );
td.html('<p>'+msg+'</p>');
wio_convert( ai_data, td );
return false;
});
function wio_reoptimize( ai_data, td ) {
$.post(ajaxUrl, ai_data, function(response) {
if ( response === 'processing' ) {
wio_reoptimize( ai_data, td );
return false;
}
td.html(response);
var btn = $('.wio-reoptimize').first();
if ( btn.closest('.media-frame-content').length ) {
if ( btn.closest('table').find('.wio-datas-list').length ) {
var diminsionName = $('.dimensions').find('strong').clone();
var fileSizeName = $('.file-size').find('strong').clone();
var diminsionSize = btn.closest('table').find('.wio-datas-list').data('dimensions');
var fileSize = btn.closest('table').find('.wio-datas-list').data('size');
$('.dimensions').html(diminsionName.get(0).outerHTML + ' ' + diminsionSize);
$('.file-size').html(fileSizeName.get(0).outerHTML + ' ' + fileSize);
}
}
});
}
function wio_convert( ai_data, td ) {
$.post(ajaxUrl, ai_data, function(response) {
if ( response === 'processing' ) {
wio_convert( ai_data, td );
return false;
}
td.html(response);
var btn = $('.wio-convert').first();
if ( btn.closest('.media-frame-content').length ) {
if ( btn.closest('table').find('.wio-datas-list').length ) {
var diminsionName = $('.dimensions').find('strong').clone();
var fileSizeName = $('.file-size').find('strong').clone();
var diminsionSize = btn.closest('table').find('.wio-datas-list').data('dimensions');
var fileSize = btn.closest('table').find('.wio-datas-list').data('size');
$('.dimensions').html(diminsionName.get(0).outerHTML + ' ' + diminsionSize);
$('.file-size').html(fileSizeName.get(0).outerHTML + ' ' + fileSize);
}
}
});
}
$(document).on('click', '.button-wio-restore', function() {
var ai_data = {
'action' : $(this).attr('data-action'),
'id' : $(this).attr('data-id'),
'_wpnonce' : $(this).attr('data-nonce')
};
var td = $(this).closest('td');
var msg = $(this).attr( 'data-waiting-label' );
td.html('<p>'+msg+'</p>');
$.post(ajaxUrl, ai_data, function(response) {
td.html(response);
var btn = $('.wio-reoptimize');
if ( btn.closest('.media-frame-content').length ) {
if ( btn.length ) {
btn = btn.first();
var diminsionName = $('.dimensions').find('strong').clone();
var fileSizeName = $('.file-size').find('strong').clone();
var diminsionSize = btn.data('dimensions');
var fileSize = btn.data('size');
$('.dimensions').html(diminsionName.get(0).outerHTML + ' ' + diminsionSize);
$('.file-size').html(fileSizeName.get(0).outerHTML + ' ' + fileSize);
}
}
});
return false;
});
});

View File

@@ -0,0 +1,113 @@
jQuery(function ($) {
var chart_html_id = 'wio-main-chart';
var webp_chart_html_id = 'wio-webp-chart';
var avif_chart_html_id = 'wio-avif-chart';
var ctx = document.getElementById(chart_html_id);
var ctx_webp = document.getElementById(webp_chart_html_id);
var ctx_avif = document.getElementById(avif_chart_html_id);
window.wio_chart = new window.robin.Chart(ctx, {
type: 'doughnut',
data: {
datasets: [
{
data: [
$('#' + chart_html_id).attr('data-errors'),
$('#' + chart_html_id).attr('data-optimized'),
$('#' + chart_html_id).attr('data-unoptimized'),
],
backgroundColor: [
'#f1b1b6',
'#8bc34a',
'#d6d6d6',
],
borderWidth: 0,
label: 'Dataset 1'
}
]
},
options: {
legend: {
display: false
},
events: [],
animation: {
easing: 'easeOutBounce'
},
responsive: false,
cutoutPercentage: 80
}
});
if (ctx_webp) {
window.wio_chart_webp = new window.robin.Chart(ctx_webp, {
type: 'doughnut',
data: {
datasets: [
{
data: [
$('#' + webp_chart_html_id).attr('data-errors'),
$('#' + webp_chart_html_id).attr('data-optimized'),
$('#' + webp_chart_html_id).attr('data-unoptimized'),
],
backgroundColor: [
'#f1b1b6',
'#8bc34a',
'#d6d6d6',
],
borderWidth: 0,
label: 'Dataset 1'
}
]
},
options: {
legend: {
display: false
},
events: [],
animation: {
easing: 'easeOutBounce'
},
responsive: false,
cutoutPercentage: 80
}
});
}
if (ctx_avif) {
window.wio_chart_avif = new window.robin.Chart(ctx_avif, {
type: 'doughnut',
data: {
datasets: [
{
data: [
$('#' + avif_chart_html_id).attr('data-errors'),
$('#' + avif_chart_html_id).attr('data-optimized'),
$('#' + avif_chart_html_id).attr('data-unoptimized'),
],
backgroundColor: [
'#f1b1b6',
'#8bc34a',
'#d6d6d6',
],
borderWidth: 0,
label: 'Dataset 1'
}
]
},
options: {
legend: {
display: false
},
events: [],
animation: {
easing: 'easeOutBounce'
},
responsive: false,
cutoutPercentage: 80
}
});
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
/**
* License Manager JavaScript
*
* Handles license activation, deactivation, sync, and unsubscribe actions.
* This is a lightweight replacement for clearfy-license-manager.js
*
* @package Robin_Image_Optimizer
*/
jQuery(function($) {
'use strict';
/**
* Handle license action button clicks
*/
$(document).on('click', '.wrio-license-btn', function(e) {
e.preventDefault();
// Remove any existing notices when user tries again
$('.wrio-license-notice').remove();
var $button = $(this),
$wrapper = $('#wrio-license-wrapper'),
action = $button.data('action'),
nonce = $wrapper.data('nonce'),
loaderUrl = $wrapper.data('loader');
// Disable all buttons and show loader inside the clicked button
$('.wrio-license-btn').prop('disabled', true);
$button.prepend('<img class="wrio-loader" src="' + loaderUrl + '" alt="Loading..." style="height: 16px; vertical-align: middle; margin-right: 8px;">');
// Build request data
var data = {
action: 'wrio_license_action',
_wpnonce: nonce,
license_action: action,
licensekey: ''
};
// Include license key for activation
if (action === 'activate') {
data.licensekey = $('#license-key').val().trim();
if (!data.licensekey) {
showNotice('Please enter a license key.', 'error');
resetButtons();
return;
}
}
// Send AJAX request
$.ajax({
url: ajaxurl,
type: 'POST',
dataType: 'json',
data: data,
success: function(response) {
if (response && response.success) {
showNotice(response.data.message, 'success');
// Reload page to show updated license state
setTimeout(function() {
window.location.reload();
}, 1000);
} else {
var errorMsg = response && response.data && response.data.message
? response.data.message
: 'An error occurred. Please try again.';
showNotice(errorMsg, 'error');
resetButtons();
}
},
error: function(xhr, status, error) {
console.error('WRIO License AJAX Error:', {
status: xhr.status,
statusText: xhr.statusText,
responseText: xhr.responseText,
error: error
});
var errorMsg = 'Connection error. Please check your internet connection and try again.';
if (xhr.responseText) {
try {
var response = JSON.parse(xhr.responseText);
if (response.data && response.data.message) {
errorMsg = response.data.message;
}
} catch (e) {
// Response wasn't JSON
}
}
showNotice(errorMsg, 'error');
resetButtons();
}
});
});
/**
* Reset buttons to their original state
*/
function resetButtons() {
$('.wrio-loader').remove();
$('.wrio-license-btn').prop('disabled', false);
}
/**
* Show a notice message
*
* @param {string} message The message to display
* @param {string} type Notice type: 'success' or 'error'
*/
function showNotice(message, type) {
// Remove any existing notices
$('.wrio-license-notice').remove();
var typeClass = type === 'success' ? 'wrio-license-notice--success' : 'wrio-license-notice--error';
var $notice = $('<div class="wrio-license-notice ' + typeClass + '"><p>' + escapeHtml(message) + '</p></div>');
// Insert into the error container
$('#license-form-error-container').html($notice);
// Auto-dismiss after 5 seconds for success messages
if (type === 'success') {
setTimeout(function() {
$notice.fadeOut(function() {
$(this).remove();
});
}, 5000);
}
}
/**
* Escape HTML entities
*
* @param {string} text Text to escape
* @return {string} Escaped text
*/
function escapeHtml(text) {
var map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return String(text).replace(/[&<>"']/g, function(m) { return map[m]; });
}
});