PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.3.1
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.3.1
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / js / wposmush.js

wposmush.js in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.3.1, at js/wposmush.js

1,353 lines 41.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(function($) {
2 WP_Optimize_Smush = WP_Optimize_Smush();
3 });
4
5 var WP_Optimize_Smush = function() {
6
7 var $ = jQuery;
8
9 /**
10 * Variables for smushing.
11 */
12 var smush_nav_tab = $('#wp-optimize-images-nav-tab-smush'),
13 smush_images_grid = $('#wpo_smush_images_grid'),
14 smush_images_optimization_message = $('#smush_info_images'),
15 smush_images_pending_tasks_container = $('#wpo_smush_images_pending_tasks_container'),
16 smush_images_pending_tasks_btn = $('#wpo_smush_images_pending_tasks_button'),
17 smush_images_save_options_btn = $('.wpo-fieldgroup #wpo_smush_images_save_options_button'),
18 smush_images_refresh_btn = $('#wpo_smush_images_refresh'),
19 smush_images_select_all_btn = $('#wpo_smush_images_select_all'),
20 smush_images_select_none_btn = $('#wpo_smush_images_select_none'),
21 smush_images_stats_clear_btn = $('#wpo_smush_clear_stats_btn'),
22 smush_selected_images_btn = $('#wpo_smush_images_btn'),
23 smush_mark_as_compressed_btn = $('#wpo_smush_mark_as_compressed'),
24 smush_single_image_btn = $('.wpo_smush_single_image .button'),
25 smush_single_restore_btn = $('.wpo_restore_single_image .button'),
26 convert_to_webp_btn = $('.wpo_smush.column-wpo_smush .convert-to-webp');
27 smush_mark_all_as_uncompressed_btn = $('#wpo_smush_mark_all_as_uncompressed_btn'),
28 restore_all_compressed_images_btn = $('#wpo_smush_restore_all_compressed_images_btn'),
29 smush_view_logs_btn = $('.wpo_smush_get_logs'),
30 smush_delete_backup_images_btn = $('#wpo_smush_delete_backup_btn'),
31 compression_server_select = $('.compression_server'),
32 reset_webp_serving_method_btn = $('#wpo_reset_webp_serving_method'),
33 smush_images_tab_loaded = false,
34 smush_service_features = [],
35 smush_total_seconds = 0,
36 smush_timer_locked = false,
37 smush_timer_handle = 0,
38 smush_image_list = [],
39 smush_completed = false,
40 smush_mark_all_as_uncompressed = false,
41 smush_affected_images = {},
42 pending_tasks_cancel_btn = $('#wpo_smush_images_pending_tasks_cancel_button'),
43 uncompressed_images_sites_select = $('#wpo_uncompressed_images_sites_select');
44
45 /**
46 * Handle Image Selection
47 */
48
49 smush_images_grid.on('click', '.thumbnail', function (e) {
50 $(this).closest('input[type="checkbox"]').prop('checked', true);
51 });
52
53
54 /**
55 * Handle Shift Ctrl keys state.
56 */
57 var ctrl_shift_on_image_held = false;
58
59
60 smush_images_grid.on('mousedown', '.thumbnail', function (e) {
61 ctrl_shift_on_image_held = e.shiftKey || e.ctrlKey;
62 });
63
64 smush_images_grid.on('mouseup', '.thumbnail', function (e) {
65 ctrl_shift_on_image_held = e.shiftKey || e.ctrlKey;
66 });
67
68 // Resets server rewrite capability
69 reset_webp_serving_method_btn.on('click', function(e) {
70 e.preventDefault();
71 smush_manager_send_command('reset_webp_serving_method', {}, function(resp) {
72 if (!resp.success) {
73 console.log('[Failed] WebP server capability detection');
74 $('#enable_webp_conversion').prop("checked", false);
75 $('#smush-information-modal .smush-information').text(resp.error_message);
76 update_view_modal_message($('#smush-information-modal'))
77 } else {
78 $('#wpo_reset_webp_serving_method_done').show().delay(3000).fadeOut();
79 }
80 });
81 });
82
83 /**
84 * Checks if smush is active and loads images if yes - image tabs change.
85 */
86 $('#wp-optimize-nav-tab-wrapper__wpo_images .nav-tab').on('click', function() {
87 if ($(this).is('#wp-optimize-nav-tab-wpo_images-smush')) {
88 get_info_from_smush_manager();
89 }
90 });
91
92 /**
93 * Checks if smush is active and loads images if yes - main menu change.
94 */
95 $('#wp-optimize-wrap').on('page-change', function(e, params) {
96 if ('wpo_images' == params.page) {
97 if ($('#wp-optimize-nav-tab-wrapper__wpo_images .nav-tab-active').is('#wp-optimize-nav-tab-wpo_images-smush')) {
98 get_info_from_smush_manager();
99 }
100 }
101 });
102
103 if ($('#smush-metabox').length > 0) {
104 update_view_available_options();
105 }
106
107
108 var lastclick = null;
109 smush_images_grid.on('click' , '.wpo_smush_image' , function(e) {
110 var grid_input = $('#wpo_smush_images_grid input[type="checkbox"]');
111 var input = $(this).find('.wpo_smush_image__input');
112 var input_val = (!(input.prop('checked')));
113 if (!lastclick) {
114 $(this).find('.wpo_smush_image__input').prop('checked',input_val);
115 lastclick = input;
116 }
117 if (true === ctrl_shift_on_image_held) {
118 var start = grid_input.index(input);
119 var end = grid_input.index(lastclick);
120 if (start === end) {
121 grid_input.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', input_val);
122 } else {
123 if (true === lastclick.prop('checked')) {
124 grid_input.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', input_val);
125 }
126 }
127 }
128 lastclick = input;
129 update_smush_action_buttons_state();
130 });
131
132 /**
133 * Disable smush actions buttons if no images selected.
134 */
135 function update_smush_action_buttons_state() {
136 var state = (0 == $('input[type="checkbox"]:checked', smush_images_grid).length);
137
138 smush_selected_images_btn.prop('disabled', state);
139 smush_mark_as_compressed_btn.prop('disabled', state);
140 }
141
142 update_smush_action_buttons_state();
143
144 /**
145 * Handles change of smush service provider
146 */
147 compression_server_select.on('change', function(e) {
148 update_view_available_options();
149 save_options();
150 });
151
152 /**
153 * Process bulk smush
154 */
155 smush_selected_images_btn.off().on('click', function() {
156
157 if (0 == $('#wpo_smush_images_grid input[type="checkbox"]:checked').length) {
158 $('#smush-information-modal .smush-information').text(wposmush.please_select_images)
159 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
160 return;
161 }
162
163 $('#smush-information-modal .smush-information').text(wposmush.server_check);
164 update_view_modal_message($('#smush-information-modal'));
165
166 data = { 'server': $("input[name='compression_server']:checked").val() };
167 smush_manager_send_command('check_server_status', data, function(resp) {
168 if (resp.online) {
169 bulk_smush_selected_images();
170 } else {
171 if (resp.error) {
172 error_message = resp.error + '<br>' + wposmush.server_error
173 $('#smush-information-modal .smush-information').html(error_message);
174 } else {
175 $('#smush-information-modal .smush-information').text(wposmush.server_error);
176 }
177 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
178 }
179 });
180 });
181
182 /**
183 * Mark as compressed
184 */
185 smush_mark_as_compressed_btn.off().on('click', function() {
186 if (0 == $('#wpo_smush_images_grid input[type="checkbox"]:checked').length) {
187 $('#smush-information-modal .smush-information').text(wposmush.please_select_compressed_images)
188 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
189 return;
190 }
191
192 var selected_images = [],
193 image;
194
195 $('#wpo_smush_images_grid input:checked').each(function() {
196 image = {
197 'attachment_id':$(this).val(),
198 'blog_id': $(this).data('blog')
199 };
200 selected_images.push(image);
201 });
202
203 update_view_modal_message(wposmush.please_updating_images_info);
204
205 smush_manager_send_command('mark_as_compressed', {selected_images: selected_images}, function(response) {
206 $('#smush-information-modal .smush-information').text(response.summary);
207 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
208 // refresh images list.
209 get_info_from_smush_manager();
210 });
211 });
212
213 /**
214 * Handle "Mark all images as uncompressed" click.
215 */
216 smush_mark_all_as_uncompressed_btn.on('click', function() {
217 if (!confirm(wposmush.mark_all_images_uncompressed)) return;
218
219 var restore_backup = confirm(wposmush.restore_images_from_backup);
220
221 update_view_modal_message($('#smush-information-modal-cancel-btn'));
222 $('#smush-information-modal-cancel-btn .smush-information').text(wposmush.please_wait);
223
224 smush_mark_all_as_uncompressed = true;
225 run_mark_all_as_uncompressed(restore_backup);
226 });
227
228 /**
229 * Handle "Restore all compressed images" click.
230 */
231 restore_all_compressed_images_btn.on('click', function() {
232 if (!confirm(wposmush.restore_all_compressed_images)) return;
233
234 update_view_modal_message($('#smush-information-modal-cancel-btn'));
235 $('#smush-information-modal-cancel-btn .smush-information').text(wposmush.please_wait);
236
237 smush_mark_all_as_uncompressed = true;
238 run_mark_all_as_uncompressed(true, true);
239 });
240
241 /**
242 * Handle "Cancel" button click for mark all images as uncompressed process
243 */
244 $('#smush-information-modal-cancel-btn input[type="button"]').on('click', function() {
245 smush_mark_all_as_uncompressed = false;
246 get_info_from_smush_manager();
247 $.unblockUI();
248 });
249
250 /**
251 * Send command for mark all compressed images as uncompressed.
252 *
253 * @param {bool} restore_backup if set to true then images will restored from backup if possible.
254 */
255 function run_mark_all_as_uncompressed(restore_backup, delete_only_backups_meta) {
256 if (!smush_mark_all_as_uncompressed) return;
257
258 var info = $('#smush-information-modal-cancel-btn .smush-information');
259 smush_manager_send_command('mark_all_as_uncompressed',
260 {
261 restore_backup: restore_backup ? 1 : 0,
262 delete_only_backups_meta: delete_only_backups_meta ? 1 : 0
263 },
264 function(resp) {
265 // if cancel button pressed then exit
266 if (!smush_mark_all_as_uncompressed) return;
267
268 // if we get an error then show it
269 if (resp.hasOwnProperty('error')) {
270 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
271 $('#smush-information-modal .smush-information').text(resp.error);
272 get_info_from_smush_manager();
273 return;
274 }
275
276 // if completed then refresh uncompressed images list and show final message.
277 if (resp.completed) {
278 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
279 $('#smush-information-modal .smush-information').text(resp.message);
280 get_info_from_smush_manager();
281 } else {
282 info.text(resp.message);
283 run_mark_all_as_uncompressed(restore_backup);
284 }
285 }
286 );
287 }
288
289 /**
290 * Refresh image list
291 */
292 smush_images_refresh_btn.off().on('click', function() {
293 get_info_from_smush_manager();
294 });
295
296 /**
297 * Bind select all / select none controls
298 */
299 smush_images_select_all_btn.off().on('click', function() {
300 $('#wpo_smush_images_grid input[type="checkbox"]').prop("checked", true);
301 lastclick = null;
302 update_smush_action_buttons_state();
303 });
304
305
306 /**
307 * Bind select all / select none controls
308 */
309 smush_images_select_none_btn.off().on('click', function() {
310 $('#wpo_smush_images_grid input[type="checkbox"]').prop("checked", false);
311 lastclick = null;
312 update_smush_action_buttons_state();
313 });
314
315 /**
316 * Displays logs in a modal
317 */
318 smush_view_logs_btn.off().on('click', function() {
319 $("#log-panel").text("Please wait, fetching logs.");
320 smush_manager_send_command('get_smush_logs', {}, function(resp) {
321 $.blockUI({
322 message: $("#smush-log-modal"),
323 onOverlayClick: $.unblockUI(),
324 css: {
325 width: '80%',
326 height: '80%',
327 top: '15%',
328 left: '15%'
329 }
330 });
331 $("#log-panel").html("<pre>" + resp + "</pre>");
332 download_link = ajaxurl + "?action=updraft_smush_ajax&subaction=get_smush_logs&nonce=" + wposmush.smush_ajax_nonce;
333 $("#smush-log-modal a").attr('href', download_link);
334 }, false);
335 });
336
337 /**
338 * Handle delete all backup images button click.
339 */
340 smush_delete_backup_images_btn.on('click', function() {
341
342 if (!confirm(wposmush.delete_image_backup_confirm)) return;
343 smush_delete_backup_images_btn.prop('disabled', true);
344 var spinner = $('#wpo_smush_delete_backup_spinner'),
345 done = $('#wpo_smush_delete_backup_done');
346
347 spinner.show();
348
349 smush_manager_send_command('clean_all_backup_images', {}, function() {
350 spinner.hide();
351 smush_delete_backup_images_btn.prop('disabled', false);
352 done.css('display', 'inline-block').delay(3000).fadeOut();
353 });
354 });
355
356 /**
357 * Saves options
358 */
359 smush_images_save_options_btn.off().on('click', function(e) {
360 save_options();
361 });
362
363 /**
364 * Binds clear stats button
365 */
366 smush_images_stats_clear_btn.off().on('click', function(e) {
367 $('#wpo_smush_images_clear_stats_spinner').show().delay(3000).fadeOut();
368
369 smush_manager_send_command('clear_smush_stats', {}, function(resp) {
370 $('#wpo_smush_images_clear_stats_spinner').hide();
371 $('#wpo_smush_images_clear_stats_done').show().delay(3000).fadeOut();
372 });
373 });
374
375 /**
376 * Binds pending tasks button
377 */
378 smush_images_pending_tasks_btn.off().on('click', function(e) {
379 $('#smush-information-modal .smush-information').text(wposmush.server_check);
380 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
381 data = { 'server': $("input[name='compression_server']:checked").val() };
382 smush_manager_send_command('check_server_status', data, function(resp) {
383 if (resp.online) {
384 update_view_bulk_smush_start();
385 smush_manager_send_command('process_pending_images', {}, function(resp) {
386 handle_response_from_smush_manager(resp, update_view_bulk_smush_progress);
387 });
388 } else {
389 if (resp.error) {
390 error_message = resp.error + '<br>' + wposmush.server_error
391 $('#smush-information-modal .smush-information').html(error_message);
392 } else {
393 $('#smush-information-modal .smush-information').text(wposmush.server_error);
394 }
395 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
396 }
397 });
398
399 });
400
401
402 /**
403 * Binds smush cancel button
404 */
405 $('body').on('click', '#wpo_smush_images_pending_tasks_cancel_button', function(e) {
406
407 if (wpoptimize.cancel === pending_tasks_cancel_btn.val()) {
408 pending_tasks_cancel_btn.val(wpoptimize.cancelling);
409 pending_tasks_cancel_btn.prop('disabled', true);
410 }
411 smush_manager_send_command('clear_pending_images', {}, function(resp) {
412 $.unblockUI();
413 if (resp.status) {
414 get_info_from_smush_manager();
415 reset_view_bulk_smush();
416 } else {
417 console.log('Cancelling pending images apparently failed.', resp);
418 }
419 pending_tasks_cancel_btn.val(wpoptimize.cancel);
420 pending_tasks_cancel_btn.prop('disabled', false);
421 });
422 });
423
424 /**
425 * Single image compression
426 */
427 $('body').on('click', '.wpo_smush_single_image .button', function() {
428
429 image = {
430 'attachment_id':$(this).data('id'),
431 'blog_id': $(this).data('blog')
432 };
433
434 if ($('#enable_custom_compression').is(":checked")) {
435 image_quality = $('#custom_compression_slider').val();
436 } else {
437 // The '60' here has to be kept in sync with WP_Optimize::admin_page_wpo_images_smush()
438 image_quality = $('#enable_lossy_compression').is(":checked") ? 60 : 92;
439 }
440 lossy_compression = image_quality < 92 ? true : false;
441
442 smush_options = {
443 'compression_server': $("input[name='compression_server_" + image.attachment_id + "']:checked").val(),
444 'image_quality': image_quality,
445 'lossy_compression': lossy_compression,
446 'back_up_original': $('#smush_backup_' + image.attachment_id).is(":checked"),
447 'preserve_exif': $('#smush_exif_' + image.attachment_id).is(":checked")
448 }
449
450 data = { 'server': $("input[name='compression_server_" + $(this).attr('id').substring(15) + "']:checked").val() };
451 update_view_modal_message(wposmush.server_check);
452 smush_manager_send_command('check_server_status', data, function(resp) {
453 if (resp.online) {
454 smush_selected_image(image, smush_options);
455 } else {
456 if (resp.error) {
457 error_message = resp.error + '<br>' + wposmush.server_error
458
459 update_view_modal_message(error_message, $.unblockUI);
460 } else {
461 update_view_modal_message(wposmush.server_error, $.unblockUI);
462 }
463 }
464 });
465 });
466
467 /**
468 * Single image restore
469 */
470 $('body').on('click', '.wpo_restore_single_image .button', function() {
471 var clicked_image = $(this);
472 blog_id = clicked_image.data('blog');
473 image_id = clicked_image.data('id');
474
475 if (!image_id || !blog_id) return;
476 restore_selected_image(blog_id, image_id);
477 });
478
479 /**
480 * Mark as compressed
481 */
482 $('body').on('click', '.wpo_smush_mark_single_image .button', function() {
483 var image = {
484 'attachment_id':$(this).data('id'),
485 'blog_id': $(this).data('blog')
486 },
487 wrapper = $(this).closest('#smush-metabox-inside-wrapper');
488
489 update_view_modal_message(wposmush.please_updating_images_info);
490
491 smush_manager_send_command('mark_as_compressed', {selected_images: [ image ]}, function(response) {
492 $('#smush-information-modal .smush-information').text(response.summary);
493 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
494
495 if (response.status) {
496 $('.wpo_smush_single_image', wrapper).hide();
497 $('.wpo-toggle-advanced-options', wrapper).removeClass('opened');
498 $('.wpo_smush_mark_single_image', wrapper).hide();
499 $('.wpo_smush_unmark_single_image', wrapper).show();
500 $('.wpo_restore_single_image', wrapper).show();
501 $('#smush_info', wrapper).text(response.info);
502 }
503 });
504 });
505
506 /**
507 * Unmark as uncompressed
508 */
509 $('body').on('click', '.wpo_smush_unmark_single_image .button', function() {
510 var image = {
511 'attachment_id':$(this).data('id'),
512 'blog_id': $(this).data('blog')
513 },
514 wrapper = $(this).closest('#smush-metabox-inside-wrapper');
515
516 update_view_modal_message(wposmush.please_updating_images_info);
517
518 smush_manager_send_command('mark_as_compressed', {selected_images: [ image ], unmark: true}, function(response) {
519 $('#smush-information-modal .smush-information').text(response.summary);
520 update_view_modal_message($('#smush-information-modal'), $.unblockUI);
521
522 if (response.status) {
523 $('.wpo_smush_single_image', wrapper).show();
524 $('.wpo_smush_mark_single_image', wrapper).show();
525 $('.wpo_smush_unmark_single_image', wrapper).hide();
526 $('.wpo_restore_single_image', wrapper).hide();
527 $('#smush_info', wrapper).text('');
528 }
529 });
530 });
531
532 $('body').on('click', '#wpo_smush_details .wpo-collapsible', toggle_smush_details);
533 $('body').on('click', '.column-wpo_smush .wpo-collapsible', toggle_smush_details);
534
535 function toggle_smush_details() {
536 $(this).toggleClass('opened');
537 if ($(this).hasClass('opened')) {
538 $(this).text(wposmush.less);
539 } else {
540 $(this).text(wposmush.more);
541 }
542 }
543
544 $('body').on('click', '#smush-log-modal .close, #smush-information-modal .information-modal-close', function() {
545 $.unblockUI();
546 });
547
548 $('body').on('click', '.wpo_smush_stats_cta_btn, .wpo_smush_get_logs, #smush-complete-summary .close', function() {
549 $.unblockUI();
550 get_info_from_smush_manager();
551 setTimeout(reset_view_bulk_smush, 500);
552 });
553
554 $('body').on('click', '.wpo-toggle-advanced-options', function(e) {
555 e.preventDefault();
556 $(this).toggleClass('opened');
557 });
558
559 $('.wpo-fieldgroup .autosmush input, .wpo-fieldgroup .compression_level, .wpo-fieldgroup .image_options, #smush-show-metabox').on('change', function(e) {
560 save_options();
561 });
562
563 $('body').on('change', '.smush-options.compression_level', function() {
564 if ($('#enable_custom_compression').is(':checked')) {
565 $('.smush-options.custom_compression').show();
566 } else {
567 $('.smush-options.custom_compression').hide();
568 }
569 });
570
571 $('body').on('change', '.smush-advanced input[type="radio"]', function() {
572 update_view_available_options();
573 });
574
575 $('#enable_webp_conversion').on('change', function(e) {
576 // only save when changing the options on the wpo dashboard.
577 if (!$('#wp-optimize-wrap').length) return;
578
579 $('#wpo_smush_images_save_options_spinner').show().delay(3000).fadeOut();
580 $('#enable_webp_conversion').prop("disabled", true);
581
582 var smush_options = get_smush_options();
583
584 smush_manager_send_command('update_webp_options', smush_options, function(resp) {
585 $('#wpo_smush_images_save_options_spinner').hide();
586 if (resp.hasOwnProperty('saved') && resp.saved) {
587 $('#wpo_smush_images_save_options_done').show().delay(3000).fadeOut();
588 smush_images_save_options_btn.hide();
589 } else {
590 $('#enable_webp_conversion').prop("checked", false);
591 smush_images_save_options_btn.show();
592 if ('update_failed_no_working_webp_converter' === resp.error_code) {
593 var html_msg = '<p>'
594 + wposmush.webp_conversion_tool_error
595 + ' <a href="https://getwpo.com/faqs/#How-can-I-get-WebP-conversion-tools-to-work-" target="_blank">'
596 + wposmush.webp_conversion_tool_how_to
597 + '</a></p>';
598 $('#smush-information-modal .smush-information').html(html_msg);
599 } else {
600 $('#smush-information-modal .smush-information').text(resp.error_message);
601 }
602 update_view_modal_message($('#smush-information-modal'));
603 }
604 $('#enable_webp_conversion').prop("disabled", false);
605 });
606 });
607
608 convert_to_webp_btn.on('click', function(e){
609 e.preventDefault();
610 var $link = $(this);
611 data = {
612 'attachment_id': $(this).data('attachment-id')
613 };
614 update_view_modal_message(wposmush.converting_to_webp);
615 smush_manager_send_command('convert_to_webp_format', data, function(response) {
616 if (response.error) {
617 update_view_modal_message(response.error, $.unblockUI);
618 setTimeout(function() {
619 $.unblockUI();
620 }, 2000);
621 } else {
622 update_view_modal_message(response.success, $.unblockUI);
623 setTimeout(function() {
624 $.unblockUI();
625 }, 2000);
626 $link.next().remove();
627 $link.remove();
628 }
629 });
630 });
631
632 /**
633 * Load and show information about uncompressed images.
634 *
635 * @param {Boolean} use_cache Use the request cache
636 *
637 * @return void
638 */
639 function get_info_from_smush_manager(use_cache) {
640
641 var use_cache = (typeof use_cache === 'undefined') ? true : use_cache;
642 var data = { 'use_cache': use_cache };
643
644 smush_images_optimization_message.html('...');
645 smush_images_pending_tasks_container.hide();
646
647 disable_image_optimization_controls(true);
648
649 smush_manager_send_command('get_ui_update', data, function(resp) {
650 handle_response_from_smush_manager(resp, update_view_show_uncompressed_images);
651 update_view_available_options();
652 disable_image_optimization_controls(false);
653 update_smush_action_buttons_state();
654 });
655 }
656
657
658 /**
659 * Get selected images and make an ajax request to compress them.
660 *
661 * @return void
662 */
663 function bulk_smush_selected_images() {
664
665 $('#wpo_smush_images_grid input:checked').each(function() {
666 image = {
667 'attachment_id':$(this).val(),
668 'blog_id': $(this).data('blog')
669 };
670 smush_image_list.push(image);
671 });
672
673 data = {
674 optimization_id: 'smush',
675 selected_images: smush_image_list,
676 smush_options: {
677 'compression_server': $("input[name='compression_server']:checked").val(),
678 'image_quality': $('#image_quality').val(),
679 'lossy_compression': $('#smush-lossy-compression').is(":checked"),
680 'back_up_original': $('#smush-backup-original').is(":checked"),
681 'preserve_exif': $('#smush-preserve-exif').is(":checked")
682 }
683 }
684
685 update_view_bulk_smush_start();
686 smush_manager_send_command('process_bulk_smush', data);
687 }
688
689 /**
690 * Save options in the DB
691 *
692 * @return void
693 */
694 function save_options() {
695 // only save when changing the options on the wpo dashboard.
696 if (!$('#wp-optimize-wrap').length) return;
697
698 $('#wpo_smush_images_save_options_spinner').show().delay(3000).fadeOut();
699
700 var smush_options = get_smush_options();
701
702 smush_manager_send_command('update_smush_options', smush_options, function(resp) {
703 $('#wpo_smush_images_save_options_spinner').hide();
704 if (resp.hasOwnProperty('saved') && resp.saved) {
705 $('#wpo_smush_images_save_options_done').show().delay(3000).fadeOut();
706 smush_images_save_options_btn.hide();
707 } else {
708 $('#wpo_smush_images_save_options_fail').show().delay(3000).fadeOut();
709 smush_images_save_options_btn.show();
710 }
711 });
712 }
713
714 /**
715 * A timer to run for the duration of the bulk smush operation.
716 *
717 * @return void
718 */
719 function smush_timer() {
720 smush_timer_locked = true;
721 smush_total_seconds++;
722 seconds = (smush_total_seconds % 60) + '' < 10 ? '0' + (smush_total_seconds % 60) : (smush_total_seconds % 60);
723 minutes = parseInt(smush_total_seconds / 60) + '' < 10 ? '0' + parseInt(smush_total_seconds / 60) : parseInt(smush_total_seconds / 60);
724
725 $('#smush_stats_timer').text(minutes + ":" + seconds);
726 trigger_events(smush_total_seconds);
727 }
728
729 /**
730 * A timer to run for the duration of the bulk smush operation.
731 *
732 * @param {Number} time_elapsed - time in seconds
733 *
734 * @return void
735 */
736 function trigger_events(time_elapsed) {
737
738 if (0 == time_elapsed % 3) {
739 update_smush_stats();
740 }
741
742 if (0 == time_elapsed % 60) {
743 smush_manager_send_command('process_pending_images', {}, function(resp) {
744 handle_response_from_smush_manager(resp, update_view_bulk_smush_progress);
745 });
746 }
747 }
748
749 /**
750 * Updates the UI with stats
751 *
752 * @param {Boolean} use_cache Use the request cache
753 *
754 * @return void
755 */
756 function update_smush_stats(use_cache) {
757
758 var use_cache = (typeof use_cache === 'undefined') ? true : use_cache;
759
760 data = {
761 update_ui: true,
762 use_cache: false
763 }
764
765 smush_manager_send_command('get_ui_update', data, function(resp) {
766 handle_response_from_smush_manager(resp, update_view_bulk_smush_progress);
767 });
768 }
769
770 /**
771 * Update images optimization tab view with data returned from images optimization.
772 *
773 * @param {Object} data - meta data returned from task manager
774 *
775 * @return void
776 */
777 function update_view_show_uncompressed_images(data) {
778 smush_images_grid.html('');
779
780 if (!data || !data.hasOwnProperty('unsmushed_images')) return;
781
782 var unsmushed_images = data.unsmushed_images,
783 pending_tasks = data.pending_tasks,
784 blog_id = 0;
785
786 if (0 == unsmushed_images.length && 0 == pending_tasks) {
787 smush_images_grid.text(wposmush.all_images_compressed).wrapInner("<div class='wpo-fieldgroup'> </div>");
788 }
789
790 if (0 != pending_tasks) {
791 smush_images_pending_tasks_container.show().find('.red').text(data.pending);
792 }
793
794 if (1 === data.is_multisite) {
795 blog_id = uncompressed_images_sites_select.find(":selected").val();
796 add_unsmushed_images_to_grid(blog_id, data);
797 } else {
798 for (blog_id in data.unsmushed_images) {
799 add_unsmushed_images_to_grid(blog_id, data);
800 }
801 }
802 }
803
804 function sort_unsmushed_images(a, b) {
805 return a.id - b.id;
806 }
807
808 function add_unsmushed_images_to_grid(blog_id, data) {
809 // Used to have upload.php?item= on multisite (using data.is_multisite), and no suffix
810 var admin_url_pre_id = 'post.php?post=',
811 admin_url_post_id = '&action=edit',
812 admin_url = data.admin_urls[blog_id],
813 unsmushed_images = data.unsmushed_images[blog_id];
814
815 if ('undefined' !== typeof unsmushed_images) {
816 unsmushed_images.sort(sort_unsmushed_images);
817 }
818
819 for (i in unsmushed_images) {
820 if (!unsmushed_images.hasOwnProperty(i)) continue;
821 var image = unsmushed_images[i];
822 add_image_to_grid(image, blog_id, admin_url + admin_url_pre_id + image.id + admin_url_post_id);
823 }
824 }
825
826 uncompressed_images_sites_select.on('change', function() {
827 get_info_from_smush_manager();
828 });
829
830 /**
831 * Updates the view when bulk smush starts
832 *
833 * @return void
834 */
835 function update_view_bulk_smush_start() {
836 if (smush_timer_locked) return;
837 update_view_modal_message($('#wpo_smush_images_information_container'));
838
839 service = $('.compression_server input[type="radio"]:checked + label small').text();
840 $('#wpo_smush_images_information_server').html(service);
841
842 // Clear stats
843 $('#smush_stats_pending_images').html("...");
844 $('#smush_stats_completed_images').html("...");
845 $('#smush_stats_bytes_saved').html("...");
846 $('#smush_stats_percent_saved').html("...");
847 $('#smush_stats_timer').html("...");
848
849 smush_timer_handle = window.setInterval(smush_timer, 1000);
850 disable_image_optimization_controls(true);
851 }
852
853 /**
854 * Updates the view with progress related stats
855 *
856 * @param {Object} resp - response from smush manager.
857 *
858 * @return void
859 */
860 function update_view_bulk_smush_progress(resp) {
861
862 // Update stats
863 $('#smush_stats_pending_images').html(resp.pending_tasks);
864 $('#smush_stats_completed_images').html(resp.completed_task_count);
865 $('#smush_stats_bytes_saved').html(resp.bytes_saved);
866 $('#smush_stats_percent_saved').html(resp.percent_saved);
867
868 // Show summary and close the modal
869 if (true == resp.smush_complete) {
870 // Force a delay here to avoid stale data
871 setTimeout(update_view_bulk_smush_complete, 1500);
872 }
873 }
874
875 /**
876 * Updates the view when bulk smush completes
877 *
878 * @return void
879 */
880 function update_view_bulk_smush_complete() {
881
882 data = {
883 update_ui: true,
884 use_cache: false,
885 image_list: smush_image_list
886 }
887
888 smush_manager_send_command('get_ui_update', data, function(resp) {
889
890 summary = resp.session_stats;
891
892 if (0 != resp.completed_task_count) {
893 summary += '<hr>' + resp.summary;
894 }
895
896 show_smush_summary(summary);
897 });
898 }
899
900 /**
901 * Displays a modal with compression data
902 *
903 * @param {string} summary - stats and info
904 *
905 * @return void
906 */
907 function show_smush_summary(summary) {
908
909 if (smush_completed) return;
910
911 $('#summary-message').html(summary);
912 reset_view_bulk_smush();
913 update_view_modal_message($('#smush-complete-summary'));
914 smush_completed = true;
915 }
916
917 /**
918 * Updates the view when bulk smush completes
919 *
920 * @return void
921 */
922 function reset_view_bulk_smush() {
923 // Reset timer and locks
924 smush_total_seconds = 0;
925 smush_timer_locked = false;
926 smush_completed = false;
927 smush_image_list = [];
928 window.clearInterval(smush_timer_handle);
929 disable_image_optimization_controls(false);
930 }
931
932 /**
933 * Append the image to the grid
934 *
935 * @param {Object} image - image data returned from smush manager
936 * @param {int} blog_id - The blog id the image
937 * @param {String} admin_url - The URL to link to for viewing the image
938 *
939 * @return void
940 */
941 function add_image_to_grid(image, blog_id, admin_url) {
942
943 var dom_id = ['wpo_smush_', blog_id, '_', image.id].join('');
944
945 image_html = '<div class="wpo_smush_image" data-filesize="'+image.filesize+'">';
946 image_html += '<a class="button" href="'+admin_url+'" target="_blank"> ' + wposmush.view_image + ' </a>';
947 image_html += '<input id="' + dom_id + '" type="checkbox" data-blog="'+blog_id+ '" class="wpo_smush_image__input" value="'+image.id+'">';
948 image_html += '<label for="' + dom_id + '"></a>';
949 image_html += '<div class="thumbnail">';
950 image_html += '<img class="lazyload" src="'+image.thumb_url+'">';
951 image_html += '</div></label></div>';
952
953 smush_images_grid.append(image_html);
954 }
955
956 /**
957 * Updates UI based on service provider selected
958 *
959 * @param {Object} features - image data returned from smush manager
960 *
961 * @return void
962 */
963 function update_view_available_options() {
964 features = wposmush.features;
965 service = $("input[name^='compression_server']:checked").val();
966
967 for (feature in features[service]) {
968 $('.' + feature).prop('disabled', !features[service][feature]);
969 }
970
971 $('.wpo_smush_image').each(function() {
972 if ($(this).data('filesize') > wposmush.features[service]["max_filesize"]) {
973 $(this).hide();
974 } else {
975 $(this).show();
976 }
977 })
978 }
979
980 /**
981 * Disable smush controls (buttons, checkboxes) in bulk mode
982 *
983 * @param {boolean} disable - if true then disable controls, false - enable.
984 *
985 * @return void
986 */
987 function disable_image_optimization_controls(disable) {
988 $.each([
989 smush_selected_images_btn,
990 smush_images_select_all_btn,
991 smush_images_select_none_btn,
992 smush_images_save_options_btn,
993 smush_images_refresh_btn,
994 smush_images_pending_tasks_btn,
995 smush_mark_as_compressed_btn,
996 ], function(i, el) {
997 el.prop('disabled', disable);
998 });
999
1000 if (disable) {
1001 $('#wpo_smush_images_refresh').hide();
1002 $('.wpo_smush_images_loader').show();
1003 } else {
1004 $('#wpo_smush_images_refresh').show();
1005 $('.wpo_smush_images_loader').hide();
1006 }
1007 }
1008
1009 /**
1010 * Gets selected image and make an ajax request to compress it.
1011 *
1012 * @param {Object} selected_image - { attachment_id: ..., blog_id: ... }
1013 * @param {Array} smush_options - The options to use
1014 *
1015 * @return void
1016 */
1017 function smush_selected_image(selected_image, smush_options) {
1018
1019 // if no selected images then exit.
1020 if (0 == selected_image.length) return;
1021
1022 data = {
1023 selected_image: selected_image,
1024 smush_options: smush_options
1025 }
1026
1027 update_view_modal_message(wposmush.compress_single_image_dialog);
1028 smush_manager_send_command('compress_single_image', data, function(resp) {
1029 handle_response_from_smush_manager(resp, update_view_single_image_complete);
1030 });
1031 }
1032
1033 /**
1034 * Get selected image and make an ajax request to compress it.
1035 *
1036 * @param {Number} blog_id - The blog id
1037 * @param {Number} selected_image - The image id
1038 *
1039 * @return void
1040 */
1041 function restore_selected_image(blog_id, selected_image) {
1042
1043 // if no selected images then exit.
1044 if (0 == selected_image.length) return;
1045
1046 update_view_modal_message(wposmush.please_wait, $.unblockUI);
1047 var data = { 'blog_id': blog_id, 'selected_image': selected_image };
1048 smush_manager_send_command('restore_single_image', data, function(resp) {
1049 handle_response_from_smush_manager(resp, update_view_single_image_complete);
1050 });
1051 }
1052
1053 /**
1054 * Updates the view once a single image is compressed or restored.
1055 *
1056 * @param {Object} resp - response from smush manager.
1057 *
1058 * @return void
1059 */
1060 function update_view_single_image_complete(resp) {
1061
1062 if (resp.hasOwnProperty('success') && resp.success) {
1063 $(".smush-information").text(resp.summary);
1064 update_view_modal_message($("#smush-information-modal"), $.unblockUI);
1065
1066 $('.wpo-toggle-advanced-options.wpo_smush_single_image').removeClass('opened');
1067
1068 update_view_singe_image_compress(resp.operation, resp.summary, resp.restore_possible, resp);
1069
1070 // here we store data from the the response
1071 // this information will be used to show correct UI elements
1072 // when smush metabox will shown again without reloading main page
1073 var blog_id = resp.blog_id || resp.options.blog_id,
1074 image_id = resp.image || resp.options.attachment_id;
1075
1076 if (!smush_affected_images.hasOwnProperty(blog_id)) smush_affected_images[blog_id] = {};
1077 if (!smush_affected_images[blog_id].hasOwnProperty(image_id)) smush_affected_images[blog_id][image_id] = {};
1078
1079 if ('compress' == resp.operation) {
1080 smush_affected_images[blog_id][image_id] = {
1081 operation: resp.operation,
1082 summary: resp.summary,
1083 restore_possible: resp.restore_possible
1084 }
1085 } else {
1086 smush_affected_images[blog_id][image_id] = {
1087 operation: resp.operation
1088 }
1089 }
1090 } else {
1091 $(".smush-information").text(resp.error_message);
1092 update_view_modal_message($("#smush-information-modal"), $.unblockUI);
1093 }
1094 }
1095
1096 /**
1097 * Update metabox view depending on a command response.
1098 *
1099 * @param {string} operation
1100 * @param {string} summary
1101 * @param {boolean} restore_possible
1102 * @param {object} smush_image_data
1103 */
1104 function update_view_singe_image_compress(operation, summary, restore_possible, smush_image_data) {
1105 var wrapper = $("#smush_info").closest('#smush-metabox-inside-wrapper');
1106
1107 if ('compress' == operation) {
1108 $(".wpo_smush_single_image").hide();
1109 $(".wpo_restore_single_image").show();
1110
1111 if (smush_image_data && smush_image_data.hasOwnProperty('sizes-info')) {
1112 $("#smush_info").text(summary);
1113 $("#wpo_smush_details").html(smush_image_data['sizes-info']);
1114 } else {
1115 $("#smush_info").text(summary);
1116 $("#wpo_smush_details").text('').hide();
1117 }
1118
1119 $('.wpo_smush_mark_single_image').hide();
1120
1121 if (restore_possible) {
1122 $(".restore_possible").show();
1123 } else {
1124 $(".restore_possible").hide();
1125 }
1126 } else {
1127 $(".wpo_smush_single_image").show();
1128 $(".wpo_restore_single_image").hide();
1129
1130 $('.wpo_smush_mark_single_image').show();
1131 $('.wpo_smush_unmark_single_image', wrapper).hide();
1132 }
1133 }
1134
1135 /**
1136 * Handle smush metabox load event. This handler is used to restore correct smush metabox view.
1137 */
1138 $(document).on('admin-metabox-smush-loaded', function() {
1139 var image_data = $('.wpo_restore_single_image input[type="button"]').first().data();
1140
1141 if (!image_data) return;
1142
1143 if (smush_affected_images.hasOwnProperty(image_data.blog) && smush_affected_images[image_data.blog].hasOwnProperty(image_data.id)) {
1144 var smush_image_data = smush_affected_images[image_data.blog][image_data.id];
1145
1146 if ('compress' == smush_image_data.operation) {
1147 update_view_singe_image_compress(smush_image_data.operation, smush_image_data.summary, smush_image_data.restore_possible, smush_image_data);
1148 } else {
1149 update_view_singe_image_compress(smush_image_data.operation);
1150 }
1151 }
1152 });
1153
1154 /**
1155 * Display a modal message
1156 *
1157 * @param {string} message The message or element to display
1158 * @param {Function} callback Called when the overlay is clicked
1159 *
1160 * @return void
1161 */
1162 function update_view_modal_message(message, callback) {
1163
1164 $.blockUI({
1165 message: message,
1166 onOverlayClick: callback,
1167 baseZ: 160001,
1168 css: {
1169 width: '400px',
1170 padding: '20px',
1171 cursor: 'pointer'
1172 }
1173 });
1174 }
1175
1176 /**
1177 * Check returned response from the smush manager and call update view callback.
1178 *
1179 * @param {Object} resp - response from smush manager.
1180 * @param {Function} update_view_callback - callback function to update view.
1181 *
1182 * @return void
1183 */
1184 function handle_response_from_smush_manager(resp, update_view_callback) {
1185 if (resp && resp.hasOwnProperty('status') && resp.status) {
1186 if (update_view_callback) update_view_callback(resp);
1187 } else {
1188 alert(wposmush.error_unexpected_response);
1189 console.log(resp);
1190 }
1191 }
1192
1193 /**
1194 * Send an action to the task manager via admin-ajax.php.
1195 *
1196 * @param {string} action The action to send
1197 * @param {[type]} data Data to send
1198 * @param {Function} callback Will be called with the results
1199 * @param {boolean} json_parse JSON parse the results
1200 *
1201 * @return {JSON}
1202 */
1203 function smush_manager_send_command(action, data, callback, json_parse) {
1204
1205 json_parse = ('undefined' === typeof json_parse) ? true : json_parse;
1206 data = $.isEmptyObject(data) ? {'use_cache' : false} : data;
1207
1208 var ajax_data = {
1209 action: 'updraft_smush_ajax',
1210 subaction: action,
1211 nonce: wposmush.smush_ajax_nonce,
1212 data: data
1213 };
1214
1215 var ajax_opts = {
1216 type: 'POST',
1217 url: ajaxurl,
1218 data: ajax_data,
1219 success: function(response) {
1220
1221 if (json_parse) {
1222 try {
1223 var resp = wpo_parse_json(response);
1224 } catch (e) {
1225 console.log("smush_manager_send_command JSON parse error");
1226 console.log(e);
1227 console.log(response);
1228 alert(wposmush.error_unexpected_response);
1229 }
1230 if ('undefined' !== typeof callback) callback(resp);
1231 } else {
1232 if ('undefined' !== typeof callback) callback(response);
1233 }
1234 },
1235 error: function(response, status, error_code) {
1236 console.log("smush_manager_send_command AJAX parse error: "+status+" ("+error_code+")");
1237 if ('undefined' !== typeof callback) {
1238 callback(response);
1239 } else {
1240 console.log(response);
1241 alert(wposmush.error_unexpected_response);
1242 }
1243 },
1244 dataType: 'text'
1245
1246 }
1247
1248 $.ajax(ajax_opts);
1249
1250 };
1251
1252 // Gather smush options
1253 var get_smush_options = function() {
1254 var image_quality = '';
1255 if ($('#enable_custom_compression').is(":checked")) {
1256 image_quality = $('#custom_compression_slider').val();
1257 } else {
1258 // The '90' here has to be kept in sync with WP_Optimize::admin_page_wpo_images_smush()
1259 image_quality = $('#enable_lossy_compression').is(":checked") ? 60 : 92;
1260 }
1261 var lossy_compression = image_quality < 92 ? true : false;
1262
1263 return {
1264 'compression_server': $("input[name='compression_server']:checked").val(),
1265 'image_quality': image_quality,
1266 'lossy_compression': lossy_compression,
1267 'back_up_original': $('#smush-backup-original').is(":checked"),
1268 'back_up_delete_after': $('#smush-backup-delete').is(":checked"),
1269 'back_up_delete_after_days': $('#smush-backup-delete-days').val(),
1270 'preserve_exif': $('#smush-preserve-exif').is(":checked"),
1271 'autosmush': $('#smush-automatically').is(":checked"),
1272 'show_smush_metabox': $('#smush-show-metabox').is(":checked"),
1273 'webp_conversion': $('#enable_webp_conversion').is(":checked")
1274 };
1275 }
1276 wp_optimize.smush_settings = get_smush_options;
1277 } // END WP_Optimize_Smush
1278
1279 /**
1280 * Parse JSON string, including automatically detecting unwanted extra input and skipping it
1281 *
1282 * @param {string|object} json_mix_str - JSON string which need to parse and convert to object
1283 *
1284 * @throws SyntaxError|String (including passing on what JSON.parse may throw) if a parsing error occurs.
1285 *
1286 * @return mixed parsed JSON object. Will only return if parsing is successful (otherwise, will throw)
1287 */
1288 function wpo_parse_json(json_mix_str) {
1289 // When using wp_send_json to return the value, the format is already parsed.
1290 if ('object' === typeof json_mix_str) return json_mix_str;
1291
1292 // Just try it - i.e. the 'default' case where things work (which can include extra whitespace/line-feeds, and simple strings, etc.).
1293 try {
1294 var result = JSON.parse(json_mix_str);
1295 return result;
1296 } catch (e) {
1297 console.log("WPO: Exception when trying to parse JSON (1) - will attempt to fix/re-parse");
1298 console.log(json_mix_str);
1299 }
1300
1301 var json_start_pos = json_mix_str.indexOf('{');
1302 var json_last_pos = json_mix_str.lastIndexOf('}');
1303
1304 // Case where some php notice may be added after or before json string
1305 if (json_start_pos > -1 && json_last_pos > -1) {
1306 var json_str = json_mix_str.slice(json_start_pos, json_last_pos + 1);
1307 try {
1308 var parsed = JSON.parse(json_str);
1309 return parsed;
1310 } catch (e) {
1311 console.log("WPO: Exception when trying to parse JSON (2) - will attempt to fix/re-parse based upon bracket counting");
1312
1313 var cursor = json_start_pos;
1314 var open_count = 0;
1315 var last_character = '';
1316 var inside_string = false;
1317
1318 // Don't mistake this for a real JSON parser. Its aim is to improve the odds in real-world cases seen, not to arrive at universal perfection.
1319 while ((open_count > 0 || cursor == json_start_pos) && cursor <= json_last_pos) {
1320
1321 var current_character = json_mix_str.charAt(cursor);
1322
1323 if (!inside_string && '{' == current_character) {
1324 open_count++;
1325 } else if (!inside_string && '}' == current_character) {
1326 open_count--;
1327 } else if ('"' == current_character && '\\' != last_character) {
1328 inside_string = inside_string ? false : true;
1329 }
1330
1331 last_character = current_character;
1332 cursor++;
1333 }
1334
1335 console.log("Started at cursor="+json_start_pos+", ended at cursor="+cursor+" with result following:");
1336 console.log(json_mix_str.substring(json_start_pos, cursor));
1337
1338 try {
1339 var parsed = JSON.parse(json_mix_str.substring(json_start_pos, cursor));
1340 // console.log('WPO: JSON re-parse successful');
1341 return parsed;
1342 } catch (e) {
1343 // Throw it again, so that our function works just like JSON.parse() in its behaviour.
1344 throw e;
1345 }
1346
1347 }
1348 }
1349
1350 throw "WPO: could not parse the JSON";
1351
1352 }
1353