PluginProbe ʕ •ᴥ•ʔ
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF / 2.0.6
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF v2.0.6
2.0.6 2.0.5 trunk 1.3.7 1.4.0 1.4.1 1.4.2 1.4.6 1.5.0 1.5.3 1.5.6 1.5.8 1.6.5 1.6.6 1.6.9 1.7.0 1.7.4 1.8.1 1.8.2 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4
robin-image-optimizer / admin / assets / js / bulk-conversion.js
robin-image-optimizer / admin / assets / js Last commit date
Chart.min.js 7 months ago bulk-conversion.js 7 months ago bulk-optimization.js 7 months ago calculate-attachments.js 1 year ago index.php 3 years ago meta-migrations.js 3 years ago modals.js 7 months ago notices.js 3 months ago restore-backup.js 7 months ago settings-premium.js 7 months ago single-optimization.js 7 months ago statistic.js 7 months ago sweetalert2.js 3 years ago wrio-license-manager.js 7 months ago
bulk-conversion.js
471 lines
1 jQuery(function ($) {
2 /**
3 * Factory function to create a bulk conversion handler for a specific format.
4 *
5 * @param {string} format - The conversion format ('webp' or 'avif')
6 * @param {string} buttonSelector - jQuery selector for the start button
7 * @returns {Object} - Bulk conversion handler object
8 */
9 function createBulkConversion(format, buttonSelector) {
10 return {
11 format: format,
12 inprogress: false,
13 serverDown: false,
14 i18n: {},
15 settings: {},
16 startConvertButton: $(buttonSelector),
17 startOptButton: $('#wrio-start-optimization'),
18 startWebpButton: $('#wrio-start-conversion'),
19 startAvifButton: $('#wrio-start-avif-conversion'),
20
21 init: function () {
22 this.i18n = wrio_l18n_bulk_page;
23 this.settings = wrio_settings_bulk_page;
24
25 if (this.startConvertButton.length) {
26 this.registerEvents();
27 this.checkInitialRunningState();
28 }
29 },
30
31 checkInitialRunningState: function () {
32 // If this conversion button is already running on page load, disable other buttons
33 if (this.startConvertButton.hasClass('wio-running')) {
34 this.startOptButton.prop('disabled', true);
35 // Disable the other conversion button (not this one)
36 if (this.format === 'webp') {
37 this.startAvifButton.prop('disabled', true);
38 } else {
39 this.startWebpButton.prop('disabled', true);
40 }
41 }
42 },
43
44 registerEvents: function () {
45 var self = this;
46 this.startConvertButton.on('click', function () {
47
48 if ($(this).hasClass('wio-running')) {
49 self.startOptButton.prop('disabled', false);
50 self.startWebpButton.prop('disabled', false);
51 self.startAvifButton.prop('disabled', false);
52 self.stop();
53 return;
54 }
55
56 self.showModal();
57
58 return false;
59 });
60 },
61
62 showModal: function () {
63 var self = this;
64 var infosModal = $('#wrio-tmpl-' + this.format + '-conversion');
65
66 // Fall back to webp template if format-specific one doesn't exist
67 if (!infosModal.length) {
68 infosModal = $('#wrio-tmpl-webp-conversion');
69 }
70
71 if (!infosModal.length) {
72 console.log('[Error]: Html template for modal not found.');
73 return;
74 }
75
76 var modalTitle = this.format === 'avif'
77 ? (this.i18n.modal_avif_conversion_title || this.i18n.modal_conversion_title)
78 : this.i18n.modal_conversion_title;
79
80 // Swal Information before loading the optimize process.
81 swal({
82 title: modalTitle,
83 html: infosModal.html(),
84 type: '',
85 customClass: 'wrio-modal wrio-modal-optimization-way',
86 showCancelButton: true,
87 showCloseButton: true,
88 padding: 0,
89 width: 740,
90 confirmButtonText: this.i18n.modal_conversion_manual_button,
91 cancelButtonText: this.i18n.modal_conversion_cron_button,
92 reverseButtons: true,
93 }).then(function (result) {
94
95 self.startOptButton.prop('disabled', true);
96 self.startWebpButton.prop('disabled', true);
97 self.startAvifButton.prop('disabled', true);
98 self.startConvertButton.prop('disabled', false); // Re-enable current button for stop
99 self.process();
100
101 window.onbeforeunload = function () {
102 return self.i18n.leave_page_warning;
103 }
104
105 }, function (dismiss) {
106 if (dismiss === 'cancel') { // you might also handle 'close' or 'timer' if you used those
107 self.startOptButton.prop('disabled', true);
108 self.startWebpButton.prop('disabled', true);
109 self.startAvifButton.prop('disabled', true);
110 self.startConvertButton.prop('disabled', false); // Re-enable current button for stop
111 self.process('cron');
112 } else {
113 throw dismiss;
114 }
115 });
116
117 },
118
119 /**
120 * Start conversion
121 * @param {string} type - 'cron' or undefined for manual
122 */
123 process: function (type) {
124 var self = this;
125 this.inprogress = true;
126
127 var sendData = {
128 'action': 'wrio-bulk-conversion-process',
129 'scope': this.settings.scope,
130 'format': this.format,
131 'multisite': 0,
132 '_wpnonce': this.settings.conversion_nonce,
133 };
134
135 this.setButtonStyleRun(type);
136
137 if ('cron' === type) {
138 this.startConvertButton.addClass('wrio-cron-mode');
139
140 sendData['action'] = 'wrio-' + this.format + '-cron-start';
141
142 $.post(ajaxurl, sendData, function (response) {
143 if (!response || !response.success) {
144 console.log('[Error]: Failed ajax request (Start cron).');
145 console.log(sendData);
146 console.log(response);
147
148 if (response.data && response.data.error_message) {
149 self.throwError(response.data.error_message);
150 }
151 } else {
152 if (response.data && response.data.stop) {
153 self.stop();
154 }
155 }
156 }).fail(function (xhr, status, error) {
157 console.log(xhr);
158 console.log(status);
159 console.log(error);
160
161 self.throwError(error);
162 });
163
164 return;
165 }
166
167 this.showMessage(this.i18n.conversion_inprogress.replace("%s", parseInt($('#wio-unoptimized-num').text())));
168
169 sendData['reset_current_errors'] = 1;
170
171 this.sendRequest(sendData);
172 },
173
174 stop: function () {
175 var self = this;
176 this.inprogress = false;
177
178 window.onbeforeunload = null;
179 self.setButtonStyleStop();
180 self.destroyMessages();
181
182 if (this.startConvertButton.hasClass('wrio-cron-mode')) {
183 this.startConvertButton.removeClass('wrio-cron-mode');
184
185 $.post(ajaxurl, {
186 'action': 'wrio-' + this.format + '-cron-stop',
187 '_wpnonce': self.settings.conversion_nonce,
188 'scope': self.settings.scope
189 }, function (response) {
190 if (!response || !response.success) {
191 console.log('[Error]: Failed ajax request (Stop cron).');
192 console.log(response);
193
194 if (response.data && response.data.error_message) {
195 self.throwError(response.data.error_message);
196 }
197 } else {
198 self.startOptButton.prop('disabled', false);
199 self.startWebpButton.prop('disabled', false);
200 self.startAvifButton.prop('disabled', false);
201 }
202 }).fail(function (xhr, status, error) {
203 console.log(xhr);
204 console.log(status);
205 console.log(error);
206
207 self.throwError(error);
208 });
209 }
210
211 },
212
213 complete: function () {
214 this.inprogress = false;
215 window.onbeforeunload = null;
216 this.setButtonStyleComplete();
217 },
218
219 setButtonStyleRun: function (mode) {
220
221 this.startConvertButton.addClass('wio-running');
222
223 if ("cron" === mode) {
224 this.startConvertButton.text(this.i18n.modal_conversion_cron_button_stop);
225 return;
226 }
227
228 this.startConvertButton.text(this.i18n.button_stop);
229 },
230
231 setButtonStyleComplete: function () {
232 this.showMessage(this.i18n.conversion_complete);
233 this.startConvertButton.text(this.i18n.button_completed);
234 this.startConvertButton.removeClass('wio-running');
235 this.startConvertButton.prop('disabled', true);
236 this.startOptButton.prop('disabled', false);
237 this.startWebpButton.prop('disabled', false);
238 this.startAvifButton.prop('disabled', false);
239 },
240
241 setButtonStyleStop: function () {
242 this.startConvertButton.removeClass('wio-running');
243 var buttonText = this.format === 'avif'
244 ? (this.i18n.avif_button_start || 'Convert to AVIF')
245 : this.i18n.webp_button_start;
246 this.startConvertButton.text(buttonText);
247 },
248
249 showMessage: function (text) {
250 var contanier = $('.wio-page-statistic'),
251 message;
252
253 if (contanier.find('.wrio-statistic-message').length) {
254 message = contanier.find('.wrio-statistic-message');
255 } else {
256 message = $('<div>');
257 message.addClass('wrio-statistic-message');
258 contanier.append(message);
259 }
260
261 message.html(text);
262 },
263
264 throwError: function (error_message) {
265 this.stop();
266
267 var noticeId = $.wbcr_factory_templates_759.app.showNotice(error_message, 'danger');
268
269 setTimeout(function () {
270 $.wbcr_factory_templates_759.app.hideNotice(noticeId);
271 }, 10000);
272 },
273
274 destroyMessages: function () {
275 $('.wio-page-statistic').find('.wrio-statistic-message').empty();
276 },
277
278 sendRequest: function (data) {
279 var self = this;
280
281 if (!this.inprogress) {
282 return;
283 }
284
285 $.post(ajaxurl, data, function (response) {
286 if (!self.inprogress) {
287 return;
288 }
289
290 if (!response || !response.success) {
291 console.log('[Error]: Failed ajax request (Try to optimize images).');
292 console.log(response);
293
294 if (response.data && response.data.error_message) {
295 self.throwError(response.data.error_message);
296 }
297
298 return;
299 }
300
301 data.reset_current_errors = 0;
302
303 if (!response.data.end) {
304 $('#wio-total-unoptimized').text(parseInt(response.data.remain));
305 self.showMessage(self.i18n.conversion_inprogress.replace("%s", parseInt(response.data.remain)));
306 self.sendRequest(data);
307 } else {
308 $('#wio-total-unoptimized').text(response.data.remain);
309 self.complete();
310 }
311
312 redraw_statistics(response.data.statistic);
313
314 if (response.data.last_optimized) {
315 self.updateLog(response.data.last_optimized);
316 }
317 if (response.data.last_converted) {
318 self.updateLog(response.data.last_converted);
319 }
320 }).fail(function (xhr, status, error) {
321 console.log(xhr);
322 console.log(status);
323 console.log(error);
324
325 self.throwError(error);
326 });
327 },
328
329 updateLog: function (new_item_data) {
330 var self = this;
331
332 var limit = 100,
333 tableEl = $('.wrio-optimization-progress .wrio-table');
334
335 if (!tableEl.length || !new_item_data) {
336 return;
337 }
338
339 // Clear empty table state
340 if ($('.wrio-table-container-empty').length) {
341 $('.wrio-table-container-empty').addClass('wrio-table-container').removeClass('wrio-table-container-empty');
342 if (tableEl.find('tbody').length) {
343 tableEl.find('tbody').empty();
344 }
345 }
346
347 $.each(new_item_data, function (index, value) {
348 var trEl = $('<tr>'),
349 tdEl = $('<td>'),
350 webpSize = value.webp_size ? value.webp_size : '-',
351 avifSize = value.avif_size ? value.avif_size : '-';
352
353 if (tableEl.find('.wrio-row-id-' + value.id).length) {
354 tableEl.find('.wrio-row-id-' + value.id).remove();
355 }
356
357 trEl.addClass('flash').addClass('wrio-table-item').addClass('wrio-row-id-' + value.id);
358
359 if ('error' === value.type) {
360 trEl.addClass('wrio-error');
361 }
362
363 var preview = $('<img width="40" height="40" src="' + value.thumbnail_url + '" alt="">'),
364 previewUrl = $('<a href="' + value.url + '" target="_blank">' + value.file_name + '</a>');
365
366 tableEl.prepend(trEl);
367
368 trEl.append(tdEl.clone().append(preview));
369 trEl.append(tdEl.clone().append(previewUrl));
370
371 if ('error' === value.type) {
372 var colspan = value.scope !== 'custom-folders' ? '7' : '6';
373 trEl.append(tdEl.clone().attr('colspan', colspan).text("Error: " + value.error_msg));
374 } else {
375 trEl.append(tdEl.clone().text(value.original_size));
376 trEl.append(tdEl.clone().text(value.optimized_size));
377 trEl.append(tdEl.clone().text(webpSize));
378 trEl.append(tdEl.clone().text(avifSize));
379 trEl.append(tdEl.clone().text(value.original_saving));
380
381 if ("custom-folders" !== self.settings.scope) {
382 trEl.append(tdEl.clone().text(value.thumbnails_count));
383 }
384
385 trEl.append(tdEl.clone().text(value.total_saving));
386 }
387 });
388
389 if (tableEl.find('tr').length > limit) {
390 var diff = tableEl.find('tr').length - limit;
391
392 for (var i = 0; i < diff; i++) {
393 tableEl.find('tr:last').remove();
394 }
395 }
396 }
397 };
398 }
399
400 // Create WebP conversion handler
401 var bulkConversionWebp = createBulkConversion('webp', '#wrio-start-conversion');
402
403 // Create AVIF conversion handler
404 var bulkConversionAvif = createBulkConversion('avif', '#wrio-start-avif-conversion');
405
406 $(document).ready(function () {
407 bulkConversionWebp.init();
408 bulkConversionAvif.init();
409 $('[data-toggle="tooltip"]').tooltip();
410 });
411
412 var ajaxUrl = ajaxurl;
413 var ai_data;
414
415 function redraw_statistics(statistic) {
416 // Update WebP stats - chart data attributes
417 $('#wio-webp-chart').attr('data-unoptimized', statistic.unconverted)
418 .attr('data-optimized', statistic.converted)
419 .attr('data-errors', statistic.webp_error);
420
421 // Update WebP percent display
422 $('#wio-overview-chart-percent-webp').text(statistic.webp_percent_line);
423
424 // Update WebP legend
425 $('#wio-webp-pending').text(statistic.unconverted);
426 $('#wio-webp-converted').text(statistic.converted);
427 $('#wio-webp-error').text(statistic.webp_error);
428 $('#wio-webp-done').text(statistic.converted);
429
430 // Update AVIF stats (if available)
431 if (statistic.avif_unconverted !== undefined) {
432 $('#wio-avif-chart').attr('data-unoptimized', statistic.avif_unconverted)
433 .attr('data-optimized', statistic.avif_converted)
434 .attr('data-errors', statistic.avif_error);
435
436 // Update AVIF percent display
437 $('#wio-overview-chart-percent-avif').text(statistic.avif_percent_line);
438
439 // Update AVIF legend
440 $('#wio-avif-pending').text(statistic.avif_unconverted);
441 $('#wio-avif-converted').text(statistic.avif_converted);
442 $('#wio-avif-error').text(statistic.avif_error);
443 $('#wio-avif-done').text(statistic.avif_converted);
444 }
445
446 var credits = $('.wrio-premium-user-balance');
447 if (credits.attr('data-server') !== "server_5") {
448 credits.text(statistic.credits);
449 }
450
451 if (window.wio_chart_webp) {
452 window.wio_chart_webp.data.datasets[0].data[0] = statistic.webp_error; // errors
453 window.wio_chart_webp.data.datasets[0].data[1] = statistic.converted; // optimized
454 window.wio_chart_webp.data.datasets[0].data[2] = statistic.unconverted; // unoptimized
455 window.wio_chart_webp.update();
456 }
457
458 if (window.wio_chart_avif && statistic.avif_unconverted !== undefined) {
459 window.wio_chart_avif.data.datasets[0].data[0] = statistic.avif_error; // errors
460 window.wio_chart_avif.data.datasets[0].data[1] = statistic.avif_converted; // optimized
461 window.wio_chart_avif.data.datasets[0].data[2] = statistic.avif_unconverted; // unoptimized
462 window.wio_chart_avif.update();
463 }
464
465 if ($('#wio-overview-chart-percent-webp').text() == '100') {
466 window.onbeforeunload = null;
467 }
468 }
469
470 });
471