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-optimization.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-optimization.js
647 lines
1 function bytesToSize(bytes) {
2 var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
3 if (bytes === 0) {
4 return '0 Byte';
5 }
6 var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
7 if (i === 0) {
8 return bytes + ' ' + sizes[i];
9 }
10 return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
11 }
12
13 jQuery(function ($) {
14 var bulkOptimization = {
15 inprogress: false,
16 serverDown: false,
17 i18n: {},
18 settings: {},
19
20 init: function () {
21 if (wrio_l18n_bulk_page === undefined || wrio_settings_bulk_page === undefined) {
22 console.log('[Error]: Required global variables are not declared.');
23 return;
24 }
25
26 this.i18n = wrio_l18n_bulk_page;
27 this.settings = wrio_settings_bulk_page;
28 this.startOptButton = $('#wrio-start-optimization');
29
30 this.registerEvents();
31 this.checkServerStatus();
32 //this.calculateTotalImages();
33 this.checkPremiumUserBalance();
34 },
35
36 registerEvents: function () {
37 var self = this;
38
39 this.startOptButton.on('click', function () {
40 self.startOptButton = $(this);
41
42 if ($(this).hasClass('wio-running')) {
43 self.stop();
44 return;
45 }
46
47 if (self.serverDown) {
48 $.wrio_modal.showErrorModal(self.i18n.server_down_warning);
49 return;
50 }
51
52 if ("1" === self.settings.need_migration) {
53 $.wrio_modal.showErrorModal(self.i18n.need_migrations);
54 return;
55 }
56
57 if ("0" === self.settings.images_backup) {
58 $.wrio_modal.showWarningModal(self.i18n.process_without_backup, function () {
59 self.showModal();
60 });
61 return;
62 }
63
64 self.showModal();
65
66 return false;
67 });
68 },
69
70 checkPremiumUserBalance: function () {
71 var self = this,
72 userBalance = $('.wrio-premium-user-balance'),
73 balanceResetAt = $('.wrio-premium-user-update'),
74 data = {
75 'action': 'wbcr-rio-check-user-balance',
76 '_wpnonce': self.settings.optimization_nonce
77 };
78
79 userBalance.addClass('wrio-premium-user-balance-check-proccess');
80 userBalance.text('');
81
82 balanceResetAt.addClass('wrio-premium-user-update-check-proccess');
83 balanceResetAt.text('');
84
85 $.post(ajaxurl, data, function (response) {
86
87 userBalance.removeClass('wrio-premium-user-balance-check-proccess');
88 balanceResetAt.removeClass('wrio-premium-user-update-check-proccess');
89
90 if (!response || !response.data || !response.success) {
91 console.log('[Error]: Response error');
92 response.data && response.data.error && console.log(response.data.error);
93
94 if (!response || !response.data) {
95 console.log(response);
96 }
97
98 userBalance.text('error');
99 balanceResetAt.text('error');
100 } else {
101 userBalance.text(response.data?.balance);
102 balanceResetAt.text(response.data?.reset_at);
103 }
104 }).fail(function (xhr, status, error) {
105 console.log(xhr);
106 console.log(status);
107 console.log(error);
108
109 self.throwError(error);
110 });
111 },
112
113 checkServerStatus: function () {
114 var self = this,
115 serverStatus = $('.wrio-server-status'),
116 data = {
117 'action': 'wbcr-rio-check-servers-status',
118 '_wpnonce': self.settings.optimization_nonce
119 };
120
121 self.serverDown = false;
122
123 serverStatus.addClass('wrio-server-check-proccess');
124 serverStatus.text('');
125 serverStatus.removeClass('wrio-down').removeClass('wrio-stable');
126
127 self.startOptButton.prop('disabled', true);
128
129 $.post(ajaxurl, data, function (response) {
130 serverStatus.removeClass('wrio-server-check-proccess');
131
132 if (!response || !response.data || !response.success) {
133 console.log('[Error]: Response error');
134 response.data && response.data.error && console.log(response.data.error);
135
136 if (!response || !response.data) {
137 console.log(response);
138 }
139
140 serverStatus.addClass('wrio-down');
141 serverStatus.text(self.i18n.server_status_down);
142 self.serverDown = true;
143
144 return;
145 } else {
146 serverStatus.addClass('wrio-stable');
147 serverStatus.text(self.i18n.server_status_stable);
148 }
149
150 self.startOptButton.prop('disabled', false);
151
152 }).fail(function (xhr, status, error) {
153 console.log(xhr);
154 console.log(status);
155 console.log(error);
156
157 self.throwError(error);
158 });
159 },
160
161 calculateTotalImages: function () {
162 var self = this,
163 total_num = $('#wio-total-num'),
164 data = {
165 'action': 'wbcr-rio-calculate-total-images',
166 '_wpnonce': self.settings.optimization_nonce
167 };
168
169 total_num.addClass('wrio-calculate-process');
170 total_num.text('');
171
172 $.post(ajaxurl, data, function (response) {
173 total_num.removeClass('wrio-calculate-process');
174
175 if (!response || !response.data || !response.success) {
176 console.log('[Error]: Response error');
177 response.data && response.data.error && console.log(response.data.error);
178
179 if (!response || !response.data) {
180 console.log(response);
181 }
182
183 total_num.text('');
184
185 return;
186 } else {
187 if (typeof (response.data.total) !== "undefined") {
188 total_num.addClass('wrio-total-images');
189 total_num.text(response.data.total);
190 }
191 }
192 }).fail(function (xhr, status, error) {
193 console.log(xhr);
194 console.log(status);
195 console.log(error);
196
197 self.throwError(error);
198 });
199 },
200
201 showModal: function () {
202 var self = this;
203 var infosModal = $('#wrio-tmpl-bulk-optimization');
204
205 if (!infosModal.length) {
206 console.log('[Error]: Html template for modal not found.');
207 return;
208 }
209
210 // Swal Information before loading the optimize process.
211 swal({
212 title: this.i18n.modal_optimization_title,
213 html: infosModal.html(),
214 type: '',
215 customClass: 'wrio-modal wrio-modal-optimization-way',
216 showCancelButton: true,
217 showCloseButton: true,
218 padding: 0,
219 width: 740,
220 confirmButtonText: this.i18n.modal_optimization_manual_button,
221 cancelButtonText: this.i18n.modal_optimization_cron_button,
222 reverseButtons: true,
223 }).then(function (result) {
224 self.process();
225
226 window.onbeforeunload = function () {
227 return self.i18n.leave_page_warning;
228 }
229
230 }, function (dismiss) {
231 if (dismiss === 'cancel') { // you might also handle 'close' or 'timer' if you used those
232 self.process('cron');
233 } else {
234 throw dismiss;
235 }
236 });
237
238 },
239
240 /**
241 * Start optimization
242 * @param {string} type
243 */
244 process: function (type) {
245 var self = this;
246
247 this.inprogress = true;
248
249 var sendData = {
250 'action': 'wrio-bulk-optimization-process',
251 'scope': this.settings.scope,
252 'multisite': 0,
253 '_wpnonce': this.settings.optimization_nonce,
254 };
255
256 this.setButtonStyleRun(type);
257
258 if ('cron' === type) {
259 this.startOptButton.addClass('wrio-cron-mode');
260
261 sendData['action'] = 'wrio-cron-start';
262
263 $.post(ajaxurl, sendData, function (response) {
264 if (!response || !response.success) {
265 console.log('[Error]: Failed ajax request (Start cron).');
266 console.log(sendData);
267 console.log(response);
268
269 if (response.data && response.data.error_message) {
270 self.throwError(response.data.error_message);
271 }
272 } else {
273 if (response.data && response.data.stop) {
274 self.stop();
275 }
276 }
277 }).fail(function (xhr, status, error) {
278 console.log(xhr);
279 console.log(status);
280 console.log(error);
281
282 self.throwError(error);
283 });
284
285 return;
286 }
287
288 this.showMessage(this.i18n.optimization_inprogress.replace("%s", parseInt($('#wio-unoptimized-num').text())));
289
290 // show message: Optimization remined
291 /*if( "1" === this.settings.is_network_admin ) {
292 sendData['multisite'] = 1;
293 }*/
294
295 sendData['reset_current_errors'] = 1;
296
297 this.sendRequest(sendData);
298 },
299
300 stop: function () {
301 var self = this;
302
303 this.inprogress = false;
304
305 window.onbeforeunload = null;
306 self.setButtonStyleStop();
307 self.destroyMessages();
308
309 if (this.startOptButton.hasClass('wrio-cron-mode')) {
310 this.startOptButton.removeClass('wrio-cron-mode');
311
312 $.post(ajaxurl, {
313 'action': 'wrio-cron-stop',
314 '_wpnonce': self.settings.optimization_nonce,
315 'scope': self.settings.scope
316 }, function (response) {
317 if (!response || !response.success) {
318 console.log('[Error]: Failed ajax request (Stop cron).');
319 console.log(response);
320
321 if (response.data && response.data.error_message) {
322 self.throwError(response.data.error_message);
323 }
324 }
325 }).fail(function (xhr, status, error) {
326 console.log(xhr);
327 console.log(status);
328 console.log(error);
329
330 self.throwError(error);
331 });
332 }
333
334 },
335
336 complete: function () {
337 this.inprogress = false;
338 window.onbeforeunload = null;
339 this.setButtonStyleComplete();
340 },
341
342 setButtonStyleRun: function (mode) {
343
344 this.startOptButton.addClass('wio-running');
345
346 if ("cron" === mode) {
347 this.startOptButton.text(this.i18n.modal_optimization_cron_button_stop);
348 return;
349 }
350
351 this.startOptButton.text(this.i18n.button_stop);
352 },
353
354 setButtonStyleComplete: function () {
355 this.showMessage(this.i18n.optimization_complete);
356 this.startOptButton.text(this.i18n.button_completed);
357 this.startOptButton.removeClass('wio-running');
358 this.startOptButton.prop('disabled', true);
359 },
360
361 setButtonStyleStop: function () {
362 this.startOptButton.removeClass('wio-running');
363 this.startOptButton.text(this.i18n.button_start);
364 },
365
366 showMessage: function (text) {
367 var contanier = $('.wio-page-statistic'),
368 message;
369
370 if (contanier.find('.wrio-statistic-message').length) {
371 message = contanier.find('.wrio-statistic-message');
372 } else {
373 message = $('<div>');
374 message.addClass('wrio-statistic-message');
375 contanier.append(message);
376 }
377
378 message.html(text);
379 },
380
381 throwError: function (error_message) {
382 this.stop();
383
384 var noticeId = $.wbcr_factory_templates_759.app.showNotice(error_message, 'danger');
385
386 setTimeout(function () {
387 $.wbcr_factory_templates_759.app.hideNotice(noticeId);
388 }, 10000);
389 },
390
391 destroyMessages: function () {
392 $('.wio-page-statistic').find('.wrio-statistic-message').empty();
393 },
394
395 sendRequest: function (data) {
396 var self = this;
397
398 if (!this.inprogress) {
399 return;
400 }
401
402 $.post(ajaxurl, data, function (response) {
403 if (!self.inprogress) {
404 return;
405 }
406
407 console.log(response);
408
409 if (!response || !response.success) {
410 console.log('[Error]: Failed ajax request (Try to optimize images).');
411 console.log(response);
412
413 if (response.data && response.data.error_message) {
414 self.throwError(response.data.error_message);
415 }
416
417 return;
418 }
419
420 data.reset_current_errors = 0;
421
422 if (!response.data.end) {
423 $('#wio-total-unoptimized').text(parseInt(response.data.remain));
424 self.showMessage(self.i18n.optimization_inprogress.replace("%s", parseInt(response.data.remain)));
425 self.sendRequest(data);
426 } else {
427 $('#wio-total-unoptimized').text(response.data.remain);
428 self.complete();
429
430 // если мультисайт режим, то не скрываем кнопку запуска оптимизации
431 /*if( $('#wbcr-rio-current-blog').length ) {
432 $('#wio-start-optimization').toggleClass('wio-running');
433 } else {
434 $('#wio-start-optimization').hide();
435 }*/
436 }
437
438 redraw_statistics(response.data.statistic);
439
440 self.updateLog(response.data.last_optimized);
441 }).fail(function (xhr, status, error) {
442 console.log(xhr);
443 console.log(status);
444 console.log(error);
445
446 self.throwError(error);
447 });
448 },
449
450 updateLog: function (new_item_data) {
451 const self = this;
452 const limit = 100;
453 const tableEl = $('.wrio-optimization-progress .wrio-table');
454
455 if (!tableEl.length || !new_item_data) {
456 return;
457 }
458
459 // Handle empty table state
460 if ($('.wrio-table-container-empty').length) {
461 $('.wrio-table-container-empty').addClass('wrio-table-container').removeClass('wrio-table-container-empty');
462 if (tableEl.find('tbody').length) {
463 tableEl.find('tbody').empty();
464 }
465 }
466
467 $.each(new_item_data, function (index, value) {
468 const attachmentId = value.attachment_id || value.id;
469 const existingRow = tableEl.find('[data-attachment-id="' + attachmentId + '"]');
470
471 if (existingRow.length) {
472 // Update existing row data
473 self.updateRowData(existingRow, value);
474 // Move existing row to top of the table
475 existingRow.detach();
476 tableEl.find('tbody').prepend(existingRow);
477 // Re-trigger flash animation
478 existingRow.removeClass('flash');
479 // Force reflow to restart animation
480 existingRow[0].offsetWidth;
481 existingRow.addClass('flash');
482 } else {
483 // Create new row and add to top
484 const trEl = self.buildLogRow(value);
485 tableEl.find('tbody').prepend(trEl);
486 }
487 });
488
489 // Enforce row limit
490 self.enforceRowLimit(tableEl, limit);
491 },
492
493 updateRowData: function (row, data) {
494 // Update optimized size cell
495 row.find('.wrio-optimized-size').text(data.optimized_size);
496
497 // Update WebP size if present
498 if (data.webp_size) {
499 const webpCell = row.find('.wrio-webp-size');
500 if (webpCell.length) {
501 webpCell.text(data.webp_size);
502 }
503 }
504
505 // Update AVIF size if present
506 if (data.avif_size) {
507 const avifCell = row.find('.wrio-avif-size');
508 if (avifCell.length) {
509 avifCell.text(data.avif_size);
510 }
511 }
512
513 // Update total saving
514 row.find('.wrio-total-saving').text(data.total_saving);
515
516 // Update thumbnails count
517 if (data.thumbnails_count !== undefined) {
518 row.find('.wrio-thumbnails-count').text(data.thumbnails_count);
519 }
520
521 // Update error state if needed
522 if (data.type === 'error') {
523 row.addClass('wrio-error');
524 } else {
525 row.removeClass('wrio-error');
526 }
527 },
528
529 buildLogRow: function (value) {
530 const attachmentId = value.attachment_id || value.id;
531 const trEl = $('<tr>')
532 .addClass('flash wrio-table-item')
533 .addClass('wrio-row-id-' + value.id)
534 .attr('data-attachment-id', attachmentId);
535
536 if (value.type === 'error') {
537 trEl.addClass('wrio-error');
538 }
539
540 // Build cells with classes for easy updates
541 const preview = $('<img width="40" height="40" src="' + value.thumbnail_url + '" alt="">');
542 const previewUrl = $('<a href="' + value.url + '" target="_blank">' + value.file_name + '</a>');
543
544 trEl.append($('<td>').append(preview));
545 trEl.append($('<td>').append(previewUrl));
546
547 if (value.type === 'error') {
548 const colspan = this.settings.scope !== 'custom-folders' ? '4' : '3';
549 trEl.append($('<td>').attr('colspan', colspan).text("Error: " + value.error_msg));
550 } else {
551 trEl.append($('<td class="wrio-original-size">').text(value.original_size));
552 trEl.append($('<td class="wrio-optimized-size">').text(value.optimized_size));
553
554 if ("custom-folders" !== this.settings.scope) {
555 trEl.append($('<td class="wrio-thumbnails-count">').text(value.thumbnails_count));
556 }
557
558 trEl.append($('<td class="wrio-total-saving">').text(value.total_saving));
559 }
560
561 return trEl;
562 },
563
564 enforceRowLimit: function (tableEl, limit) {
565 const rows = tableEl.find('tbody tr');
566 if (rows.length > limit) {
567 rows.slice(limit).remove();
568 }
569 }
570
571 };
572
573 $(document).ready(function () {
574 bulkOptimization.init();
575 $('[data-toggle="tooltip"]').tooltip();
576 });
577
578 var ajaxUrl = ajaxurl;
579 var ai_data;
580
581 function redraw_statistics(statistic) {
582 $('#wio-main-chart').attr('data-unoptimized', statistic.unoptimized)
583 .attr('data-optimized', statistic.optimized)
584 .attr('data-errors', statistic.error);
585 $('#wio-total-optimized-attachments').text(statistic.optimized); // optimized
586 $('#wio-original-size').text(bytesToSize(statistic.original_size));
587 $('#wio-optimized-size').text(bytesToSize(statistic.optimized_size));
588 $('#wio-total-saved').text(statistic.save_size_percent + '%');
589 $('#wio-overview-chart-percent').text(statistic.optimized_percent);
590 $('.wio-total-percent').text(statistic.optimized_percent + '%');
591 $('#wio-optimized-bar').css('width', statistic.percent_line + '%');
592
593 $('#wio-unoptimized-num').text(statistic.unoptimized);
594 $('#wio-optimized-num').text(statistic.optimized);
595 $('#wio-error-num').text(statistic.error);
596
597 if(statistic.quota_limit) {
598 $('.wrio-premium-user-balance').text(statistic.quota_limit);
599 }
600
601 if ($('.wrio-statistic-nav li.active').length) {
602 $('.wrio-statistic-nav li.active').find('span.wio-statistic-tab-percent').text(statistic.optimized_percent + '%');
603 }
604
605 window.wio_chart.data.datasets[0].data[0] = statistic.error; // errors
606 window.wio_chart.data.datasets[0].data[1] = statistic.optimized; // optimized
607 window.wio_chart.data.datasets[0].data[2] = statistic.unoptimized; // unoptimized
608 window.wio_chart.update();
609 if ($('#wio-overview-chart-percent').text() == '100%') {
610 window.onbeforeunload = null;
611 }
612 }
613
614 /*$('#wbcr-rio-current-blog').on('change', function() {
615 var self = $(this);
616 $('#wio-start-msg-complete').hide();
617 $(this).attr('disabled', true);
618 $('#wio-start-optimization').attr('disabled', true);
619 var ai_data = {
620 'action': 'wbcr_rio_update_current_blog',
621 'wpnonce': $(this).data('nonce'),
622 'current_blog_id': $(this).find('option:selected').val(),
623 'context': $(this).attr('data-context')
624 };
625 $.post(ajaxUrl, ai_data, function(response) {
626 self.removeAttr('disabled');
627 $('#wio-start-optimization').removeAttr('disabled');
628 redraw_statistics(response.data.statistic);
629 });
630 });*/
631
632 // AVIF upsell banner dismiss handler
633 $(document).on('click', '.wrio-avif-banner-dismiss', function () {
634 var $banner = $(this).closest('.wrio-avif-upsell-banner');
635
636 $.post(ajaxurl, {
637 action: 'wrio_dismiss_avif_banner',
638 nonce: $banner.data('nonce')
639 }, function () {
640 $banner.slideUp(300, function () {
641 $(this).remove();
642 });
643 });
644 });
645
646 });
647