';
smush_images_grid.append(image_html);
}
/**
* Updates UI based on service provider selected
*
* @param {Object} features - image data returned from smush manager
*
* @return void
*/
function update_view_available_options() {
features = wposmush.features;
service = $("input[name^='compression_server']:checked").val();
for (feature in features[service]) {
$('.' + feature).prop('disabled', !features[service][feature]);
}
$('.wpo_smush_image').each(function() {
if ($(this).data('filesize') > wposmush.features[service]["max_filesize"]) {
$(this).hide();
} else {
$(this).show();
}
})
}
/**
* Disable smush controls (buttons, checkboxes) in bulk mode
*
* @param {boolean} disable - if true then disable controls, false - enable.
*
* @return void
*/
function disable_image_optimization_controls(disable) {
$.each([
smush_selected_images_btn,
smush_images_select_all_btn,
smush_images_select_none_btn,
smush_images_refresh_btn,
smush_images_pending_tasks_btn,
smush_mark_as_compressed_btn,
], function(i, el) {
el.prop('disabled', disable);
});
if (disable) {
$('#wpo_smush_images_refresh').hide();
$('.wpo_smush_images_loader').show();
} else {
$('#wpo_smush_images_refresh').show();
$('.wpo_smush_images_loader').hide();
}
}
/**
* Gets selected image and make an ajax request to compress it.
*
* @param {Object} selected_image - { attachment_id: ..., blog_id: ... }
* @param {Array} smush_options - The options to use
*
* @return void
*/
function smush_selected_image(selected_image, smush_options) {
// if no selected images then exit.
if (0 == selected_image.length) return;
data = {
selected_image: selected_image,
smush_options: smush_options
}
update_view_modal_message(wposmush.compress_single_image_dialog);
smush_manager_send_command('compress_single_image', data, function(resp) {
handle_response_from_smush_manager(resp, update_view_single_image_complete);
});
}
/**
* Get selected image and make an ajax request to compress it.
*
* @param {Number} blog_id - The blog id
* @param {Number} selected_image - The image id
* @param {Function} done_callback - Optional. It will be called when the AJAX command is done, used for multiple calls that need a single `done` action (like bulk_restore)
*
* @return void
*/
function restore_selected_image(blog_id, selected_image, done_callback) {
// if no selected images then exit.
if (0 == selected_image.length) return;
update_view_modal_message(wposmush.please_wait, $.unblockUI);
var data = { 'blog_id': blog_id, 'selected_image': selected_image };
smush_manager_send_command.apply({unique: false}, ['restore_single_image', data, function(resp) {
var done = function(resp_summary_alt) {
if ('undefined' != typeof(resp_summary_alt)) {
resp.summary = resp_summary_alt;
}
handle_response_from_smush_manager(resp, update_view_single_image_complete);
}
if (done_callback instanceof Function) {
done_callback(done);
} else {
done();
}
}]);
}
/**
* Updates the view once a single image is compressed or restored.
*
* @param {Object} resp - response from smush manager.
*
* @return void
*/
function update_view_single_image_complete(resp) {
if (resp.hasOwnProperty('success') && resp.success) {
$(".smush-information").text(resp.summary);
update_view_modal_message($("#smush-information-modal"), $.unblockUI);
$('.wpo-toggle-advanced-options.wpo_smush_single_image').removeClass('opened');
update_view_singe_image_compress(resp.operation, resp.summary, resp.restore_possible, resp);
// here we store data from the the response
// this information will be used to show correct UI elements
// when smush metabox will shown again without reloading main page
var blog_id = resp.blog_id || resp.options.blog_id,
image_id = resp.image || resp.options.attachment_id;
if (!smush_affected_images.hasOwnProperty(blog_id)) smush_affected_images[blog_id] = {};
if (!smush_affected_images[blog_id].hasOwnProperty(image_id)) smush_affected_images[blog_id][image_id] = {};
if ('compress' == resp.operation) {
smush_affected_images[blog_id][image_id] = {
operation: resp.operation,
summary: resp.summary,
restore_possible: resp.restore_possible
}
} else {
if (image_id) {
update_media_library_wp_optimize_column(image_id);
reset_bulk_actions_dropdown();
}
smush_affected_images[blog_id][image_id] = {
operation: resp.operation
}
}
} else {
$(".smush-information").text(resp.error_message);
update_view_modal_message($("#smush-information-modal"), $.unblockUI);
}
}
/**
* Update metabox view depending on a command response.
*
* @param {string} operation
* @param {string} summary
* @param {boolean} restore_possible
* @param {object} smush_image_data
*/
function update_view_singe_image_compress(operation, summary, restore_possible, smush_image_data) {
var wrapper = $("#smush_info").closest('#smush-metabox-inside-wrapper');
if ('compress' == operation) {
$(".wpo_smush_single_image").hide();
$(".wpo_restore_single_image").show();
if (smush_image_data && smush_image_data.hasOwnProperty('sizes-info')) {
$("#smush_info").text(summary);
$("#wpo_smush_details").html(smush_image_data['sizes-info']);
} else {
$("#smush_info").text(summary);
$("#wpo_smush_details").text('').hide();
}
$('.wpo_smush_mark_single_image').hide();
if (restore_possible) {
$(".restore_possible").show();
} else {
$(".restore_possible").hide();
}
} else {
$(".wpo_smush_single_image").show();
$(".wpo_restore_single_image").hide();
$('.wpo_smush_mark_single_image').show();
$('.wpo_smush_unmark_single_image', wrapper).hide();
}
}
/**
* Handle smush metabox load event. This handler is used to restore correct smush metabox view.
*/
$(document).on('admin-metabox-smush-loaded', function() {
var image_data = $('.wpo_restore_single_image input[type="button"]').first().data();
if (!image_data) return;
if (smush_affected_images.hasOwnProperty(image_data.blog) && smush_affected_images[image_data.blog].hasOwnProperty(image_data.id)) {
var smush_image_data = smush_affected_images[image_data.blog][image_data.id];
if ('compress' == smush_image_data.operation) {
update_view_singe_image_compress(smush_image_data.operation, smush_image_data.summary, smush_image_data.restore_possible, smush_image_data);
} else {
update_view_singe_image_compress(smush_image_data.operation);
}
}
});
/**
* Display a modal message
*
* @param {string} message The message or element to display
* @param {Function} callback Called when the overlay is clicked
*
* @return void
*/
function update_view_modal_message(message, callback) {
$.blockUI({
message: message,
onOverlayClick: callback,
baseZ: 160001,
css: {
width: '400px',
padding: '20px',
cursor: 'pointer'
}
});
}
/**
* Check returned response from the smush manager and call update view callback.
*
* @param {Object} resp - response from smush manager.
* @param {Function} update_view_callback - callback function to update view.
*
* @return void
*/
function handle_response_from_smush_manager(resp, update_view_callback) {
if (resp && resp.hasOwnProperty('status') && resp.status) {
if (update_view_callback) update_view_callback(resp);
} else {
alert(wposmush.error_unexpected_response);
console.log(resp);
}
}
/**
* Retrieves the selected images from the media library.
*
* @return {jQuery} - The selected images as a jQuery object.
*/
function get_media_library_selected_images() {
return $('input[name="media[]"]:checked');
}
/**
* Retrieves the list of selected images from the media library.
*
* @return {Array.} The list of selected image IDs.
*/
function get_media_library_selected_images_list() {
var selected_images_list = [];
var $selected_images = get_media_library_selected_images();
$selected_images.each(function(index, element) {
selected_images_list.push(parseInt(element.value));
});
return selected_images_list;
}
/**
* Updates the media library WP Optimize column for a specified image.
*
* @param {number} image_id - The ID of the image to update the column for.
*/
function update_media_library_wp_optimize_column(image_id) {
var admin_url = ajaxurl.replace('/admin-ajax.php', '/');
admin_url += 'post.php?post=' + image_id + '&action=edit';
$('#post-' + image_id + ' .column-wpo_smush').html('' + wposmush.compress + ' ');
}
/**
* Resets the bulk action dropdown by setting its value to "-1" and unchecking all the selected checkboxes.
*
* @returns {void}
*/
function reset_bulk_actions_dropdown() {
$('#bulk-action-selector-top, #bulk-action-selector-bottom').val("-1");
$('input[name="media[]"]:checked, #cb-select-all-1, #cb-select-all-2').prop('checked', false);
}
/**
* Send an action to the task manager via admin-ajax.php.
*
* @param {string} action The action to send
* @param {[type]} data Data to send
* @param {Function} callback Will be called with the results
* @param {boolean} json_parse JSON parse the results
*
* @return {JSON}
*/
function smush_manager_send_command(action, data, callback, json_parse) {
json_parse = ('undefined' === typeof json_parse) ? true : json_parse;
data = $.isEmptyObject(data) ? {'use_cache' : false} : data;
(function(single_callback, _keep, _unique) {
heartbeat_agents.push(heartbeat.add_agent({
_wait: false,
_keep: _keep,
_unique: _unique,
command: 'updraft_smush_ajax',
command_data: {data: data, subaction: action},
callback: function(response) {
if (json_parse) {
try {
var resp = wpo_parse_json(response);
} catch (e) {
console.log("smush_manager_send_command JSON parse error");
console.log(e);
console.log(response);
alert(wposmush.error_unexpected_response);
}
if ('undefined' !== typeof single_callback) single_callback(resp);
} else {
if ('undefined' !== typeof single_callback) single_callback(response);
}
}
}));
})(callback, this.keep, this.unique);
};
// Attach heartbeat API events
heartbeat.setup();
// Gather smush options
var get_smush_options = function() {
var image_quality = '';
if ($('#enable_custom_compression').is(":checked")) {
image_quality = $('#custom_compression_slider').val();
} else {
// The '90' here has to be kept in sync with WP_Optimize::admin_page_wpo_images_smush()
image_quality = $('#enable_lossy_compression').is(":checked") ? 60 : 92;
}
var lossy_compression = image_quality < 92 ? true : false;
return {
'compression_server': $("input[name='compression_server']:checked").val(),
'image_quality': image_quality,
'lossy_compression': lossy_compression,
'back_up_original': $('#smush-backup-original').is(":checked"),
'back_up_delete_after': $('#smush-backup-delete').is(":checked"),
'back_up_delete_after_days': $('#smush-backup-delete-days').val(),
'preserve_exif': $('#smush-preserve-exif').is(":checked"),
'autosmush': $('#smush-automatically').is(":checked"),
'show_smush_metabox': $('#smush-show-metabox').is(":checked"),
'webp_conversion': $('#enable_webp_conversion').is(":checked")
};
}
wp_optimize.smush_settings = get_smush_options;
} // END WP_Optimize_Smush
/**
* Parse JSON string, including automatically detecting unwanted extra input and skipping it
*
* @param {string|object} json_mix_str - JSON string which need to parse and convert to object
*
* @throws SyntaxError|String (including passing on what JSON.parse may throw) if a parsing error occurs.
*
* @return mixed parsed JSON object. Will only return if parsing is successful (otherwise, will throw)
*/
function wpo_parse_json(json_mix_str) {
// When using wp_send_json to return the value, the format is already parsed.
if ('object' === typeof json_mix_str) return json_mix_str;
// Just try it - i.e. the 'default' case where things work (which can include extra whitespace/line-feeds, and simple strings, etc.).
try {
var result = JSON.parse(json_mix_str);
return result;
} catch (e) {
console.log("WPO: Exception when trying to parse JSON (1) - will attempt to fix/re-parse");
console.log(json_mix_str);
}
var json_start_pos = json_mix_str.indexOf('{');
var json_last_pos = json_mix_str.lastIndexOf('}');
// Case where some php notice may be added after or before json string
if (json_start_pos > -1 && json_last_pos > -1) {
var json_str = json_mix_str.slice(json_start_pos, json_last_pos + 1);
try {
var parsed = JSON.parse(json_str);
return parsed;
} catch (e) {
console.log("WPO: Exception when trying to parse JSON (2) - will attempt to fix/re-parse based upon bracket counting");
var cursor = json_start_pos;
var open_count = 0;
var last_character = '';
var inside_string = false;
// 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.
while ((open_count > 0 || cursor == json_start_pos) && cursor <= json_last_pos) {
var current_character = json_mix_str.charAt(cursor);
if (!inside_string && '{' == current_character) {
open_count++;
} else if (!inside_string && '}' == current_character) {
open_count--;
} else if ('"' == current_character && '\\' != last_character) {
inside_string = inside_string ? false : true;
}
last_character = current_character;
cursor++;
}
console.log("Started at cursor="+json_start_pos+", ended at cursor="+cursor+" with result following:");
console.log(json_mix_str.substring(json_start_pos, cursor));
try {
var parsed = JSON.parse(json_mix_str.substring(json_start_pos, cursor));
// console.log('WPO: JSON re-parse successful');
return parsed;
} catch (e) {
// Throw it again, so that our function works just like JSON.parse() in its behaviour.
throw e;
}
}
}
throw "WPO: could not parse the JSON";
}