: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
import '../../scss/resize-detection.scss';
* Image resize detection (IRD).
* Show all wrongly scaled images with a highlighted border and resize box.
* DO NOT ADD JQUERY SUPPORT!!!
bar: document.getElementById( 'smush-image-bar' ),
toggle: document.getElementById( 'smush-image-bar-toggle' ),
strings: window.wp_smush_resize_vars,
* Make sure these are set, before we proceed.
this.bar = document.getElementById( 'smush-image-bar' );
this.toggle = document.getElementById(
// Register the event handler after everything is done.
this.toggle.addEventListener(
this.handleToggleClick.bind( this )
const icon = this.toggle.querySelector( 'i' );
icon.classList.add( 'sui-icon-loader' );
icon.classList.remove( 'sui-icon-info' );
if ( ! this.images.bigger.length && ! this.images.smaller.length ) {
this.toggle.classList.add( 'smush-toggle-success' );
).style.display = 'block';
'smush-image-bar-notice-desc'
).style.display = 'none';
this.toggle.classList.remove( 'smush-toggle-success' );
).style.display = 'none';
'smush-image-bar-notice-desc'
).style.display = 'block';
this.generateMarkup( 'bigger' );
this.generateMarkup( 'smaller' );
icon.classList.remove( 'sui-icon-loader' );
icon.classList.add( 'sui-icon-info' );
* Various checks to see if the image should be processed.
* @return {boolean} Should skip image or not.
shouldSkipImage( image ) {
if ( image.classList.contains( 'avatar' ) ) {
// Skip images from Smush CDN with auto-resize feature.
'string' === typeof image.getAttribute( 'no-resize-detection' )
image.clientWidth === image.clientHeight &&
// Skip 1x1px placeholders.
image.naturalWidth === image.naturalHeight &&
// If width attribute is not set, do not continue.
return null === image.clientWidth || null === image.clientHeight;
* @return {string} Tooltip.
getTooltipText( props ) {
if ( props.bigger_width || props.bigger_height ) {
/** @param {string} strings.large_image */
tooltipText = this.strings.large_image;
} else if ( props.smaller_width || props.smaller_height ) {
/** @param {string} strings.small_image */
tooltipText = this.strings.small_image;
.replace( 'width', props.real_width )
.replace( 'height', props.real_height );
* @param {string} type Accepts: 'bigger' or 'smaller'.
this.images[ type ].forEach( ( image, index ) => {
const item = document.createElement( 'div' ),
tooltip = this.getTooltipText( image.props );
'smush-resize-box smush-tooltip smush-tooltip-constrained'
item.setAttribute( 'data-tooltip', tooltip );
item.setAttribute( 'data-image', image.class );
item.addEventListener( 'click', ( e ) =>
<div class="smush-image-info">
<span>${ index + 1 }</span>
<span class="smush-tag">${ image.props.computed_width } x ${ image.props.computed_height }px</span>
<i class="smush-front-icons smush-front-icon-arrows-in" aria-hidden="true"> </i>
<span class="smush-tag smush-tag-success">${ image.props.real_width } × ${ image.props.real_height }px</span>
<div class="smush-image-description">${ tooltip }</div>
.getElementById( 'smush-image-bar-items-' + type )
* Show/hide sections based on images.
const types = [ 'bigger', 'smaller' ];
types.forEach( ( type ) => {
const div = document.getElementById(
'smush-image-bar-items-' + type
if ( 0 === this.images[ type ].length ) {
div.style.display = 'none';
div.style.display = 'block';
* Scroll the selected image into view and highlight it.
const el = document.getElementsByClassName(
e.currentTarget.dataset.image
if ( 'undefined' !== typeof el[ 0 ] ) {
// Display description box.
e.currentTarget.classList.toggle( 'show-description' );
// Scroll and flash image.
el[ 0 ].scrollIntoView( {
el[ 0 ].style.opacity = '0.5';
el[ 0 ].style.opacity = '1';
* Handle click on the toggle item.
this.bar.classList.toggle( 'closed' );
this.toggle.classList.toggle( 'closed' );
const items = document.getElementsByClassName( 'show-description' );
if ( items.length > 0 ) {
Array.from( items ).forEach( ( div ) =>
div.classList.remove( 'show-description' )
* Function to highlight all scaled images.
* Add yellow border and then show one small box to
* resize the images as per the required size, on fly.
const images = document.getElementsByTagName( 'img' );
for ( const image of images ) {
if ( this.shouldSkipImage( image ) ) {
// Get defined width and height.
real_width: image.clientWidth,
real_height: image.clientHeight,
computed_width: image.naturalWidth,
computed_height: image.naturalHeight,
bigger_width: image.clientWidth * 1.5 < image.naturalWidth,
image.clientHeight * 1.5 < image.naturalHeight,
smaller_width: image.clientWidth > image.naturalWidth,
smaller_height: image.clientHeight > image.naturalHeight,
// In case image is in correct size, do not continue.
props.bigger_width || props.bigger_height
'smush-image-' + ( this.images[ imgType ].length + 1 );
// Fill the images arrays.
this.images[ imgType ].push( {
* Add class to original image.
* Can't add two classes in single add(), because no support in IE11.
* image.classList.add('smush-detected-img', imageClass);
image.classList.add( 'smush-detected-img' );
image.classList.add( imageClass );
* Allows refreshing the list. A good way is to refresh on lazyload actions.
// Clear out classes on DOM.
for ( let id in this.images.bigger ) {
if ( this.images.bigger.hasOwnProperty( id ) ) {
this.images.bigger[ id ].src.classList.remove(
this.images.bigger[ id ].src.classList.remove(
for ( let id in this.images.smaller ) {
if ( this.images.smaller.hasOwnProperty( id ) ) {
this.images.smaller[ id ].src.classList.remove(
this.images.smaller[ id ].src.classList.remove(
// This might be overkill - there will probably never be a situation when there are less images than on
const elements = document.getElementsByClassName(
while ( elements.length > 0 ) {
* After page load, initialize toggle event.
window.addEventListener( 'DOMContentLoaded', () => SmushIRS.init() );
window.addEventListener( 'lazyloaded', () => SmushIRS.refresh() );