| 1 |
// Utils |
| 2 |
|
| 3 |
var WP_SIR_UTIL = { |
| 4 |
setCookie: function (cname, cvalue, exdays) { |
| 5 |
var d = new Date(); |
| 6 |
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); |
| 7 |
var expires = "expires=" + d.toUTCString(); |
| 8 |
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; |
| 9 |
} |
| 10 |
}; |
| 11 |
|
| 12 |
(function ($) { |
| 13 |
'use strict'; |
| 14 |
|
| 15 |
// ELEMENTS |
| 16 |
var $colorPicker = $('#wpSirColorPicker'); |
| 17 |
var $compressImageSlider = $('.wpSirSlider'); |
| 18 |
|
| 19 |
// ------------------------------------------------------------------------------------------ |
| 20 |
// INITILIAZE COLOR PICKER |
| 21 |
// ------------------------------------------------------------------------------------------ |
| 22 |
|
| 23 |
$colorPicker.wpColorPicker(); |
| 24 |
|
| 25 |
// ------------------------------------------------------------------------------------------ |
| 26 |
// INITILIAZE COMPRESSION SLIDER. |
| 27 |
// ------------------------------------------------------------------------------------------ |
| 28 |
|
| 29 |
$compressImageSlider.each(function () { |
| 30 |
var handle = $(this).find('.wpSirSliderHandler'); |
| 31 |
var inputElement = $('.' + $(this).data('input')); |
| 32 |
$(this).slider({ |
| 33 |
create: function () { |
| 34 |
$(this).slider('value', inputElement.val()); |
| 35 |
handle.text($(this).slider('value') + '%'); |
| 36 |
}, |
| 37 |
slide: function (event, ui) { |
| 38 |
handle.text(ui.value + '%'); |
| 39 |
inputElement.val(ui.value); |
| 40 |
}, |
| 41 |
change: function (event, ui) { |
| 42 |
handle.text(ui.value + '%'); |
| 43 |
}, |
| 44 |
}); |
| 45 |
}); |
| 46 |
|
| 47 |
// we'll wait until the box is rendered, so we can move it to the top. |
| 48 |
var wpsirLoadIntervalId = setInterval(() => { |
| 49 |
if ($('.wpsirProcessMediaLibraryImageWraper').length) { |
| 50 |
clearInterval(wpsirLoadIntervalId); |
| 51 |
|
| 52 |
$('.wpsirProcessMediaLibraryImageWraper') |
| 53 |
.insertBefore($('#wp-media-grid > .media-frame')); |
| 54 |
|
| 55 |
handleProcessMediaLibraryChange($('#processMediaLibraryImage')); |
| 56 |
|
| 57 |
$(document).on('change', '#processMediaLibraryImage', function () { |
| 58 |
handleProcessMediaLibraryChange($(this)); |
| 59 |
}); |
| 60 |
|
| 61 |
} |
| 62 |
}, 100); |
| 63 |
|
| 64 |
|
| 65 |
/** |
| 66 |
* Allow user to decide whether to process image being uploaded. |
| 67 |
* We'll place a checkbox input where we cannot determine image attachment parent |
| 68 |
* under "Media > Library" and "Media > Add" new pages. |
| 69 |
*/ |
| 70 |
|
| 71 |
|
| 72 |
function handleProcessMediaLibraryChange($input) { |
| 73 |
var isProcessable = $input.is(':checked'); |
| 74 |
|
| 75 |
WP_SIR_UTIL.setCookie(wp_sir_object.process_ml_upload_cookie, isProcessable.toString(), 365); |
| 76 |
// Normal HTML uploader. |
| 77 |
if ($('#html-upload-ui').length) { |
| 78 |
var $htmlProcessableInput = $('input[name="_processable_image"]'); |
| 79 |
|
| 80 |
if ($htmlProcessableInput.length === 0) { |
| 81 |
$('#html-upload-ui').append( |
| 82 |
'<input type="hidden" name="_processable_image" >' |
| 83 |
); |
| 84 |
$htmlProcessableInput = $($htmlProcessableInput.selector); |
| 85 |
} |
| 86 |
$htmlProcessableInput.val(isProcessable); |
| 87 |
} |
| 88 |
|
| 89 |
// Drag-and-drop uploader box. |
| 90 |
if ( |
| 91 |
typeof wpUploaderInit === 'object' && |
| 92 |
wpUploaderInit.hasOwnProperty('multipart_params') |
| 93 |
) { |
| 94 |
wpUploaderInit.multipart_params._processable_image = isProcessable; |
| 95 |
} |
| 96 |
|
| 97 |
// Media library modal. |
| 98 |
if ( |
| 99 |
wp.media && |
| 100 |
wp.media.frame && |
| 101 |
wp.media.frame.uploader && |
| 102 |
wp.media.frame.uploader.uploader |
| 103 |
) { |
| 104 |
wp.media.frame.uploader.uploader.param('_processable_image', isProcessable); |
| 105 |
} |
| 106 |
} |
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
// Reset "Image sizes" to default ones. |
| 111 |
$(document).on('click', '#wpsirResetDefaultSizes', function () { |
| 112 |
var preselectedSizes = $('#wp-sir-sizes-selector').data('defaults').split(','); |
| 113 |
$('.wpSirSelectSize').each(function () { |
| 114 |
if (preselectedSizes.indexOf($(this).val()) >= 0) { |
| 115 |
$(this).prop('checked', true).change(); |
| 116 |
} else { |
| 117 |
$(this).prop('checked', false).change(); |
| 118 |
} |
| 119 |
}); |
| 120 |
}); |
| 121 |
|
| 122 |
|
| 123 |
// Add filter to Media Library (grid view) |
| 124 |
|
| 125 |
if (typeof sir_vars != 'undefined') { |
| 126 |
var SIR_MediaLibraryTaxonomyFilter = wp.media.view.AttachmentFilters.extend({ |
| 127 |
id: 'media-attachment-sir-filter', |
| 128 |
createFilters() { |
| 129 |
this.filters = { |
| 130 |
all: { |
| 131 |
text: sir_vars.filter_strings.all, |
| 132 |
props: { _filter: 'all' }, |
| 133 |
priority: 10, |
| 134 |
}, |
| 135 |
processed: { |
| 136 |
text: sir_vars.filter_strings.processed, |
| 137 |
props: { _filter: 'processed' }, |
| 138 |
priority: 20, |
| 139 |
}, |
| 140 |
unprocessed: { |
| 141 |
text: sir_vars.filter_strings.unprocessed, |
| 142 |
props: { _filter: 'unprocessed' }, |
| 143 |
priority: 30, |
| 144 |
}, |
| 145 |
}; |
| 146 |
}, |
| 147 |
}); |
| 148 |
|
| 149 |
var SIR_AttachmentsBrowser = wp.media.view.AttachmentsBrowser; |
| 150 |
wp.media.view.AttachmentsBrowser = wp.media.view.AttachmentsBrowser.extend({ |
| 151 |
createToolbar() { |
| 152 |
// Make sure to load the original toolbar |
| 153 |
SIR_AttachmentsBrowser.prototype.createToolbar.call(this); |
| 154 |
this.toolbar.set( |
| 155 |
'SIR_MediaLibraryTaxonomyFilter', |
| 156 |
new SIR_MediaLibraryTaxonomyFilter({ |
| 157 |
controller: this.controller, |
| 158 |
model: this.collection.props, |
| 159 |
priority: -75, |
| 160 |
}).render() |
| 161 |
); |
| 162 |
}, |
| 163 |
}); |
| 164 |
|
| 165 |
} |
| 166 |
|
| 167 |
// Handle the "Clear" button display. |
| 168 |
$('#wp-sir-clear-bg-color').on('click', function (e) { |
| 169 |
$colorPicker.find('.wp-picker-clear').click(); |
| 170 |
$colorPicker.val('').trigger('change'); |
| 171 |
$colorPicker.find('.wp-color-result').css({ 'background-color': '' }); |
| 172 |
e.preventDefault(); |
| 173 |
e.stopPropagation(); |
| 174 |
$(this).hide(); |
| 175 |
}); |
| 176 |
|
| 177 |
if (!$colorPicker.val()) { |
| 178 |
$('#wp-sir-clear-bg-color').hide(); |
| 179 |
} |
| 180 |
|
| 181 |
$('.wp-picker-container').on('click', function () { |
| 182 |
if ($(this).hasClass('wp-picker-active')) { |
| 183 |
$('#wp-sir-clear-bg-color').hide(); |
| 184 |
} else if ($colorPicker.val()) { |
| 185 |
$('#wp-sir-clear-bg-color').show(); |
| 186 |
} |
| 187 |
}); |
| 188 |
|
| 189 |
|
| 190 |
$(document).on('click', function (e) { |
| 191 |
if ($colorPicker.val()) { |
| 192 |
$('#wp-sir-clear-bg-color').show(); |
| 193 |
} |
| 194 |
}); |
| 195 |
|
| 196 |
|
| 197 |
$(document).on('change', '.wpSirSelectSize', function () { |
| 198 |
|
| 199 |
$(this).closest('tr').find('input[type="number"]').prop('disabled', !$(this).is(':checked')); |
| 200 |
$(this).closest('tr').find('.wp-sir-fit-mode').prop('disabled', !$(this).is(':checked')); |
| 201 |
if ($(this).closest('tr').find('.wp-sir-fit-mode').is(':checked')) { |
| 202 |
$(this).closest('tr').find('input[type="number"]').prop('disabled', true); |
| 203 |
} |
| 204 |
var isAllSizesSelected = $('.wpSirSelectSize:checked').length === $('.wpSirSelectSize').length; |
| 205 |
$('#wp-sir-toggle-all-sizes').prop('checked', isAllSizesSelected); |
| 206 |
|
| 207 |
// Check if current selection matches defaults |
| 208 |
const defaultSizes = $('#wp-sir-sizes-selector').data('defaults').split(','); |
| 209 |
const currentSizes = $('.wpSirSelectSize:checked').map(function() { |
| 210 |
return $(this).val(); |
| 211 |
}).get(); |
| 212 |
|
| 213 |
const hasChanges = defaultSizes.length !== currentSizes.length || |
| 214 |
defaultSizes.some(size => !currentSizes.includes(size)) || |
| 215 |
currentSizes.some(size => !defaultSizes.includes(size)); |
| 216 |
|
| 217 |
// Show/hide reset button based on changes |
| 218 |
$('#wpsirResetDefaultSizes').toggle(hasChanges); |
| 219 |
}); |
| 220 |
|
| 221 |
$('.wpSirSelectSize').each(function () { |
| 222 |
|
| 223 |
$(this).closest('tr').find('input[type=number]').prop('disabled', !$(this).is(':checked')).change(); |
| 224 |
$(this).closest('tr').find('.wp-sir-fit-mode').prop('disabled', !$(this).is(':checked')).change(); |
| 225 |
$(this).closest('tr').find('.wp-sir-fit-mode').each(function () { |
| 226 |
if ($(this).is(':checked')) { |
| 227 |
$(this).closest('tr').find('input[type=number]').prop('disabled', true); |
| 228 |
} |
| 229 |
}); |
| 230 |
}); |
| 231 |
|
| 232 |
$('#wp-sir-toggle-all-sizes').on('change', function () { |
| 233 |
var $toggle = $(this); |
| 234 |
$('.wpSirSelectSize').each(function(){ |
| 235 |
if(! $(this).is(':disabled')){ |
| 236 |
$(this).prop('checked', $toggle.is(':checked')); |
| 237 |
|
| 238 |
} |
| 239 |
}); |
| 240 |
$('.wpSirSelectSize').change(); |
| 241 |
}); |
| 242 |
|
| 243 |
$('.wp-sir-fit-mode').on('change', function () { |
| 244 |
if ($(this).is(':checked') ) { |
| 245 |
$(this).closest('tr').find('.wp-sir-custom-dimensions').find('input').prop('disabled', true); |
| 246 |
} else { |
| 247 |
$(this).closest('tr').find('.wp-sir-custom-dimensions').find('input').prop('disabled', false); |
| 248 |
} |
| 249 |
}); |
| 250 |
|
| 251 |
|
| 252 |
$(document).on('click', '#wp-sir-open-media-uploader', function (e) { |
| 253 |
var frame; |
| 254 |
|
| 255 |
if (frame) { |
| 256 |
frame.open(); |
| 257 |
return; |
| 258 |
} |
| 259 |
|
| 260 |
frame = wp.media({ |
| 261 |
title: 'Select or Upload Watermark image', |
| 262 |
multiple: false, |
| 263 |
}); |
| 264 |
|
| 265 |
frame.on('select', function () { |
| 266 |
var attachment = frame.state().get('selection').first().toJSON(); |
| 267 |
var $watermarkImageInput = $('input[name="wp_sir_settings[watermark_image]"]'); |
| 268 |
$watermarkImageInput.val(attachment.id); |
| 269 |
$watermarkImageInput.data('size', { w: attachment.width, h: attachment.height }); |
| 270 |
|
| 271 |
var $watermarkPreview = $('.wp-sir-watermark-preview-container'); |
| 272 |
|
| 273 |
if ($watermarkPreview.find('img').length) { |
| 274 |
$watermarkPreview.find('img').attr('src', attachment.url); |
| 275 |
} else { |
| 276 |
$watermarkPreview.append('<img src="' + attachment.url + '"/>'); |
| 277 |
$watermarkPreview.find('img').css('position', 'absolute'); |
| 278 |
} |
| 279 |
|
| 280 |
var previewSize = { w: $watermarkPreview.width(), h: $watermarkPreview.height() }; |
| 281 |
var h,w; |
| 282 |
var size = +$('.wp-sir-watermark-size').val(); |
| 283 |
|
| 284 |
if (attachment.width >= attachment.height) { |
| 285 |
w = previewSize.w * size /100; |
| 286 |
if (w >= previewSize.w) { |
| 287 |
w = previewSize.w; |
| 288 |
} |
| 289 |
h = attachment.height * w / attachment.width; |
| 290 |
} else { |
| 291 |
h = previewSize.h * size / 100; |
| 292 |
if (h >= previewSize.h) { |
| 293 |
h = previewSize.h |
| 294 |
} |
| 295 |
w = attachment.width * h / attachment.height; |
| 296 |
} |
| 297 |
|
| 298 |
if(w >= previewSize.w) { |
| 299 |
w = previewSize.w; |
| 300 |
h = attachment.height * w / attachment.width; |
| 301 |
} |
| 302 |
|
| 303 |
if(h >= previewSize.h) { |
| 304 |
h = previewSize.h; |
| 305 |
w = attachment.width * h / attachment.height; |
| 306 |
} |
| 307 |
|
| 308 |
$watermarkPreview.find('img').css({ width: w + 'px', height: h + 'px' }); |
| 309 |
$watermarkPreview.find('img').css({ opacity: +$('.wp-sir-watermark-opacity').val()/100 }); |
| 310 |
$('#wp-sir-watermark-position').trigger('change'); |
| 311 |
}); |
| 312 |
|
| 313 |
frame.open(); |
| 314 |
|
| 315 |
}); |
| 316 |
|
| 317 |
|
| 318 |
// Handle watermark slider change. |
| 319 |
$('.wp-sir-watermark-size').on('input', function() { |
| 320 |
var $slider = $(this); |
| 321 |
var $previewImageContainer = $('.wp-sir-watermark-preview-container'); |
| 322 |
var $watermark = $previewImageContainer.find('img'); |
| 323 |
var value = $slider.val(); |
| 324 |
|
| 325 |
// Update the size input value |
| 326 |
|
| 327 |
if (!$watermark.length) { |
| 328 |
return; |
| 329 |
} |
| 330 |
|
| 331 |
var previewSize = { |
| 332 |
w: $previewImageContainer.width(), |
| 333 |
h: $previewImageContainer.height() |
| 334 |
}; |
| 335 |
var watermarkSize = { |
| 336 |
w: $watermark.width(), |
| 337 |
h: $watermark.height() |
| 338 |
}; |
| 339 |
|
| 340 |
var watermarkNewWidth, watermarkNewHeight; |
| 341 |
|
| 342 |
if (watermarkSize.w >= watermarkSize.h) { |
| 343 |
watermarkNewWidth = previewSize.w * value / 100; |
| 344 |
if (watermarkNewWidth >= previewSize.w) { |
| 345 |
watermarkNewWidth = previewSize.w; |
| 346 |
} |
| 347 |
watermarkNewHeight = watermarkSize.h * watermarkNewWidth / watermarkSize.w; |
| 348 |
} else { |
| 349 |
watermarkNewHeight = previewSize.h * value / 100; |
| 350 |
if (watermarkNewHeight >= previewSize.h) { |
| 351 |
watermarkNewHeight = previewSize.h; |
| 352 |
} |
| 353 |
watermarkNewWidth = watermarkSize.w * watermarkNewHeight / watermarkSize.h; |
| 354 |
} |
| 355 |
|
| 356 |
if (watermarkNewWidth >= previewSize.w) { |
| 357 |
watermarkNewWidth = previewSize.w; |
| 358 |
watermarkNewHeight = watermarkSize.h * watermarkNewWidth / watermarkSize.w; |
| 359 |
} |
| 360 |
|
| 361 |
if (watermarkNewHeight >= previewSize.h) { |
| 362 |
watermarkNewHeight = previewSize.h; |
| 363 |
watermarkNewWidth = watermarkSize.w * watermarkNewHeight / watermarkSize.h; |
| 364 |
} |
| 365 |
|
| 366 |
$watermark.css({ |
| 367 |
width: watermarkNewWidth + 'px', |
| 368 |
height: watermarkNewHeight + 'px' |
| 369 |
}); |
| 370 |
|
| 371 |
}); |
| 372 |
|
| 373 |
$(document).on('change', '#wp-sir-watermark-position', function () { |
| 374 |
setWatermarkPosition($(this)); |
| 375 |
}); |
| 376 |
|
| 377 |
|
| 378 |
$('.wp-sir-watermark-opacity').on('input', function() { |
| 379 |
var $slider = $(this); |
| 380 |
var $opacityInput = $('.' + $slider.data('input')); |
| 381 |
var value = $slider.val(); |
| 382 |
var $watermark = $('.wp-sir-watermark-preview-container').find('img'); |
| 383 |
|
| 384 |
// Update the opacity input value and display |
| 385 |
$opacityInput.val(value); |
| 386 |
$('.wp-sir-watermark-opacity-slider-handler').text(value + '%'); |
| 387 |
|
| 388 |
// Update watermark opacity if it exists |
| 389 |
if ($watermark.length) { |
| 390 |
$watermark.css({ opacity: value / 100 }); |
| 391 |
} |
| 392 |
}); |
| 393 |
|
| 394 |
// Initialize opacity on page load |
| 395 |
$(document).ready(function() { |
| 396 |
$('.wp-sir-watermark-opacity').each(function() { |
| 397 |
$(this).trigger('input'); |
| 398 |
}); |
| 399 |
}); |
| 400 |
|
| 401 |
function setWatermarkPosition($element) { |
| 402 |
var $img = $('.wp-sir-watermark-preview-container').find('img'); |
| 403 |
var $offset_y = $('#wp-sir-watermark-offset-y'); |
| 404 |
var $offset_x = $('#wp-sir-watermark-offset-x'); |
| 405 |
var offset_x = parseInt($offset_x.val()) || 0; |
| 406 |
var offset_y = parseInt($offset_y.val()) || 0; |
| 407 |
|
| 408 |
// Reset any previous positioning |
| 409 |
$img.css({ |
| 410 |
'top': '', |
| 411 |
'left': '', |
| 412 |
'right': '', |
| 413 |
'bottom': '', |
| 414 |
'transform': '' |
| 415 |
}); |
| 416 |
|
| 417 |
// Enable both inputs by default |
| 418 |
$offset_x.prop('disabled', false); |
| 419 |
$offset_y.prop('disabled', false); |
| 420 |
|
| 421 |
switch ($element.val()) { |
| 422 |
case 'top-left': |
| 423 |
$img.css({ |
| 424 |
'top': offset_y + 'px', |
| 425 |
'left': offset_x + 'px' |
| 426 |
}); |
| 427 |
break; |
| 428 |
case 'top-right': |
| 429 |
$img.css({ |
| 430 |
'top': offset_y + 'px', |
| 431 |
'right': offset_x + 'px' |
| 432 |
}); |
| 433 |
break; |
| 434 |
case 'bottom-left': |
| 435 |
$img.css({ |
| 436 |
'bottom': offset_y + 'px', |
| 437 |
'left': offset_x + 'px' |
| 438 |
}); |
| 439 |
break; |
| 440 |
case 'bottom-right': |
| 441 |
$img.css({ |
| 442 |
'bottom': offset_y + 'px', |
| 443 |
'right': offset_x + 'px' |
| 444 |
}); |
| 445 |
break; |
| 446 |
case 'center': |
| 447 |
$img.css({ |
| 448 |
'top': '50%', |
| 449 |
'left': '50%', |
| 450 |
'transform': 'translate(-50%, -50%)' |
| 451 |
}); |
| 452 |
// Disable both offsets for center position |
| 453 |
$offset_x.prop('disabled', true); |
| 454 |
$offset_y.prop('disabled', true); |
| 455 |
break; |
| 456 |
case 'left': |
| 457 |
$img.css({ |
| 458 |
'top': '50%', |
| 459 |
'left': offset_x + 'px', |
| 460 |
'transform': 'translateY(-50%)' |
| 461 |
}); |
| 462 |
// Disable Y offset for left position |
| 463 |
$offset_y.prop('disabled', true); |
| 464 |
break; |
| 465 |
case 'right': |
| 466 |
$img.css({ |
| 467 |
'top': '50%', |
| 468 |
'right': offset_x + 'px', |
| 469 |
'transform': 'translateY(-50%)' |
| 470 |
}); |
| 471 |
// Disable Y offset for right position |
| 472 |
$offset_y.prop('disabled', true); |
| 473 |
break; |
| 474 |
case 'top': |
| 475 |
$img.css({ |
| 476 |
'top': offset_y + 'px', |
| 477 |
'left': '50%', |
| 478 |
'transform': 'translateX(-50%)' |
| 479 |
}); |
| 480 |
// Disable X offset for top position |
| 481 |
$offset_x.prop('disabled', true); |
| 482 |
break; |
| 483 |
case 'bottom': |
| 484 |
$img.css({ |
| 485 |
'bottom': offset_y + 'px', |
| 486 |
'left': '50%', |
| 487 |
'transform': 'translateX(-50%)' |
| 488 |
}); |
| 489 |
// Disable X offset for bottom position |
| 490 |
$offset_x.prop('disabled', true); |
| 491 |
break; |
| 492 |
} |
| 493 |
|
| 494 |
// Add visual feedback for disabled inputs |
| 495 |
$('.wp-sir-offset-input').each(function() { |
| 496 |
$(this).closest('.wp-sir-offset-field').toggleClass('disabled', $(this).prop('disabled')); |
| 497 |
}); |
| 498 |
} |
| 499 |
|
| 500 |
setWatermarkPosition($('#wp-sir-watermark-position')); |
| 501 |
|
| 502 |
// Update offset handlers |
| 503 |
$(document).on('change keyup paste', '#wp-sir-watermark-offset-x, #wp-sir-watermark-offset-y', function() { |
| 504 |
setWatermarkPosition($('#wp-sir-watermark-position')); |
| 505 |
}); |
| 506 |
|
| 507 |
$(document).on('change', '#wp-sir-enable-watermark', function () { |
| 508 |
if ($(this).is(':checked')) { |
| 509 |
$('.wp-sir-watermark-settings').css('display', 'flex'); |
| 510 |
} else { |
| 511 |
$('.wp-sir-watermark-settings').css('display', 'none'); |
| 512 |
|
| 513 |
} |
| 514 |
}).change(); |
| 515 |
|
| 516 |
|
| 517 |
jQuery(document).ready(function($) { |
| 518 |
|
| 519 |
|
| 520 |
// Update tolerance value display |
| 521 |
$('.wp-sir-range-input').on('input', function() { |
| 522 |
$('#' + $(this).data('value-display')).text($(this).val() + '%'); |
| 523 |
}); |
| 524 |
|
| 525 |
// Trim toggle — show/hide advanced sub-fields |
| 526 |
$('#wp-sir-enable-trim').on('change', function() { |
| 527 |
$('.wp-sir-trim-advanced-settings').toggle($(this).prop('checked')); |
| 528 |
}); |
| 529 |
|
| 530 |
// Tolerance slider — live feedback message |
| 531 |
$('#wp-sir-trim-tolerance').on('input', function() { |
| 532 |
var value = parseInt( $(this).val(), 10 ); |
| 533 |
var $feedback = $('.wp-sir-tolerance-feedback'); |
| 534 |
if ( value > 50 ) { |
| 535 |
$feedback.html('<span class="wp-sir-feedback--danger">Warning: High tolerance may trim parts of your image that you want to keep.</span>'); |
| 536 |
} else if ( value > 20 ) { |
| 537 |
$feedback.html('<span class="wp-sir-feedback--warning">Caution: Moderate-high tolerance — test on sample images first.</span>'); |
| 538 |
} else if ( value > 10 ) { |
| 539 |
$feedback.text('Medium tolerance — will trim similar shades of white.'); |
| 540 |
} else { |
| 541 |
$feedback.text('Default: 3%. Increase to trim more aggressively.'); |
| 542 |
} |
| 543 |
}).trigger('input'); |
| 544 |
|
| 545 |
$('.wp-sir-watermark-size').trigger('input'); |
| 546 |
|
| 547 |
// Initialize tooltips |
| 548 |
if($.fn.tipTip) |
| 549 |
{ |
| 550 |
$('.wp-sir-help-tip').tipTip({ |
| 551 |
'attribute': 'title', |
| 552 |
'fadeIn': 50, |
| 553 |
'fadeOut': 50, |
| 554 |
'delay': 200 |
| 555 |
}); |
| 556 |
} |
| 557 |
|
| 558 |
// Handle sizes section toggle |
| 559 |
$('.wp-sir-toggle-sizes').on('click', function() { |
| 560 |
const $button = $(this); |
| 561 |
const $wrapper = $('#wp-sir-sizes-options'); |
| 562 |
const isExpanded = $button.attr('aria-expanded') === 'true'; |
| 563 |
|
| 564 |
$wrapper.slideToggle(200); |
| 565 |
$button.attr('aria-expanded', !isExpanded); |
| 566 |
|
| 567 |
// Update button text |
| 568 |
const $text = $button.find('.wp-sir-toggle-text'); |
| 569 |
$text.text(isExpanded ? 'Customize image sizes' : 'Hide image sizes'); |
| 570 |
}); |
| 571 |
|
| 572 |
// Update sizes summary when selections change |
| 573 |
$('#wp-sir-sizes-selector input[type="checkbox"]').on('change', function() { |
| 574 |
const totalSizes = $('#wp-sir-sizes-selector .wpSirSelectSize').length; |
| 575 |
const selectedSizes = $('#wp-sir-sizes-selector .wpSirSelectSize:checked').length; |
| 576 |
|
| 577 |
$('.wp-sir-sizes-summary').text( |
| 578 |
`${selectedSizes} of ${totalSizes} size${totalSizes !== 1 ? 's' : ''} selected` |
| 579 |
); |
| 580 |
}); |
| 581 |
}); |
| 582 |
|
| 583 |
function createCurveControl() { |
| 584 |
const positions = [ |
| 585 |
['top-left', 'top', 'top-right'], |
| 586 |
['left', 'center', 'right'], |
| 587 |
['bottom-left', 'bottom', 'bottom-right'] |
| 588 |
]; |
| 589 |
|
| 590 |
let html = '<div class="wp-sir-curve-control">'; |
| 591 |
positions.forEach((row) => { |
| 592 |
html += '<div class="wp-sir-curve-row">'; |
| 593 |
row.forEach((pos) => { |
| 594 |
const label = pos.replace(/-/g, ' '); |
| 595 |
html += `<button type="button" class="wp-sir-curve-point" data-position="${pos}" title="${label}"><span class="screen-reader-text">${label}</span></button>`; |
| 596 |
}); |
| 597 |
html += '</div>'; |
| 598 |
}); |
| 599 |
html += '</div>'; |
| 600 |
|
| 601 |
$('#wp-sir-watermark-position').after(html); |
| 602 |
|
| 603 |
// Handle clicks |
| 604 |
$(document).on('click', '.wp-sir-curve-point', function() { |
| 605 |
$('.wp-sir-curve-point').removeClass('active'); |
| 606 |
$(this).addClass('active'); |
| 607 |
$('#wp-sir-watermark-position').val($(this).data('position')).trigger('change'); |
| 608 |
}); |
| 609 |
|
| 610 |
// Sync grid with dropdown |
| 611 |
function updateCurveFromDropdown() { |
| 612 |
const current = $('#wp-sir-watermark-position').val(); |
| 613 |
$('.wp-sir-curve-point').removeClass('active'); |
| 614 |
$(`.wp-sir-curve-point[data-position="${current}"]`).addClass('active'); |
| 615 |
} |
| 616 |
|
| 617 |
updateCurveFromDropdown(); |
| 618 |
$('#wp-sir-watermark-position').on('change', updateCurveFromDropdown); |
| 619 |
} |
| 620 |
|
| 621 |
// Initialize curve control when document is ready |
| 622 |
$(document).ready(function() { |
| 623 |
createCurveControl(); |
| 624 |
}); |
| 625 |
|
| 626 |
$('.wp-sir-tabs div').on('click', function(e) { |
| 627 |
e.preventDefault(); |
| 628 |
$('.wp-sir-tabs div').removeClass('active'); |
| 629 |
$(this).addClass('active'); |
| 630 |
if($(this).data('tab') === 'general'){ |
| 631 |
$('.sir-settings-general >table>tbody>tr:not(.wp-sir-is-advanced)').removeClass('hidden'); |
| 632 |
$('.sir-settings-general >table>tbody>tr.wp-sir-is-advanced').addClass('hidden'); |
| 633 |
}else{ |
| 634 |
$('.sir-settings-general >table>tbody>tr:not(.wp-sir-is-advanced)').addClass('hidden'); |
| 635 |
$('.sir-settings-general >table>tbody>tr.wp-sir-is-advanced').removeClass('hidden'); |
| 636 |
} |
| 637 |
}); |
| 638 |
|
| 639 |
// ── Redesigned settings page interactions ──────────────────────────────────── |
| 640 |
(function ($) { |
| 641 |
'use strict'; |
| 642 |
|
| 643 |
$(document).ready(function () { |
| 644 |
|
| 645 |
// Advanced settings toggle |
| 646 |
$('#wp-sir-toggle-advanced').on('click', function () { |
| 647 |
var $btn = $(this); |
| 648 |
var $panel = $('#wp-sir-advanced-fields'); |
| 649 |
var expanded = $btn.attr('aria-expanded') === 'true'; |
| 650 |
|
| 651 |
$panel.slideToggle(200); |
| 652 |
$btn.attr('aria-expanded', !expanded); |
| 653 |
}); |
| 654 |
|
| 655 |
// Image Uniformity enable/disable — dim the card body when off. |
| 656 |
function toggleUniformityState() { |
| 657 |
var $card = $('#wp-sir-core-settings'); |
| 658 |
if ($('#wp-sir-enable').is(':checked')) { |
| 659 |
$card.removeClass('wp-sir-card--disabled'); |
| 660 |
} else { |
| 661 |
$card.addClass('wp-sir-card--disabled'); |
| 662 |
} |
| 663 |
} |
| 664 |
toggleUniformityState(); |
| 665 |
$('#wp-sir-enable').on('change', toggleUniformityState); |
| 666 |
|
| 667 |
// Add-on card expand / collapse via header click |
| 668 |
// The toggle checkbox itself is handled separately to avoid double-firing. |
| 669 |
$(document).on('click', '.wp-sir-addon-card__header', function (e) { |
| 670 |
// Don't collapse when clicking the toggle checkbox or the PRO pill link. |
| 671 |
if ($(e.target).is('input[type="checkbox"], a, .wp-sir-toggle-label, .wp-sir-toggle-label *')) { |
| 672 |
return; |
| 673 |
} |
| 674 |
|
| 675 |
var $header = $(this); |
| 676 |
var targetId = $header.attr('aria-controls'); |
| 677 |
var $body = $('#' + targetId); |
| 678 |
var expanded = $header.attr('aria-expanded') === 'true'; |
| 679 |
|
| 680 |
$body.slideToggle(200); |
| 681 |
$header.attr('aria-expanded', !expanded); |
| 682 |
}); |
| 683 |
|
| 684 |
// Keyboard accessibility for add-on card headers |
| 685 |
$(document).on('keydown', '.wp-sir-addon-card__header', function (e) { |
| 686 |
if (e.which === 13 || e.which === 32) { |
| 687 |
e.preventDefault(); |
| 688 |
$(this).trigger('click'); |
| 689 |
} |
| 690 |
}); |
| 691 |
|
| 692 |
// When an add-on toggle is switched ON, also expand the body. |
| 693 |
$(document).on('change', '.wp-sir-addon-toggle', function () { |
| 694 |
var $checkbox = $(this); |
| 695 |
var targetId = $checkbox.data('target'); |
| 696 |
var $body = $('#' + targetId); |
| 697 |
var $header = $body.closest('.wp-sir-addon-card').find('.wp-sir-addon-card__header'); |
| 698 |
|
| 699 |
if ($checkbox.is(':checked')) { |
| 700 |
$body.slideDown(200); |
| 701 |
$header.attr('aria-expanded', 'true'); |
| 702 |
} else { |
| 703 |
$body.slideUp(200); |
| 704 |
$header.attr('aria-expanded', 'false'); |
| 705 |
} |
| 706 |
}); |
| 707 |
|
| 708 |
}); |
| 709 |
})(jQuery); |
| 710 |
|
| 711 |
// Handle Regenerate Thumbnails plugin installation — removed (built-in bulk processor replaces RT) |
| 712 |
|
| 713 |
// ─── Built-in Bulk Image Processor ─────────────────────────────────────────── |
| 714 |
(function ($) { |
| 715 |
'use strict'; |
| 716 |
|
| 717 |
// Only run when the bulk-regenerate tab is present. |
| 718 |
if (typeof wp_sir_object === 'undefined' || !wp_sir_object.bulk) { |
| 719 |
return; |
| 720 |
} |
| 721 |
|
| 722 |
var bulk = wp_sir_object.bulk; |
| 723 |
var ajaxUrl = wp_sir_object.ajax_url; |
| 724 |
var nonce = wp_sir_object.nonce; |
| 725 |
|
| 726 |
// All errors accumulated across the entire session (survives ticks). |
| 727 |
var _allErrors = []; |
| 728 |
var _aborted = false; |
| 729 |
var _started = false; // True once user initiates a process — prevents stale fetchStatus data. |
| 730 |
var _done = false; // True once done state is shown — prevents late callbacks overriding it. |
| 731 |
|
| 732 |
// DOM refs — resolved once the page is ready. |
| 733 |
var $wrap, $stateIdle, $stateActive, $stateDone; |
| 734 |
var $btnStart, $btnPause, $btnResume, $btnRestart, $btnAbort; |
| 735 |
var $statusLabel, $doneCount, $totalCount; |
| 736 |
var $progressBar, $progressBarWrap, $percentLabel; |
| 737 |
var $doneSummary; |
| 738 |
var $errorLog, $errorLogToggle, $errorLogTitle, $errorLogBody, $errorTableBody; |
| 739 |
var $idleMessage, $idleHint; |
| 740 |
|
| 741 |
function init() { |
| 742 |
$wrap = $('#wp-sir-bulk-wrap'); |
| 743 |
if (!$wrap.length) return; |
| 744 |
|
| 745 |
$stateIdle = $('#wp-sir-state-idle'); |
| 746 |
$stateActive = $('#wp-sir-state-active'); |
| 747 |
$stateDone = $('#wp-sir-state-done'); |
| 748 |
|
| 749 |
$btnStart = $('#wp-sir-bulk-start'); |
| 750 |
$btnPause = $('#wp-sir-bulk-pause'); |
| 751 |
$btnResume = $('#wp-sir-bulk-resume'); |
| 752 |
$btnRestart = $('#wp-sir-bulk-restart'); |
| 753 |
$btnAbort = $('#wp-sir-bulk-abort'); |
| 754 |
|
| 755 |
$statusLabel = $('#wp-sir-status-label'); |
| 756 |
$doneCount = $('#wp-sir-done-count'); |
| 757 |
$totalCount = $('#wp-sir-total-count'); |
| 758 |
$progressBar = $('#wp-sir-progress-bar'); |
| 759 |
$progressBarWrap = $('#wp-sir-progress-bar-wrap'); |
| 760 |
$percentLabel = $('#wp-sir-percent-label'); |
| 761 |
$doneSummary = $('#wp-sir-done-summary'); |
| 762 |
|
| 763 |
$errorLog = $('#wp-sir-error-log'); |
| 764 |
$errorLogToggle = $('#wp-sir-error-log-toggle'); |
| 765 |
$errorLogTitle = $('#wp-sir-error-log-title'); |
| 766 |
$errorLogBody = $('#wp-sir-error-log-body'); |
| 767 |
$errorTableBody = $('#wp-sir-error-table-body'); |
| 768 |
$idleMessage = $('#wp-sir-idle-message'); |
| 769 |
$idleHint = $('#wp-sir-idle-hint'); |
| 770 |
|
| 771 |
// Collapsible error log. |
| 772 |
$errorLogToggle.on('click keydown', function (e) { |
| 773 |
if (e.type === 'keydown' && e.which !== 13 && e.which !== 32) return; |
| 774 |
var expanded = $errorLogToggle.attr('aria-expanded') === 'true'; |
| 775 |
$errorLogToggle.attr('aria-expanded', !expanded); |
| 776 |
$errorLogBody.slideToggle(150); |
| 777 |
$errorLogToggle.find('.wp-sir-error-log-chevron') |
| 778 |
.toggleClass('dashicons-arrow-down-alt2', expanded) |
| 779 |
.toggleClass('dashicons-arrow-up-alt2', !expanded); |
| 780 |
}); |
| 781 |
|
| 782 |
$btnStart.on('click', function () { startProcess(false); }); |
| 783 |
$btnPause.on('click', pauseProcess); |
| 784 |
$btnResume.on('click', function () { resumeProcess(); }); |
| 785 |
$btnRestart.on('click', function () { |
| 786 |
startProcess(true); |
| 787 |
}); |
| 788 |
$btnAbort.on('click', function () { |
| 789 |
if (!window.confirm('Abort this process? Progress will be cleared and you can start fresh.')) return; |
| 790 |
_aborted = true; |
| 791 |
var $icon = $btnAbort.find('.dashicons'); |
| 792 |
var $label = $btnAbort.contents().filter(function() { return this.nodeType === 3; }).last(); |
| 793 |
$btnAbort.prop('disabled', true); |
| 794 |
$label[0].textContent = ' Aborting\u2026'; |
| 795 |
ajax(bulk.action_reset, {}, function (res) { |
| 796 |
$label[0].textContent = ' Abort'; |
| 797 |
$btnAbort.prop('disabled', false); |
| 798 |
_allErrors = []; |
| 799 |
$errorTableBody.empty(); |
| 800 |
$errorLog.hide(); |
| 801 |
if (res && res.success) { |
| 802 |
applyState({ status: 'idle' }); |
| 803 |
fetchCount(); |
| 804 |
} |
| 805 |
}); |
| 806 |
}); |
| 807 |
|
| 808 |
fetchStatus(); |
| 809 |
|
| 810 |
// Refresh count link — manual recount. |
| 811 |
$('#wp-sir-refresh-count').on('click', function (e) { |
| 812 |
e.preventDefault(); |
| 813 |
var $link = $(this); |
| 814 |
$link.addClass('wp-sir-refresh-count--spinning'); |
| 815 |
ajax(bulk.action_count, {}, function (res) { |
| 816 |
$link.removeClass('wp-sir-refresh-count--spinning'); |
| 817 |
if (res && res.success) { |
| 818 |
applyCount(parseInt(res.data.count, 10) || 0); |
| 819 |
} |
| 820 |
}); |
| 821 |
}); |
| 822 |
|
| 823 |
// If no cached count was available server-side, fetch it now. |
| 824 |
if ($btnStart.prop('disabled') && $idleMessage.text().indexOf('Checking') !== -1) { |
| 825 |
prefetchCount(); |
| 826 |
} |
| 827 |
} |
| 828 |
|
| 829 |
// ── API ──────────────────────────────────────────────────────────────────── |
| 830 |
|
| 831 |
var _prefetchedCount = null; |
| 832 |
|
| 833 |
function ajax(action, extraData, callback) { |
| 834 |
$.post(ajaxUrl, $.extend({ action: action, nonce: nonce }, extraData || {}), callback, 'json'); |
| 835 |
} |
| 836 |
|
| 837 |
function fetchStatus() { |
| 838 |
ajax(bulk.action_status, {}, function (res) { |
| 839 |
if (res && res.success) { |
| 840 |
// Only restore errors from a previous session if we haven't already |
| 841 |
// started a new process (prevents race condition on fast clicks). |
| 842 |
if (!_started && res.data.new_errors && res.data.new_errors.length && res.data.status !== 'running') { |
| 843 |
appendErrors(res.data.new_errors); |
| 844 |
} |
| 845 |
|
| 846 |
// On a fresh page load there is no active tick loop. |
| 847 |
// If the server says "running" it means the previous session was |
| 848 |
// interrupted (tab closed, reload, crash). Treat it as paused so |
| 849 |
// the user sees Resume, not Pause with nothing actually processing. |
| 850 |
if (res.data.status === 'running') { |
| 851 |
res.data.status = 'paused'; |
| 852 |
// Tell the server to record the paused state too, fire-and-forget. |
| 853 |
ajax(bulk.action_pause, {}); |
| 854 |
} |
| 855 |
|
| 856 |
applyState(res.data); |
| 857 |
|
| 858 |
// If idle, apply the prefetched count (or wait for it). |
| 859 |
if (!res.data.status || res.data.status === 'idle') { |
| 860 |
applyCount(_prefetchedCount); |
| 861 |
} |
| 862 |
} |
| 863 |
}); |
| 864 |
} |
| 865 |
|
| 866 |
// Fire the count request in parallel with fetchStatus for faster load. |
| 867 |
function prefetchCount() { |
| 868 |
ajax(bulk.action_count, {}, function (res) { |
| 869 |
if (res && res.success) { |
| 870 |
_prefetchedCount = parseInt(res.data.count, 10) || 0; |
| 871 |
} else { |
| 872 |
_prefetchedCount = -1; // error state |
| 873 |
} |
| 874 |
// If idle state is already shown, apply immediately. |
| 875 |
if ($stateIdle.is(':visible')) { |
| 876 |
applyCount(_prefetchedCount); |
| 877 |
} |
| 878 |
}); |
| 879 |
} |
| 880 |
|
| 881 |
function applyCount(count) { |
| 882 |
if (count === null) return; // still loading |
| 883 |
if (count === -1) { |
| 884 |
$idleMessage.text('Ready to process your images.'); |
| 885 |
$idleHint.show(); |
| 886 |
$btnStart.prop('disabled', false); |
| 887 |
return; |
| 888 |
} |
| 889 |
if (count > 0) { |
| 890 |
$idleMessage.text(count + ' image' + (count !== 1 ? 's' : '') + ' ready to be processed.'); |
| 891 |
$btnStart.prop('disabled', false); |
| 892 |
} else { |
| 893 |
$idleMessage.text('All your images are already up to date.'); |
| 894 |
$btnStart.prop('disabled', true); |
| 895 |
} |
| 896 |
$idleHint.show(); |
| 897 |
} |
| 898 |
|
| 899 |
function fetchCount() { |
| 900 |
// Used after abort — fires a fresh count request. |
| 901 |
ajax(bulk.action_count, {}, function (res) { |
| 902 |
if (res && res.success) { |
| 903 |
applyCount(parseInt(res.data.count, 10) || 0); |
| 904 |
} else { |
| 905 |
applyCount(-1); |
| 906 |
} |
| 907 |
}); |
| 908 |
} |
| 909 |
|
| 910 |
function startProcess(restart) { |
| 911 |
_aborted = false; |
| 912 |
_started = true; |
| 913 |
_done = false; |
| 914 |
// Always clear the client-side error log before starting or restarting — |
| 915 |
// the server truncates the errors table on both paths too. |
| 916 |
_allErrors = []; |
| 917 |
$errorTableBody.empty(); |
| 918 |
$errorLog.hide(); |
| 919 |
// Instant feedback — disable button and show loading state. |
| 920 |
$btnStart.prop('disabled', true).addClass('wp-sir-btn-loading'); |
| 921 |
ajax(bulk.action_start, { restart: restart ? 1 : 0 }, function (res) { |
| 922 |
$btnStart.prop('disabled', false).removeClass('wp-sir-btn-loading'); |
| 923 |
if (res && res.success) { |
| 924 |
applyState(res.data); |
| 925 |
if (res.data.status === 'running') tick(); |
| 926 |
} |
| 927 |
}); |
| 928 |
} |
| 929 |
|
| 930 |
function resumeProcess() { |
| 931 |
_aborted = false; |
| 932 |
// Instant feedback — hide resume, show pause immediately. |
| 933 |
$btnResume.hide(); |
| 934 |
$btnAbort.hide(); |
| 935 |
$btnPause.css('display', 'inline-flex'); |
| 936 |
$statusLabel.text('Processing\u2026'); |
| 937 |
ajax(bulk.action_start, { restart: 0 }, function (res) { |
| 938 |
if (res && res.success) { |
| 939 |
applyState(res.data); |
| 940 |
if (res.data.status === 'running') tick(); |
| 941 |
} |
| 942 |
}); |
| 943 |
} |
| 944 |
|
| 945 |
function pauseProcess() { |
| 946 |
_aborted = true; |
| 947 |
// Instant feedback — disable button and show loading state. |
| 948 |
$btnPause.prop('disabled', true).addClass('wp-sir-btn-loading'); |
| 949 |
ajax(bulk.action_pause, {}, function (res) { |
| 950 |
$btnPause.prop('disabled', false).removeClass('wp-sir-btn-loading'); |
| 951 |
if (res && res.success) applyState(res.data); |
| 952 |
}); |
| 953 |
} |
| 954 |
|
| 955 |
function tick() { |
| 956 |
if (_aborted) return; |
| 957 |
|
| 958 |
ajax(bulk.action_process, {}, function (res) { |
| 959 |
if (_aborted) return; // pause was clicked while this request was in-flight |
| 960 |
|
| 961 |
if (!res || !res.success) { |
| 962 |
_aborted = true; |
| 963 |
applyState({ status: 'paused', total: parseInt($totalCount.text(), 10), done: parseInt($doneCount.text(), 10), error_count: _allErrors.length }); |
| 964 |
return; |
| 965 |
} |
| 966 |
|
| 967 |
// Append any new errors from this batch immediately. |
| 968 |
if (res.data.new_errors && res.data.new_errors.length) { |
| 969 |
appendErrors(res.data.new_errors); |
| 970 |
} |
| 971 |
|
| 972 |
applyState(res.data); |
| 973 |
|
| 974 |
if (res.data.status === 'running') { |
| 975 |
setTimeout(tick, 300); |
| 976 |
} |
| 977 |
}); |
| 978 |
} |
| 979 |
|
| 980 |
// ── Error log helpers ────────────────────────────────────────────────────── |
| 981 |
|
| 982 |
function appendErrors(errors) { |
| 983 |
if (!errors || !errors.length) return; |
| 984 |
|
| 985 |
errors.forEach(function (err) { |
| 986 |
_allErrors.push(err); |
| 987 |
var $row = $('<tr>') |
| 988 |
.append($('<td class="wp-sir-error-file">').text(err.file)) |
| 989 |
.append($('<td class="wp-sir-error-reason">').text(err.reason)); |
| 990 |
$errorTableBody.append($row); |
| 991 |
}); |
| 992 |
|
| 993 |
// Update header count and show the log. |
| 994 |
var count = _allErrors.length; |
| 995 |
$errorLogTitle.text(count + ' image' + (count !== 1 ? 's' : '') + ' skipped'); |
| 996 |
$errorLog.show(); |
| 997 |
} |
| 998 |
|
| 999 |
// ── UI state ─────────────────────────────────────────────────────────────── |
| 1000 |
|
| 1001 |
function applyState(data) { |
| 1002 |
var status = data.status || 'idle'; |
| 1003 |
var total = parseInt(data.total, 10) || 0; |
| 1004 |
var done = parseInt(data.done, 10) || 0; |
| 1005 |
var pct = total > 0 ? Math.round((done / total) * 100) : 0; |
| 1006 |
|
| 1007 |
// Once done, don't allow late callbacks to revert to another state. |
| 1008 |
if (_done && status !== 'done' && status !== 'idle') { |
| 1009 |
return; |
| 1010 |
} |
| 1011 |
|
| 1012 |
// Hide loading placeholder once real state is known. |
| 1013 |
$('#wp-sir-state-loading').remove(); |
| 1014 |
|
| 1015 |
$stateIdle.hide(); |
| 1016 |
$stateActive.hide(); |
| 1017 |
$stateDone.hide(); |
| 1018 |
|
| 1019 |
if (status === 'idle') { |
| 1020 |
_done = false; |
| 1021 |
$stateIdle.show(); |
| 1022 |
return; |
| 1023 |
} |
| 1024 |
|
| 1025 |
if (status === 'done') { |
| 1026 |
_done = true; |
| 1027 |
$stateDone.show(); |
| 1028 |
var skipped = _allErrors.length; |
| 1029 |
var succeeded = done - skipped; |
| 1030 |
var summary = succeeded + ' image' + (succeeded !== 1 ? 's' : '') + ' processed successfully.'; |
| 1031 |
if (skipped > 0) { |
| 1032 |
summary += ' ' + skipped + ' image' + (skipped !== 1 ? 's' : '') + ' were skipped — see the log below.'; |
| 1033 |
} |
| 1034 |
$doneSummary.text(summary); |
| 1035 |
return; |
| 1036 |
} |
| 1037 |
|
| 1038 |
// running or paused |
| 1039 |
$stateActive.show(); |
| 1040 |
$doneCount.text(done); |
| 1041 |
$totalCount.text(total); |
| 1042 |
$percentLabel.text(pct + '%'); |
| 1043 |
$progressBar.css('width', pct + '%'); |
| 1044 |
$progressBarWrap.attr('aria-valuenow', pct); |
| 1045 |
|
| 1046 |
if (status === 'running') { |
| 1047 |
$statusLabel.text('Processing\u2026'); |
| 1048 |
$btnPause.css('display', 'inline-flex'); |
| 1049 |
$btnResume.hide(); |
| 1050 |
$btnAbort.hide(); |
| 1051 |
$progressBar.removeClass('wp-sir-bulk-progress-bar--paused'); |
| 1052 |
} else { |
| 1053 |
$statusLabel.text('Paused'); |
| 1054 |
$btnPause.hide(); |
| 1055 |
$btnResume.css('display', 'inline-flex'); |
| 1056 |
$btnAbort.css('display', 'inline-flex'); |
| 1057 |
$progressBar.addClass('wp-sir-bulk-progress-bar--paused'); |
| 1058 |
} |
| 1059 |
} |
| 1060 |
|
| 1061 |
$(document).ready(init); |
| 1062 |
|
| 1063 |
})(jQuery); |
| 1064 |
|
| 1065 |
})(jQuery); |
| 1066 |
|
| 1067 |
|
| 1068 |
|
| 1069 |
|
| 1070 |
|
| 1071 |
|
| 1072 |
// ─── Reset images (settings page) ──────────────────────────────────────────── |
| 1073 |
(function ($) { |
| 1074 |
'use strict'; |
| 1075 |
|
| 1076 |
$(document).ready(function () { |
| 1077 |
|
| 1078 |
if (!$('#wp-sir-reset-section').length) return; |
| 1079 |
|
| 1080 |
var ajaxUrl = wp_sir_object.ajax_url; |
| 1081 |
var nonce = wp_sir_object.restore_nonce; |
| 1082 |
var BATCH = 5; |
| 1083 |
|
| 1084 |
var $btnStart = $('#wp-sir-reset-start'); |
| 1085 |
var $countLabel = $('#wp-sir-reset-count'); |
| 1086 |
var $stateIdle = $('#wp-sir-reset-state-idle'); |
| 1087 |
var $stateRunning = $('#wp-sir-reset-state-running'); |
| 1088 |
var $stateDone = $('#wp-sir-reset-state-done'); |
| 1089 |
var $progressBar = $('#wp-sir-reset-progress-bar'); |
| 1090 |
var $progressWrap = $('#wp-sir-reset-progress-wrap'); |
| 1091 |
var $pct = $('#wp-sir-reset-percent'); |
| 1092 |
var $doneCount = $('#wp-sir-reset-done'); |
| 1093 |
var $totalCount = $('#wp-sir-reset-total'); |
| 1094 |
var $summary = $('#wp-sir-reset-summary'); |
| 1095 |
var $errorsWrap = $('#wp-sir-reset-errors'); |
| 1096 |
var $errorList = $('#wp-sir-reset-error-list'); |
| 1097 |
|
| 1098 |
var _ids = []; |
| 1099 |
var _total = 0; |
| 1100 |
var _done = 0; |
| 1101 |
var _errors = []; |
| 1102 |
var _stopped = false; |
| 1103 |
|
| 1104 |
// Fetch count of processed images on page load. |
| 1105 |
$.post(ajaxUrl, { action: 'wp_sir_bulk_restore_status', nonce: nonce }, function (res) { |
| 1106 |
if (res && res.success && res.data.total > 0) { |
| 1107 |
_ids = res.data.ids; |
| 1108 |
_total = res.data.total; |
| 1109 |
$countLabel.text('(' + _total + ' image' + (_total !== 1 ? 's' : '') + ' processed)'); |
| 1110 |
$btnStart.prop('disabled', false); |
| 1111 |
} else { |
| 1112 |
$countLabel.text('(' + wp_sir_object.i18n.no_processed_images + ')'); |
| 1113 |
} |
| 1114 |
}, 'json'); |
| 1115 |
|
| 1116 |
$btnStart.on('click', function () { |
| 1117 |
if (!_ids.length) return; |
| 1118 |
if (!window.confirm(wp_sir_object.i18n.restore_confirm)) return; |
| 1119 |
|
| 1120 |
_done = 0; |
| 1121 |
_errors = []; |
| 1122 |
_stopped = false; |
| 1123 |
$errorList.empty(); |
| 1124 |
$errorsWrap.hide(); |
| 1125 |
$stateIdle.hide(); |
| 1126 |
$stateRunning.show(); |
| 1127 |
$stateDone.hide(); |
| 1128 |
$totalCount.text(_total); |
| 1129 |
processBatch(); |
| 1130 |
}); |
| 1131 |
|
| 1132 |
$('#wp-sir-reset-stop').on('click', function () { |
| 1133 |
_stopped = true; |
| 1134 |
$(this).prop('disabled', true).text('Stopping…'); |
| 1135 |
}); |
| 1136 |
|
| 1137 |
function processBatch() { |
| 1138 |
if (_stopped) { finish(); return; } |
| 1139 |
var batch = _ids.slice(_done, _done + BATCH); |
| 1140 |
if (!batch.length) { finish(); return; } |
| 1141 |
|
| 1142 |
$.post(ajaxUrl, { |
| 1143 |
action: 'wp_sir_bulk_restore_batch', |
| 1144 |
nonce: nonce, |
| 1145 |
ids: JSON.stringify(batch) |
| 1146 |
}, function (res) { |
| 1147 |
if (!res || !res.success) { finish(); return; } |
| 1148 |
|
| 1149 |
_done += batch.length; |
| 1150 |
|
| 1151 |
if (res.data.errors && res.data.errors.length) { |
| 1152 |
res.data.errors.forEach(function (e) { |
| 1153 |
_errors.push(e); |
| 1154 |
$errorList.append('<li>ID ' + e.id + ': ' + $('<span>').text(e.reason).html() + '</li>'); |
| 1155 |
}); |
| 1156 |
$errorsWrap.show(); |
| 1157 |
} |
| 1158 |
|
| 1159 |
var percent = Math.round((_done / _total) * 100); |
| 1160 |
$progressBar.css('width', percent + '%'); |
| 1161 |
$progressWrap.attr('aria-valuenow', percent); |
| 1162 |
$pct.text(percent + '%'); |
| 1163 |
$doneCount.text(_done); |
| 1164 |
|
| 1165 |
if (_done >= _total) { finish(); } else if (!_stopped) { setTimeout(processBatch, 300); } else { finish(); } |
| 1166 |
}, 'json'); |
| 1167 |
} |
| 1168 |
|
| 1169 |
function finish() { |
| 1170 |
$stateRunning.hide(); |
| 1171 |
$stateDone.show(); |
| 1172 |
$('#wp-sir-reset-stop').prop('disabled', false).text('Stop'); |
| 1173 |
|
| 1174 |
var succeeded = _done - _errors.length; |
| 1175 |
var s = succeeded + ' image' + (succeeded !== 1 ? 's' : '') + ' restored to original state.'; |
| 1176 |
if (_stopped && _done < _total) { s += ' Stopped — ' + (_total - _done) + ' remaining.'; } |
| 1177 |
if (_errors.length) { s += ' ' + _errors.length + ' failed — see above.'; } |
| 1178 |
$summary.text(s); |
| 1179 |
|
| 1180 |
_ids = []; |
| 1181 |
$btnStart.prop('disabled', true); |
| 1182 |
$countLabel.text('(' + wp_sir_object.i18n.no_processed_images + ')'); |
| 1183 |
} |
| 1184 |
|
| 1185 |
}); |
| 1186 |
|
| 1187 |
})(jQuery); |
| 1188 |
|