EWWW Image Optimizer - Version 4.7.1

Version Description

  • added: CSS background image support for
  • elements
  • added: ExactDN + Lazy Load will auto-calculate dimensions for img elements without srcset/responsive markup
  • added: ExactDN parses thumbnail url for personalization.com + WooCommerce integration
  • added: ExactDN can use data-actual-width attribute for srcset generation
  • added: ExactDN + Lazy Load uses devicePixelRatio to provide clearer background images
  • fixed: Lazy Load for CSS background images misfires when display height is greater than width
  • fixed: visitors without JS see Lazy Load placeholder + fallback image
Download this release

Release Info

Developer nosilver4u
Plugin Icon 128x128 EWWW Image Optimizer
Version 4.7.1
Comparing to
See all releases

Code changes from version 4.7.0 to 4.7.1

bulk.php CHANGED
@@ -773,6 +773,11 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
773
  $skipped_ids[] = $selected_id;
774
  continue;
775
  }
 
 
 
 
 
776
  if ( empty( $attachment_meta[ $selected_id ]['meta'] ) ) {
777
  ewwwio_debug_message( "empty meta for $selected_id" );
778
  $meta = array();
@@ -1498,9 +1503,8 @@ function ewww_image_optimizer_bulk_loop( $hook = '', $delay = 0 ) {
1498
  $output['new_nonce'] = '';
1499
  }
1500
  }
1501
- $batch_image_limit = ( empty( $_REQUEST['ewww_batch_limit'] ) ? 999 : 1 );
1502
  // Get the 'bulk attachments' with a list of IDs remaining.
1503
- // $attachments = get_option( 'ewww_image_optimizer_bulk_attachments' );.
1504
  $attachments = ewww_image_optimizer_get_queued_attachments( 'media', $batch_image_limit );
1505
  if ( ! empty( $attachments ) && is_array( $attachments ) ) {
1506
  $attachment = (int) $attachments[0];
773
  $skipped_ids[] = $selected_id;
774
  continue;
775
  }
776
+ if ( ! empty( $attachment_meta[ $selected_id ]['file'] ) && false !== strpos( $attachment_meta[ $selected_id ]['file'], 'https://images-na.ssl-images-amazon.com' ) ) {
777
+ ewwwio_debug_message( "Cannot compress externally-hosted Amazon image $selected_id" );
778
+ $skipped_ids[] = $selected_id;
779
+ continue;
780
+ }
781
  if ( empty( $attachment_meta[ $selected_id ]['meta'] ) ) {
782
  ewwwio_debug_message( "empty meta for $selected_id" );
783
  $meta = array();
1503
  $output['new_nonce'] = '';
1504
  }
1505
  }
1506
+ $batch_image_limit = ( empty( $_REQUEST['ewww_batch_limit'] ) && ! class_exists( 'Amazon_S3_And_CloudFront' ) && ! class_exists( 'S3_Uploads' ) ? 999 : 1 );
1507
  // Get the 'bulk attachments' with a list of IDs remaining.
 
1508
  $attachments = ewww_image_optimizer_get_queued_attachments( 'media', $batch_image_limit );
1509
  if ( ! empty( $attachments ) && is_array( $attachments ) ) {
1510
  $attachment = (int) $attachments[0];
changelog.txt CHANGED
@@ -1,3 +1,12 @@
 
 
 
 
 
 
 
 
 
1
  = 4.7.0 =
2
  * added: lazy load (on ExactDN tab for now)
3
  * added: JS WebP supports background images via lazy load (div elements only for now)
1
+ = 4.7.1 =
2
+ * added: CSS background image support for <li> elements
3
+ * added: ExactDN + Lazy Load will auto-calculate dimensions for img elements without srcset/responsive markup
4
+ * added: ExactDN parses thumbnail url for personalization.com + WooCommerce integration
5
+ * added: ExactDN can use data-actual-width attribute for srcset generation
6
+ * added: ExactDN + Lazy Load uses devicePixelRatio to provide clearer background images
7
+ * fixed: Lazy Load for CSS background images misfires when display height is greater than width
8
+ * fixed: visitors without JS see Lazy Load placeholder + fallback image
9
+
10
  = 4.7.0 =
11
  * added: lazy load (on ExactDN tab for now)
12
  * added: JS WebP supports background images via lazy load (div elements only for now)
classes/class-ewwwio-lazy-load.php CHANGED
@@ -41,8 +41,8 @@ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
41
  ewwwio_debug_message( 'you are doing it wrong' );
42
  return 'you are doing it wrong';
43
  }
44
- // Start an output buffer before any output starts.
45
- /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 1 ); */
46
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 15 );
47
 
48
  if ( class_exists( 'ExactDN' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
@@ -198,40 +198,10 @@ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
198
  }
199
  } // End foreach().
200
  } // End if().
201
- // Process background images on 'div' elements.
202
- $divs = $this->get_elements_from_html( $buffer, 'div' );
203
- if ( ewww_image_optimizer_iterable( $divs ) ) {
204
- $lazy_class = 'lazyload';
205
- foreach ( $divs as $index => $div ) {
206
- ewwwio_debug_message( 'parsing a div' );
207
- if ( false === strpos( $div, 'background:' ) && false === strpos( $div, 'background-image:' ) ) {
208
- continue;
209
- }
210
- if ( false !== strpos( $div, $lazy_class ) ) {
211
- continue;
212
- }
213
- if ( ! $this->validate_bgimage_tag( $div ) ) {
214
- continue;
215
- }
216
- $style = $this->get_attribute( $div, 'style' );
217
- if ( empty( $style ) ) {
218
- continue;
219
- }
220
- ewwwio_debug_message( "checking style attr for background-image: $style" );
221
- $bg_image_url = $this->get_background_image_url( $style );
222
- if ( $bg_image_url ) {
223
- $this->set_attribute( $div, 'class', $this->get_attribute( $div, 'class' ) . " $lazy_class", true );
224
- $this->set_attribute( $div, 'data-bg', $bg_image_url );
225
- $new_style = $this->remove_background_image( $style );
226
- if ( $style !== $new_style ) {
227
- $div = str_replace( $style, $new_style, $div );
228
- }
229
- }
230
- if ( $div !== $divs[ $index ] ) {
231
- $buffer = str_replace( $divs[ $index ], $div, $buffer );
232
- }
233
- }
234
- }
235
  // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere.
236
  $pictures = $this->get_picture_tags_from_html( $buffer );
237
  if ( ewww_image_optimizer_iterable( $pictures ) ) {
@@ -285,6 +255,46 @@ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
285
  return $buffer;
286
  }
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  /**
289
  * Checks if the tag is allowed to be lazy loaded.
290
  *
@@ -355,7 +365,9 @@ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
355
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
356
  $exclusions = apply_filters(
357
  'ewww_image_optimizer_lazy_bg_image_exclusions',
358
- array(),
 
 
359
  $tag
360
  );
361
  foreach ( $exclusions as $exclusion ) {
@@ -379,6 +391,13 @@ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
379
  return $use_lqip;
380
  }
381
 
 
 
 
 
 
 
 
382
  /**
383
  * Load full lazysizes script when SCRIPT_DEBUG is enabled.
384
  */
41
  ewwwio_debug_message( 'you are doing it wrong' );
42
  return 'you are doing it wrong';
43
  }
44
+
45
+ add_action( 'wp_head', array( $this, 'no_js_css' ) );
46
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 15 );
47
 
48
  if ( class_exists( 'ExactDN' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
198
  }
199
  } // End foreach().
200
  } // End if().
201
+ // Process background images on div elements.
202
+ $buffer = $this->parse_background_images( $buffer, 'div' );
203
+ // Process background images on li elements.
204
+ $buffer = $this->parse_background_images( $buffer, 'li' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere.
206
  $pictures = $this->get_picture_tags_from_html( $buffer );
207
  if ( ewww_image_optimizer_iterable( $pictures ) ) {
255
  return $buffer;
256
  }
257
 
258
+ /**
259
+ * Parse elements of a given type for inline CSS background images.
260
+ *
261
+ * @param string $buffer The HTML content to parse.
262
+ * @param string $tag_type The type of HTML tag to look for.
263
+ * @return string The modified content with LL markup.
264
+ */
265
+ function parse_background_images( $buffer, $tag_type ) {
266
+ $elements = $this->get_elements_from_html( $buffer, $tag_type );
267
+ if ( ewww_image_optimizer_iterable( $elements ) ) {
268
+ foreach ( $elements as $index => $element ) {
269
+ ewwwio_debug_message( "parsing a $tag_type" );
270
+ if ( false === strpos( $element, 'background:' ) && false === strpos( $element, 'background-image:' ) ) {
271
+ continue;
272
+ }
273
+ if ( ! $this->validate_bgimage_tag( $element ) ) {
274
+ continue;
275
+ }
276
+ $style = $this->get_attribute( $element, 'style' );
277
+ if ( empty( $style ) ) {
278
+ continue;
279
+ }
280
+ ewwwio_debug_message( "checking style attr for background-image: $style" );
281
+ $bg_image_url = $this->get_background_image_url( $style );
282
+ if ( $bg_image_url ) {
283
+ $new_style = $this->remove_background_image( $style );
284
+ if ( $style !== $new_style ) {
285
+ $this->set_attribute( $element, 'class', $this->get_attribute( $element, 'class' ) . ' lazyload', true );
286
+ $this->set_attribute( $element, 'data-bg', $bg_image_url );
287
+ $element = str_replace( $style, $new_style, $element );
288
+ }
289
+ }
290
+ if ( $element !== $elements[ $index ] ) {
291
+ $buffer = str_replace( $elements[ $index ], $element, $buffer );
292
+ }
293
+ }
294
+ }
295
+ return $buffer;
296
+ }
297
+
298
  /**
299
  * Checks if the tag is allowed to be lazy loaded.
300
  *
365
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
366
  $exclusions = apply_filters(
367
  'ewww_image_optimizer_lazy_bg_image_exclusions',
368
+ array(
369
+ 'lazyload',
370
+ ),
371
  $tag
372
  );
373
  foreach ( $exclusions as $exclusion ) {
391
  return $use_lqip;
392
  }
393
 
394
+ /**
395
+ * Adds a small CSS block to hide lazyload elements for no-JS browsers.
396
+ */
397
+ function no_js_css() {
398
+ echo '<noscript><style>.lazyload[data-src]{display:none !important;}</style></noscript>';
399
+ }
400
+
401
  /**
402
  * Load full lazysizes script when SCRIPT_DEBUG is enabled.
403
  */
classes/class-exactdn.php CHANGED
@@ -867,14 +867,20 @@ class ExactDN extends EWWWIO_Page_Parser {
867
  $height = $filename_height;
868
  }
869
  // WP Attachment ID, if uploaded to this site.
870
- preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id );
 
 
 
 
871
  if ( ! ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) && empty( $attachment_id ) ) {
872
  ewwwio_debug_message( 'looking for attachment id' );
873
- $attachment_id = array( attachment_url_to_postid( $src ) );
874
  }
875
  if ( ! ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) && ! empty( $attachment_id ) ) {
876
- ewwwio_debug_message( 'using attachment id to get source image' );
877
- $attachment_id = intval( array_pop( $attachment_id ) );
 
 
878
 
879
  if ( $attachment_id ) {
880
  ewwwio_debug_message( "detected attachment $attachment_id" );
@@ -1130,6 +1136,9 @@ class ExactDN extends EWWWIO_Page_Parser {
1130
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1131
  $width = $filename_width;
1132
  }
 
 
 
1133
  if ( false !== strpos( $src, 'crop=' ) || false !== strpos( $src, '&h=' ) || false !== strpos( $src, '?h=' ) ) {
1134
  $width = false;
1135
  }
@@ -1148,6 +1157,10 @@ class ExactDN extends EWWWIO_Page_Parser {
1148
  }
1149
  } // End foreach().
1150
  } // End if();
 
 
 
 
1151
  if ( $this->filtering_the_page && ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ) {
1152
  ewwwio_debug_message( 'rewriting all other wp_content urls' );
1153
  if ( $this->exactdn_domain && $this->upload_domain ) {
@@ -1172,7 +1185,6 @@ class ExactDN extends EWWWIO_Page_Parser {
1172
  $content = str_replace( '?wpcontent-bypass?', 'wp-content', $content );
1173
  }
1174
  }
1175
- $content = $this->filter_bg_images( $content );
1176
  ewwwio_debug_message( 'done parsing page' );
1177
  $this->filtering_the_content = false;
1178
 
@@ -1189,7 +1201,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1189
  /**
1190
  * Parse page content looking for elements with CSS background-image properties.
1191
  *
1192
- * @param string $content The HTML content of to parse.
1193
  * @return string The filtered HTML content.
1194
  */
1195
  function filter_bg_images( $content ) {
@@ -1241,6 +1253,27 @@ class ExactDN extends EWWWIO_Page_Parser {
1241
  return $content;
1242
  }
1243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1244
  /**
1245
  * Allow resizing of images for some admin-ajax requests.
1246
  *
867
  $height = $filename_height;
868
  }
869
  // WP Attachment ID, if uploaded to this site.
870
+ $attachment_id = $this->get_attribute( $images['img_tag'][ $index ], 'data-id' );
871
+ if ( empty( $attachment_id ) ) {
872
+ ewwwio_debug_message( 'data-id not found, looking for wp-image-x in class' );
873
+ preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id );
874
+ }
875
  if ( ! ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) && empty( $attachment_id ) ) {
876
  ewwwio_debug_message( 'looking for attachment id' );
877
+ $attachment_id = attachment_url_to_postid( $src );
878
  }
879
  if ( ! ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) && ! empty( $attachment_id ) ) {
880
+ if ( is_array( $attachment_id ) ) {
881
+ $attachment_id = intval( array_pop( $attachment_id ) );
882
+ }
883
+ ewwwio_debug_message( "using attachment id ($attachment_id) to get source image" );
884
 
885
  if ( $attachment_id ) {
886
  ewwwio_debug_message( "detected attachment $attachment_id" );
1136
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1137
  $width = $filename_width;
1138
  }
1139
+ if ( empty( $width ) || ! is_numeric( $width ) ) {
1140
+ $width = $this->get_attribute( $images['img_tag'][ $index ], 'data-actual-width' );
1141
+ }
1142
  if ( false !== strpos( $src, 'crop=' ) || false !== strpos( $src, '&h=' ) || false !== strpos( $src, '?h=' ) ) {
1143
  $width = false;
1144
  }
1157
  }
1158
  } // End foreach().
1159
  } // End if();
1160
+ $content = $this->filter_bg_images( $content );
1161
+ if ( $this->filtering_the_page ) {
1162
+ $content = $this->filter_prz_thumb( $content );
1163
+ }
1164
  if ( $this->filtering_the_page && ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ) {
1165
  ewwwio_debug_message( 'rewriting all other wp_content urls' );
1166
  if ( $this->exactdn_domain && $this->upload_domain ) {
1185
  $content = str_replace( '?wpcontent-bypass?', 'wp-content', $content );
1186
  }
1187
  }
 
1188
  ewwwio_debug_message( 'done parsing page' );
1189
  $this->filtering_the_content = false;
1190
 
1201
  /**
1202
  * Parse page content looking for elements with CSS background-image properties.
1203
  *
1204
+ * @param string $content The HTML content to parse.
1205
  * @return string The filtered HTML content.
1206
  */
1207
  function filter_bg_images( $content ) {
1253
  return $content;
1254
  }
1255
 
1256
+ /**
1257
+ * Parse page content looking for thumburl from personalization.com.
1258
+ *
1259
+ * @param string $content The HTML content to parse.
1260
+ * @return string The filtered HTML content.
1261
+ */
1262
+ function filter_prz_thumb( $content ) {
1263
+ if ( ! class_exists( 'WooCommerce' ) || false === strpos( $content, 'productDetailsForPrz' ) ) {
1264
+ return $content;
1265
+ }
1266
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1267
+ $prz_match = preg_match( '#productDetailsForPrz=[^<]+?thumbnailUrl:\'([^\']+?)\'[^<]+?</script>#', $content, $prz_detail_matches );
1268
+ if ( $prz_match && ! empty( $prz_detail_matches[1] ) && $this->validate_image_url( $prz_detail_matches[1] ) ) {
1269
+ $prz_thumb = $this->generate_url( $prz_detail_matches[1], apply_filters( 'exactdn_personalizationdotcom_thumb_args', '', $prz_detail_matches[1] ) );
1270
+ if ( $prz_thumb != $prz_detail_matches ) {
1271
+ $content = str_replace( "thumbnailUrl:'{$prz_detail_matches[1]}'", "thumbnailUrl:'$prz_thumb'", $content );
1272
+ }
1273
+ }
1274
+ return $content;
1275
+ }
1276
+
1277
  /**
1278
  * Allow resizing of images for some admin-ajax requests.
1279
  *
common.php CHANGED
@@ -10,7 +10,7 @@
10
  * @package EWWW_Image_Optimizer
11
  */
12
 
13
- // TODO: might be able to use the Custom Bulk Actions in 4.7 to support the bulk optimize drop-down menu.
14
  // TODO: need to make the scheduler so it can resume without having to re-run the queue population, and then we can probably also flush the queue when scheduled opt starts, but later it would be nice to implement the bulk_loop as the aux_loop so that it could handle media properly.
15
  // TODO: Add a custom async function for parallel mode to store image as pending and use the row ID instead of relative path.
16
  // TODO: write some tests for AGR.
@@ -18,12 +18,11 @@
18
  // TODO: use this: https://codex.wordpress.org/AJAX_in_Plugins#The_post-load_JavaScript_Event .
19
  // TODO: can some of the bulk "fallbacks" be implemented for async processing?
20
  // TODO: check to see if we can use PHP and WP core is_iterable and is_countable functions.
21
- // TODO: ExactDN can use data-id attribute in 5.0 instead of trying to grok wp-image-1234 in the class.
22
  if ( ! defined( 'ABSPATH' ) ) {
23
  exit;
24
  }
25
 
26
- define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '470.0' );
27
 
28
  // Initialize a couple globals.
29
  $ewww_debug = '';
@@ -6446,6 +6445,14 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null, $r
6446
  }
6447
  $output .= "<div id='ewww-media-status-$id'>";
6448
  $ewww_cdn = false;
 
 
 
 
 
 
 
 
6449
  if ( is_array( $meta ) && ! empty( $meta['cloudinary'] ) ) {
6450
  $output .= esc_html__( 'Cloudinary image', 'ewww-image-optimizer' ) . '</div>';
6451
  if ( $return_output ) {
10
  * @package EWWW_Image_Optimizer
11
  */
12
 
13
+ // TODO: might be able to use the Custom Bulk Actions in WP 4.7 to support the bulk optimize drop-down menu.
14
  // TODO: need to make the scheduler so it can resume without having to re-run the queue population, and then we can probably also flush the queue when scheduled opt starts, but later it would be nice to implement the bulk_loop as the aux_loop so that it could handle media properly.
15
  // TODO: Add a custom async function for parallel mode to store image as pending and use the row ID instead of relative path.
16
  // TODO: write some tests for AGR.
18
  // TODO: use this: https://codex.wordpress.org/AJAX_in_Plugins#The_post-load_JavaScript_Event .
19
  // TODO: can some of the bulk "fallbacks" be implemented for async processing?
20
  // TODO: check to see if we can use PHP and WP core is_iterable and is_countable functions.
 
21
  if ( ! defined( 'ABSPATH' ) ) {
22
  exit;
23
  }
24
 
25
+ define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '471.0' );
26
 
27
  // Initialize a couple globals.
28
  $ewww_debug = '';
6445
  }
6446
  $output .= "<div id='ewww-media-status-$id'>";
6447
  $ewww_cdn = false;
6448
+ if ( is_array( $meta ) && ! empty( $meta['file'] ) && false !== strpos( $meta['file'], 'https://images-na.ssl-images-amazon.com' ) ) {
6449
+ $output .= esc_html__( 'Amazon-hosted image', 'ewww-image-optimizer' ) . '</div>';
6450
+ if ( $return_output ) {
6451
+ return $output;
6452
+ }
6453
+ echo $output;
6454
+ return;
6455
+ }
6456
  if ( is_array( $meta ) && ! empty( $meta['cloudinary'] ) ) {
6457
  $output .= esc_html__( 'Cloudinary image', 'ewww-image-optimizer' ) . '</div>';
6458
  if ( $return_output ) {
ewww-image-optimizer.php CHANGED
@@ -13,7 +13,7 @@ Plugin Name: EWWW Image Optimizer
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Reduce file sizes for images within WordPress including NextGEN Gallery and GRAND FlAGallery. Uses jpegtran, optipng/pngout, and gifsicle.
15
  Author: Exactly WWW
16
- Version: 4.7.0
17
  Author URI: https://ewww.io/
18
  License: GPLv3
19
  */
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Reduce file sizes for images within WordPress including NextGEN Gallery and GRAND FlAGallery. Uses jpegtran, optipng/pngout, and gifsicle.
15
  Author: Exactly WWW
16
+ Version: 4.7.1
17
  Author URI: https://ewww.io/
18
  License: GPLv3
19
  */
includes/lazysizes-post.js CHANGED
@@ -1,38 +1,66 @@
1
  lazysizesWebP('alpha', lazySizes.init);
2
- function constrainSrc(bg,objectWidth,objectHeight){
3
  var regW = /w=(\d+)/;
4
  var regFit = /fit=(\d+),(\d+)/;
5
  var regResize = /resize=(\d+),(\d+)/;
6
- if (bg.search('\\?') > 0 && bg.search(ewww_lazy_vars.exactdn_domain) > 0){
7
- var resultW = regW.exec(bg);
8
- if(resultW && objectWidth < resultW[1]){
9
- return bg.replace(regW, 'w=' + objectWidth);
10
  }
11
- var resultFit = regFit.exec(bg);
12
- if(resultFit && objectWidth < resultFit[1]){
13
- return bg.replace(regFit, 'fit=' + objectWidth + ',' + objectHeight);
14
  }
15
- var resultResize = regResize.exec(bg);
16
- if(resultResize && objectWidth < resultResize[1]){
17
- return bg.replace(regResize, 'resize=' + objectWidth + ',' + objectHeight);
18
  }
19
  if(!resultW && !resultFit && !resultResize){
20
- return bg + '&w=' + objectWidth;
21
- }
22
  }
23
- if (bg.search('\\?') == -1 && bg.search(ewww_lazy_vars.exactdn_domain) > 0){
24
- return bg + '?w=' + objectWidth;
25
  }
26
- return bg;
27
  }
28
  document.addEventListener('lazybeforeunveil', function(e){
29
  var target = e.target;
30
  //console.log('the target');
31
  //console.log(target);
32
  //console.log('loading an image');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  if(ewww_webp_supported) {
34
  //console.log('we could load webp');
35
- var srcset = target.getAttribute('data-srcset');
36
  //console.log(srcset);
37
  if (srcset && -1 < srcset.search('webp=1')){
38
  //console.log('srcset already contains webp ' + srcset);
1
  lazysizesWebP('alpha', lazySizes.init);
2
+ function constrainSrc(url,objectWidth,objectHeight){
3
  var regW = /w=(\d+)/;
4
  var regFit = /fit=(\d+),(\d+)/;
5
  var regResize = /resize=(\d+),(\d+)/;
6
+ if (url.search('\\?') > 0 && url.search(ewww_lazy_vars.exactdn_domain) > 0){
7
+ var resultResize = regResize.exec(url);
8
+ if(resultResize && objectWidth < resultResize[1]){
9
+ return url.replace(regResize, 'resize=' + objectWidth + ',' + objectHeight);
10
  }
11
+ var resultW = regW.exec(url);
12
+ if(resultW && objectWidth <= resultW[1]){
13
+ return url.replace(regW, 'resize=' + objectWidth + ',' + objectHeight);
14
  }
15
+ var resultFit = regFit.exec(url);
16
+ if(resultFit && objectWidth < resultFit[1]){
17
+ return url.replace(regFit, 'resize=' + objectWidth + ',' + objectHeight);
18
  }
19
  if(!resultW && !resultFit && !resultResize){
20
+ return url + '&resize=' + objectWidth + ',' + objectHeight;
21
+ }
22
  }
23
+ if (url.search('\\?') == -1 && url.search(ewww_lazy_vars.exactdn_domain) > 0){
24
+ return url + '?resize=' + objectWidth + ',' + objectHeight;
25
  }
26
+ return url;
27
  }
28
  document.addEventListener('lazybeforeunveil', function(e){
29
  var target = e.target;
30
  //console.log('the target');
31
  //console.log(target);
32
  //console.log('loading an image');
33
+ var wrongSize = false;
34
+ var srcset = target.getAttribute('data-srcset');
35
+ if ( ! srcset && target.naturalWidth) {
36
+ console.log('we have something');
37
+ if ((target.naturalWidth > 1) && (target.naturalHeight > 1)) {
38
+ // For each image with a natural width which isn't
39
+ // a 1x1 image, check its size.
40
+ var dPR = (window.devicePixelRatio || 1);
41
+ var wrongWidth = (target.clientWidth * 1.25 < target.naturalWidth);
42
+ var wrongHeight = (target.clientHeight * 1.25 < target.naturalHeight);
43
+ if (wrongWidth || wrongHeight) {
44
+ console.log(Math.round(target.clientWidth * dPR) + "x" + Math.round(target.clientHeight * dPR) + ", natural is " +
45
+ target.naturalWidth + "x" + target.naturalHeight + "!");
46
+ var targetWidth = Math.round(target.offsetWidth * dPR);
47
+ var targetHeight = Math.round(target.offsetHeight * dPR);
48
+
49
+ var src = target.getAttribute('data-src');
50
+ var webpsrc = target.getAttribute('data-src-webp');
51
+ if(ewww_webp_supported && webpsrc && -1 == src.search('webp=1')){
52
+ console.log('using data-src-webp');
53
+ src = webpsrc;
54
+ }
55
+ var newSrc = constrainSrc(src,targetWidth,targetHeight);
56
+ if (newSrc && src != newSrc){
57
+ target.setAttribute('data-src', newSrc);
58
+ }
59
+ }
60
+ }
61
+ }
62
  if(ewww_webp_supported) {
63
  //console.log('we could load webp');
 
64
  //console.log(srcset);
65
  if (srcset && -1 < srcset.search('webp=1')){
66
  //console.log('srcset already contains webp ' + srcset);
includes/lazysizes.js CHANGED
@@ -303,10 +303,6 @@
303
 
304
  var resetPreloading = function(e){
305
  isLoading--;
306
- if(e && e.target){
307
- addRemoveLoadEvents(e.target, resetPreloading);
308
- }
309
-
310
  if(!e || isLoading < 0 || !e.target){
311
  isLoading = 0;
312
  }
@@ -361,6 +357,8 @@
361
  docElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370 :
362
  lazySizesConfig.expand;
363
 
 
 
364
  preloadExpand = defaultExpand * lazySizesConfig.expFactor;
365
  hFac = lazySizesConfig.hFac;
366
  isBodyHidden = null;
@@ -420,10 +418,18 @@
420
  var throttledCheckElements = throttle(checkElements);
421
 
422
  var switchLoadingClass = function(e){
423
- addClass(e.target, lazySizesConfig.loadedClass);
424
- removeClass(e.target, lazySizesConfig.loadingClass);
425
- addRemoveLoadEvents(e.target, rafSwitchLoadingClass);
426
- triggerEvent(e.target, 'lazyloaded');
 
 
 
 
 
 
 
 
427
  };
428
  var rafedSwitchLoadingClass = rAFIt(switchLoadingClass);
429
  var rafSwitchLoadingClass = function(e){
@@ -477,12 +483,11 @@
477
 
478
  event = {target: elem};
479
 
 
 
480
  if(firesLoad){
481
- addRemoveLoadEvents(elem, resetPreloading, true);
482
  clearTimeout(resetPreloadingTimer);
483
  resetPreloadingTimer = setTimeout(resetPreloading, 2500);
484
-
485
- addClass(elem, lazySizesConfig.loadingClass);
486
  addRemoveLoadEvents(elem, rafSwitchLoadingClass, true);
487
  }
488
 
@@ -511,13 +516,15 @@
511
  removeClass(elem, lazySizesConfig.lazyClass);
512
 
513
  rAF(function(){
 
514
  if( !firesLoad || (elem.complete && elem.naturalWidth > 1)){
515
- if(firesLoad){
516
- resetPreloading(event);
517
- } else {
518
- isLoading--;
519
- }
520
  switchLoadingClass(event);
 
 
 
 
 
 
521
  }
522
  }, true);
523
  });
303
 
304
  var resetPreloading = function(e){
305
  isLoading--;
 
 
 
 
306
  if(!e || isLoading < 0 || !e.target){
307
  isLoading = 0;
308
  }
357
  docElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370 :
358
  lazySizesConfig.expand;
359
 
360
+ lazysizes._defEx = defaultExpand;
361
+
362
  preloadExpand = defaultExpand * lazySizesConfig.expFactor;
363
  hFac = lazySizesConfig.hFac;
364
  isBodyHidden = null;
418
  var throttledCheckElements = throttle(checkElements);
419
 
420
  var switchLoadingClass = function(e){
421
+ var elem = e.target;
422
+
423
+ if (elem._lazyCache) {
424
+ delete elem._lazyCache;
425
+ return;
426
+ }
427
+
428
+ resetPreloading(e);
429
+ addClass(elem, lazySizesConfig.loadedClass);
430
+ removeClass(elem, lazySizesConfig.loadingClass);
431
+ addRemoveLoadEvents(elem, rafSwitchLoadingClass);
432
+ triggerEvent(elem, 'lazyloaded');
433
  };
434
  var rafedSwitchLoadingClass = rAFIt(switchLoadingClass);
435
  var rafSwitchLoadingClass = function(e){
483
 
484
  event = {target: elem};
485
 
486
+ addClass(elem, lazySizesConfig.loadingClass);
487
+
488
  if(firesLoad){
 
489
  clearTimeout(resetPreloadingTimer);
490
  resetPreloadingTimer = setTimeout(resetPreloading, 2500);
 
 
491
  addRemoveLoadEvents(elem, rafSwitchLoadingClass, true);
492
  }
493
 
516
  removeClass(elem, lazySizesConfig.lazyClass);
517
 
518
  rAF(function(){
519
+ // Part of this can be removed as soon as this fix is older: https://bugs.chromium.org/p/chromium/issues/detail?id=7731 (2015)
520
  if( !firesLoad || (elem.complete && elem.naturalWidth > 1)){
 
 
 
 
 
521
  switchLoadingClass(event);
522
+ elem._lazyCache = true;
523
+ setTimeout(function(){
524
+ if ('_lazyCache' in elem) {
525
+ delete elem._lazyCache;
526
+ }
527
+ }, 9);
528
  }
529
  }, true);
530
  });
includes/lazysizes.min.js CHANGED
@@ -1 +1 @@
1
- var ewww_webp_supported=!1;function lazysizesWebP(e,t){var a=new Image;a.onload=function(){ewww_webp_supported=0<a.width&&0<a.height,t()},a.onerror=function(){t()},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function constrainSrc(e,t,a){var i=/w=(\d+)/,n=/fit=(\d+),(\d+)/,r=/resize=(\d+),(\d+)/;if(0<e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)){var o=i.exec(e);if(o&&t<o[1])return e.replace(i,"w="+t);var s=n.exec(e);if(s&&t<s[1])return e.replace(n,"fit="+t+","+a);var l=r.exec(e);if(l&&t<l[1])return e.replace(r,"resize="+t+","+a);if(!o&&!s&&!l)return e+"&w="+t}return-1==e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)?e+"?w="+t:e}window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.init=!1,function(e,t){var a=function(i,f){"use strict";if(!f.getElementsByClassName)return;var g,z,v=f.documentElement,r=i.Date,n=i.HTMLPictureElement,o="addEventListener",m="getAttribute",t=i[o],u=i.setTimeout,a=i.requestAnimationFrame||u,s=i.requestIdleCallback,A=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},p=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[m]("class")||"")&&d[t]},y=function(e,t){c(e,t)||e.setAttribute("class",(e[m]("class")||"").trim()+" "+t)},h=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[m]("class")||"").replace(a," "))},b=function(t,a,e){var i=e?o:"removeEventListener";e&&b(t,a),l.forEach(function(e){t[i](e,a)})},w=function(e,t,a,i,n){var r=f.createEvent("Event");return a||(a={}),a.instance=g,r.initEvent(t,!i,!n),r.detail=a,e.dispatchEvent(r),r},C=function(e,t){var a;!n&&(a=i.picturefill||z.pf)?(t&&t.src&&!e[m]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)},E=function(e,t){return(getComputedStyle(e,null)||{})[t]},_=function(e,t,a){for(a=a||e.offsetWidth;a<z.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},x=(L=[],M=[],N=L,R=function(){var e=N;for(N=L.length?M:L,W=!(S=!0);e.length;)e.shift()();S=!1},Q=function(e,t){S&&!t?e.apply(this,arguments):(N.push(e),W||(W=!0,(f.hidden?u:a)(R)))},Q._lsFlush=R,Q),e=function(a,e){return e?function(){x(a)}:function(){var e=this,t=arguments;x(function(){a.apply(e,t)})}},B=function(e){var t,a,i=function(){t=null,e()},n=function(){var e=r.now()-a;e<99?u(n,99-e):(s||i)(i)};return function(){a=r.now(),t||(t=u(n,99))}};var S,W,L,M,N,R,Q;!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in z=i.lazySizesConfig||i.lazysizesConfig||{},t)e in z||(z[e]=t[e]);i.lazySizesConfig=z,u(function(){z.init&&P()})}();var k=(se=/^img$/i,le=/^iframe$/i,de="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),ce=0,ue=0,Ae=-1,fe=function(e){ue--,e&&e.target&&b(e.target,fe),(!e||ue<0||!e.target)&&(ue=0)},ge=function(e){return null==Z&&(Z="hidden"==E(f.body,"visibility")),Z||"hidden"!=E(e.parentNode,"visibility")&&"hidden"!=E(e,"visibility")},ze=function(e,t){var a,i=e,n=ge(e);for(V-=t,K+=t,X-=t,Y+=t;n&&(i=i.offsetParent)&&i!=f.body&&i!=v;)(n=0<(E(i,"opacity")||1))&&"visible"!=E(i,"overflow")&&(a=i.getBoundingClientRect(),n=Y>a.left&&X<a.right&&K>a.top-1&&V<a.bottom+1);return n},ve=function(){var e,t,a,i,n,r,o,s,l,d,c,u,A=g.elements;if((G=z.loadMode)&&ue<8&&(e=A.length)){for(t=0,Ae++,d=!z.expand||z.expand<1?500<v.clientHeight&&500<v.clientWidth?500:370:z.expand,c=d*z.expFactor,u=z.hFac,Z=null,ce<c&&ue<1&&2<Ae&&2<G&&!f.hidden?(ce=c,Ae=0):ce=1<G&&1<Ae&&ue<6?d:0;t<e;t++)if(A[t]&&!A[t]._lazyRace)if(de)if((s=A[t][m]("data-expand"))&&(r=1*s)||(r=ce),l!==r&&(q=innerWidth+r*u,j=innerHeight+r,o=-1*r,l=r),a=A[t].getBoundingClientRect(),(K=a.bottom)>=o&&(V=a.top)<=j&&(Y=a.right)>=o*u&&(X=a.left)<=q&&(K||Y||X||V)&&(z.loadHidden||ge(A[t]))&&(J&&ue<3&&!s&&(G<3||Ae<4)||ze(A[t],r))){if(Ce(A[t]),n=!0,9<ue)break}else!n&&J&&!i&&ue<4&&Ae<4&&2<G&&(H[0]||z.preloadAfterLoad)&&(H[0]||!s&&(K||Y||X||V||"auto"!=A[t][m](z.sizesAttr)))&&(i=H[0]||A[t]);else Ce(A[t]);i&&!n&&Ce(i)}},ee=ve,ae=0,ie=z.throttleDelay,ne=z.ricTimeout,re=function(){te=!1,ae=r.now(),ee()},oe=s&&49<ne?function(){s(re,{timeout:ne}),ne!==z.ricTimeout&&(ne=z.ricTimeout)}:e(function(){u(re)},!0),me=function(e){var t;(e=!0===e)&&(ne=33),te||(te=!0,(t=ie-(r.now()-ae))<0&&(t=0),e||t<9?oe():u(oe,t))},pe=function(e){y(e.target,z.loadedClass),h(e.target,z.loadingClass),b(e.target,he),w(e.target,"lazyloaded")},ye=e(pe),he=function(e){ye({target:e.target})},be=function(e){var t,a=e[m](z.srcsetAttr);(t=z.customMedia[e[m]("data-media")||e[m]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},we=e(function(e,t,a,i,n){var r,o,s,l,d,c;(d=w(e,"lazybeforeunveil",t)).defaultPrevented||(i&&(a?y(e,z.autosizesClass):e.setAttribute("sizes",i)),o=e[m](z.srcsetAttr),r=e[m](z.srcAttr),n&&(s=e.parentNode,l=s&&A.test(s.nodeName||"")),c=t.firesLoad||"src"in e&&(o||r||l),d={target:e},c&&(b(e,fe,!0),clearTimeout(O),O=u(fe,2500),y(e,z.loadingClass),b(e,he,!0)),l&&p.call(s.getElementsByTagName("source"),be),o?e.setAttribute("srcset",o):r&&!l&&(le.test(e.nodeName)?function(t,a){try{t.contentWindow.location.replace(a)}catch(e){t.src=a}}(e,r):e.src=r),n&&(o||l)&&C(e,{src:r})),e._lazyRace&&delete e._lazyRace,h(e,z.lazyClass),x(function(){(!c||e.complete&&1<e.naturalWidth)&&(c?fe(d):ue--,pe(d))},!0)}),Ce=function(e){var t,a=se.test(e.nodeName),i=a&&(e[m](z.sizesAttr)||e[m]("sizes")),n="auto"==i;(!n&&J||!a||!e[m]("src")&&!e.srcset||e.complete||c(e,z.errorClass)||!c(e,z.lazyClass))&&(t=w(e,"lazyunveilread").detail,n&&D.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,ue++,we(e,t,n,i,a))},Ee=function(){if(!J)if(r.now()-$<999)u(Ee,999);else{var e=B(function(){z.loadMode=3,me()});J=!0,z.loadMode=3,me(),t("scroll",function(){3==z.loadMode&&(z.loadMode=2),e()},!0)}},{_:function(){$=r.now(),g.elements=f.getElementsByClassName(z.lazyClass),H=f.getElementsByClassName(z.lazyClass+" "+z.preloadClass),t("scroll",me,!0),t("resize",me,!0),i.MutationObserver?new MutationObserver(me).observe(v,{childList:!0,subtree:!0,attributes:!0}):(v[o]("DOMNodeInserted",me,!0),v[o]("DOMAttrModified",me,!0),setInterval(me,999)),t("hashchange",me,!0),["focus","mouseover","click","load","transitionend","animationend","webkitAnimationEnd"].forEach(function(e){f[o](e,me,!0)}),/d$|^c/.test(f.readyState)?Ee():(t("load",Ee),f[o]("DOMContentLoaded",me),u(Ee,2e4)),g.elements.length?(ve(),x._lsFlush()):me()},checkElems:me,unveil:Ce}),D=(F=e(function(e,t,a,i){var n,r,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),A.test(t.nodeName||""))for(n=t.getElementsByTagName("source"),r=0,o=n.length;r<o;r++)n[r].setAttribute("sizes",i);a.detail.dataAttr||C(e,a.detail)}),U=function(e,t,a){var i,n=e.parentNode;n&&(a=_(e,n,a),(i=w(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&F(e,n,i,a))},I=B(function(){var e,t=T.length;if(t)for(e=0;e<t;e++)U(T[e])}),{_:function(){T=f.getElementsByClassName(z.autosizesClass),t("resize",I)},checkElems:I,updateElem:U}),P=function(){P.i||(P.i=!0,D._(),k._())};var T,F,U,I;var H,J,O,G,$,q,j,V,X,Y,K,Z,ee,te,ae,ie,ne,re,oe,se,le,de,ce,ue,Ae,fe,ge,ze,ve,me,pe,ye,he,be,we,Ce,Ee;return g={cfg:z,autoSizer:D,loader:k,init:P,uP:C,aC:y,rC:h,hC:c,fire:w,gW:_,rAF:x}}(e,e.document);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}(window),lazysizesWebP("alpha",lazySizes.init),document.addEventListener("lazybeforeunveil",function(e){var t=e.target;if(ewww_webp_supported){var a=t.getAttribute("data-srcset");if(a&&-1<a.search("webp=1"))return;if(a){var i=t.getAttribute("data-srcset-webp");i&&t.setAttribute("data-srcset",i)}var n=t.getAttribute("data-src");if(n&&-1<n.search("webp=1"))return;var r=t.getAttribute("data-src-webp");if(!r)return;t.setAttribute("data-src",r)}}),function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,i,n){"use strict";var r,o;i.addEventListener&&(r=function(e,t){var a=i.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,i;e.detail.instance==n&&(e.defaultPrevented||("none"==e.target.preload&&(e.target.preload="auto"),(t=e.target.getAttribute("data-bg"))&&(ewww_webp_supported&&(a=e.target.getAttribute("data-bg-webp"))&&(t=a),t=constrainSrc(t,e.target.offsetWidth,e.target.offsetHeight),e.detail.firesLoad=!0,r(t,function(){e.target.style.backgroundImage="url("+(o.test(t)?JSON.stringify(t):t)+")",e.detail.firesLoad=!1,n.fire(e.target,"_lazyloaded",{},!0,!0)})),(i=e.target.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,r(i,function(){e.target.poster=i,e.detail.firesLoad=!1,n.fire(e.target,"_lazyloaded",{},!0,!0)}))))},!(o=/\(|\)|\s|'/)))});
1
+ var ewww_webp_supported=!1;function lazysizesWebP(e,t){var a=new Image;a.onload=function(){ewww_webp_supported=0<a.width&&0<a.height,t()},a.onerror=function(){t()},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function constrainSrc(e,t,a){var i=/w=(\d+)/,n=/fit=(\d+),(\d+)/,r=/resize=(\d+),(\d+)/;if(0<e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)){var o=r.exec(e);if(o&&t<o[1])return e.replace(r,"resize="+t+","+a);var s=i.exec(e);if(s&&t<=s[1])return e.replace(i,"resize="+t+","+a);var l=n.exec(e);if(l&&t<l[1])return e.replace(n,"resize="+t+","+a);if(!s&&!l&&!o)return e+"&resize="+t+","+a}return-1==e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)?e+"?resize="+t+","+a:e}window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.init=!1,function(e,t){var a=function(i,A){"use strict";if(!A.getElementsByClassName)return;var g,z,h=A.documentElement,r=i.Date,n=i.HTMLPictureElement,o="addEventListener",v="getAttribute",t=i[o],u=i.setTimeout,a=i.requestAnimationFrame||u,s=i.requestIdleCallback,f=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},p=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[v]("class")||"")&&d[t]},m=function(e,t){c(e,t)||e.setAttribute("class",(e[v]("class")||"").trim()+" "+t)},y=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[v]("class")||"").replace(a," "))},b=function(t,a,e){var i=e?o:"removeEventListener";e&&b(t,a),l.forEach(function(e){t[i](e,a)})},w=function(e,t,a,i,n){var r=A.createEvent("Event");return a||(a={}),a.instance=g,r.initEvent(t,!i,!n),r.detail=a,e.dispatchEvent(r),r},C=function(e,t){var a;!n&&(a=i.picturefill||z.pf)?(t&&t.src&&!e[v]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)},_=function(e,t){return(getComputedStyle(e,null)||{})[t]},E=function(e,t,a){for(a=a||e.offsetWidth;a<z.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},W=(B=[],R=[],L=B,N=function(){var e=L;for(L=B.length?R:B,S=!(M=!0);e.length;)e.shift()();M=!1},Q=function(e,t){M&&!t?e.apply(this,arguments):(L.push(e),S||(S=!0,(A.hidden?u:a)(N)))},Q._lsFlush=N,Q),e=function(a,e){return e?function(){W(a)}:function(){var e=this,t=arguments;W(function(){a.apply(e,t)})}},x=function(e){var t,a,i=function(){t=null,e()},n=function(){var e=r.now()-a;e<99?u(n,99-e):(s||i)(i)};return function(){a=r.now(),t||(t=u(n,99))}};var M,S,B,R,L,N,Q;!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in z=i.lazySizesConfig||i.lazysizesConfig||{},t)e in z||(z[e]=t[e]);i.lazySizesConfig=z,u(function(){z.init&&k()})}();var P=(se=/^img$/i,le=/^iframe$/i,de="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),ce=0,ue=0,fe=-1,Ae=function(e){ue--,(!e||ue<0||!e.target)&&(ue=0)},ge=function(e){return null==Z&&(Z="hidden"==_(A.body,"visibility")),Z||"hidden"!=_(e.parentNode,"visibility")&&"hidden"!=_(e,"visibility")},ze=function(e,t){var a,i=e,n=ge(e);for(V-=t,K+=t,X-=t,Y+=t;n&&(i=i.offsetParent)&&i!=A.body&&i!=h;)(n=0<(_(i,"opacity")||1))&&"visible"!=_(i,"overflow")&&(a=i.getBoundingClientRect(),n=Y>a.left&&X<a.right&&K>a.top-1&&V<a.bottom+1);return n},he=function(){var e,t,a,i,n,r,o,s,l,d,c,u,f=g.elements;if((G=z.loadMode)&&ue<8&&(e=f.length)){for(t=0,fe++,d=!z.expand||z.expand<1?500<h.clientHeight&&500<h.clientWidth?500:370:z.expand,g._defEx=d,c=d*z.expFactor,u=z.hFac,Z=null,ce<c&&ue<1&&2<fe&&2<G&&!A.hidden?(ce=c,fe=0):ce=1<G&&1<fe&&ue<6?d:0;t<e;t++)if(f[t]&&!f[t]._lazyRace)if(de)if((s=f[t][v]("data-expand"))&&(r=1*s)||(r=ce),l!==r&&(q=innerWidth+r*u,j=innerHeight+r,o=-1*r,l=r),a=f[t].getBoundingClientRect(),(K=a.bottom)>=o&&(V=a.top)<=j&&(Y=a.right)>=o*u&&(X=a.left)<=q&&(K||Y||X||V)&&(z.loadHidden||ge(f[t]))&&(J&&ue<3&&!s&&(G<3||fe<4)||ze(f[t],r))){if(Ce(f[t]),n=!0,9<ue)break}else!n&&J&&!i&&ue<4&&fe<4&&2<G&&(I[0]||z.preloadAfterLoad)&&(I[0]||!s&&(K||Y||X||V||"auto"!=f[t][v](z.sizesAttr)))&&(i=I[0]||f[t]);else Ce(f[t]);i&&!n&&Ce(i)}},ee=he,ae=0,ie=z.throttleDelay,ne=z.ricTimeout,re=function(){te=!1,ae=r.now(),ee()},oe=s&&49<ne?function(){s(re,{timeout:ne}),ne!==z.ricTimeout&&(ne=z.ricTimeout)}:e(function(){u(re)},!0),ve=function(e){var t;(e=!0===e)&&(ne=33),te||(te=!0,(t=ie-(r.now()-ae))<0&&(t=0),e||t<9?oe():u(oe,t))},pe=function(e){var t=e.target;t._lazyCache?delete t._lazyCache:(Ae(e),m(t,z.loadedClass),y(t,z.loadingClass),b(t,ye),w(t,"lazyloaded"))},me=e(pe),ye=function(e){me({target:e.target})},be=function(e){var t,a=e[v](z.srcsetAttr);(t=z.customMedia[e[v]("data-media")||e[v]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},we=e(function(e,t,a,i,n){var r,o,s,l,d,c;(d=w(e,"lazybeforeunveil",t)).defaultPrevented||(i&&(a?m(e,z.autosizesClass):e.setAttribute("sizes",i)),o=e[v](z.srcsetAttr),r=e[v](z.srcAttr),n&&(s=e.parentNode,l=s&&f.test(s.nodeName||"")),c=t.firesLoad||"src"in e&&(o||r||l),d={target:e},m(e,z.loadingClass),c&&(clearTimeout(O),O=u(Ae,2500),b(e,ye,!0)),l&&p.call(s.getElementsByTagName("source"),be),o?e.setAttribute("srcset",o):r&&!l&&(le.test(e.nodeName)?function(t,a){try{t.contentWindow.location.replace(a)}catch(e){t.src=a}}(e,r):e.src=r),n&&(o||l)&&C(e,{src:r})),e._lazyRace&&delete e._lazyRace,y(e,z.lazyClass),W(function(){(!c||e.complete&&1<e.naturalWidth)&&(pe(d),e._lazyCache=!0,u(function(){"_lazyCache"in e&&delete e._lazyCache},9))},!0)}),Ce=function(e){var t,a=se.test(e.nodeName),i=a&&(e[v](z.sizesAttr)||e[v]("sizes")),n="auto"==i;(!n&&J||!a||!e[v]("src")&&!e.srcset||e.complete||c(e,z.errorClass)||!c(e,z.lazyClass))&&(t=w(e,"lazyunveilread").detail,n&&H.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,ue++,we(e,t,n,i,a))},_e=function(){if(!J)if(r.now()-$<999)u(_e,999);else{var e=x(function(){z.loadMode=3,ve()});J=!0,z.loadMode=3,ve(),t("scroll",function(){3==z.loadMode&&(z.loadMode=2),e()},!0)}},{_:function(){$=r.now(),g.elements=A.getElementsByClassName(z.lazyClass),I=A.getElementsByClassName(z.lazyClass+" "+z.preloadClass),t("scroll",ve,!0),t("resize",ve,!0),i.MutationObserver?new MutationObserver(ve).observe(h,{childList:!0,subtree:!0,attributes:!0}):(h[o]("DOMNodeInserted",ve,!0),h[o]("DOMAttrModified",ve,!0),setInterval(ve,999)),t("hashchange",ve,!0),["focus","mouseover","click","load","transitionend","animationend","webkitAnimationEnd"].forEach(function(e){A[o](e,ve,!0)}),/d$|^c/.test(A.readyState)?_e():(t("load",_e),A[o]("DOMContentLoaded",ve),u(_e,2e4)),g.elements.length?(he(),W._lsFlush()):ve()},checkElems:ve,unveil:Ce}),H=(T=e(function(e,t,a,i){var n,r,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),f.test(t.nodeName||""))for(n=t.getElementsByTagName("source"),r=0,o=n.length;r<o;r++)n[r].setAttribute("sizes",i);a.detail.dataAttr||C(e,a.detail)}),F=function(e,t,a){var i,n=e.parentNode;n&&(a=E(e,n,a),(i=w(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&T(e,n,i,a))},U=x(function(){var e,t=D.length;if(t)for(e=0;e<t;e++)F(D[e])}),{_:function(){D=A.getElementsByClassName(z.autosizesClass),t("resize",U)},checkElems:U,updateElem:F}),k=function(){k.i||(k.i=!0,H._(),P._())};var D,T,F,U;var I,J,O,G,$,q,j,V,X,Y,K,Z,ee,te,ae,ie,ne,re,oe,se,le,de,ce,ue,fe,Ae,ge,ze,he,ve,pe,me,ye,be,we,Ce,_e;return g={cfg:z,autoSizer:H,loader:P,init:k,uP:C,aC:m,rC:y,hC:c,fire:w,gW:E,rAF:W}}(e,e.document);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}(window),lazysizesWebP("alpha",lazySizes.init),document.addEventListener("lazybeforeunveil",function(e){var t=e.target,a=t.getAttribute("data-srcset");if(!a&&t.naturalWidth&&(console.log("we have something"),1<t.naturalWidth&&1<t.naturalHeight)){var i=window.devicePixelRatio||1,n=1.25*t.clientWidth<t.naturalWidth,r=1.25*t.clientHeight<t.naturalHeight;if(n||r){console.log(Math.round(t.clientWidth*i)+"x"+Math.round(t.clientHeight*i)+", natural is "+t.naturalWidth+"x"+t.naturalHeight+"!");var o=Math.round(t.offsetWidth*i),s=Math.round(t.offsetHeight*i),l=t.getAttribute("data-src"),d=t.getAttribute("data-src-webp");ewww_webp_supported&&d&&-1==l.search("webp=1")&&(console.log("using data-src-webp"),l=d);var c=constrainSrc(l,o,s);c&&l!=c&&t.setAttribute("data-src",c)}}if(ewww_webp_supported){if(a&&-1<a.search("webp=1"))return;if(a){var u=t.getAttribute("data-srcset-webp");u&&t.setAttribute("data-srcset",u)}if((l=t.getAttribute("data-src"))&&-1<l.search("webp=1"))return;if(!(d=t.getAttribute("data-src-webp")))return;t.setAttribute("data-src",d)}}),function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(s,i,l){"use strict";var d,c;i.addEventListener&&(d=function(e,t){var a=i.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,i;if(e.detail.instance==l&&!e.defaultPrevented){if("none"==e.target.preload&&(e.target.preload="auto"),t=e.target.getAttribute("data-bg")){ewww_webp_supported&&(a=e.target.getAttribute("data-bg-webp"))&&(t=a);var n=s.devicePixelRatio||1,r=Math.round(e.target.offsetWidth*n),o=Math.round(e.target.offsetHeight*n);t=constrainSrc(t,r,o),e.detail.firesLoad=!0,d(t,function(){e.target.style.backgroundImage="url("+(c.test(t)?JSON.stringify(t):t)+")",e.detail.firesLoad=!1,l.fire(e.target,"_lazyloaded",{},!0,!0)})}(i=e.target.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,d(i,function(){e.target.poster=i,e.detail.firesLoad=!1,l.fire(e.target,"_lazyloaded",{},!0,!0)}))}},!(c=/\(|\)|\s|'/)))});
includes/ls.unveilhooks.js CHANGED
@@ -82,7 +82,10 @@ For background images, use data-bg attribute:
82
  bg = bgWebP;
83
  }
84
  }
85
- bg = constrainSrc(bg,e.target.offsetWidth,e.target.offsetHeight);
 
 
 
86
  e.detail.firesLoad = true;
87
  load = function(){
88
  e.target.style.backgroundImage = 'url(' + (regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg ) + ')';
82
  bg = bgWebP;
83
  }
84
  }
85
+ var dPR = (window.devicePixelRatio || 1);
86
+ var targetWidth = Math.round(e.target.offsetWidth * dPR);
87
+ var targetHeight = Math.round(e.target.offsetHeight * dPR);
88
+ bg = constrainSrc(bg,targetWidth,targetHeight);
89
  e.detail.firesLoad = true;
90
  load = function(){
91
  e.target.style.backgroundImage = 'url(' + (regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg ) + ')';
includes/resize_detection.js CHANGED
@@ -24,9 +24,10 @@ function checkImageScale(img) {
24
  if ((img.naturalWidth != 1) && (img.naturalHeight != 1)) {
25
  // For each image with a natural width which isn't
26
  // a 1x1 image, check its size.
27
- var wrongWidth = (img.clientWidth * 1.5 < img.naturalWidth);
28
- var wrongHeight = (img.clientHeight * 1.5 < img.naturalHeight);
29
- if (wrongWidth || wrongHeight) {
 
30
  img.classList.add('scaled-image');
31
  img.title = "Forced to wrong size: " +
32
  img.clientWidth + "x" + img.clientHeight + ", natural is " +
@@ -43,5 +44,6 @@ function clearScaledImages() {
43
  }
44
  document.addEventListener('lazyloaded', function(e){
45
  e.target.classList.remove('scaled-image');
 
46
  checkImageScale(e.target);
47
  });
24
  if ((img.naturalWidth != 1) && (img.naturalHeight != 1)) {
25
  // For each image with a natural width which isn't
26
  // a 1x1 image, check its size.
27
+ var dPR = (window.devicePixelRatio || 1);
28
+ var wrongWidth = (img.clientWidth * 1.5 * dPR < img.naturalWidth);
29
+ var wrongHeight = (img.clientHeight * 1.5 * dPR < img.naturalHeight);
30
+ if (wrongWidth || wrongHeight) {
31
  img.classList.add('scaled-image');
32
  img.title = "Forced to wrong size: " +
33
  img.clientWidth + "x" + img.clientHeight + ", natural is " +
44
  }
45
  document.addEventListener('lazyloaded', function(e){
46
  e.target.classList.remove('scaled-image');
47
+ e.target.title = '';
48
  checkImageScale(e.target);
49
  });
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: image, compress, resize, optimize, optimization, lossless, lossy, seo, web
5
  Requires at least: 4.9
6
  Tested up to: 5.1
7
  Requires PHP: 5.6
8
- Stable tag: 4.7.0
9
  License: GPLv3
10
 
11
  Speed up your website and improve your visitors' experience by automatically compressing and resizing images and PDFs. Boost SEO and improve sales.
@@ -174,6 +174,15 @@ http://developer.yahoo.com/performance/rules.html#opt_images
174
  * Feature requests can be viewed and submitted at https://github.com/nosilver4u/ewww-image-optimizer/labels/enhancement
175
  * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/
176
 
 
 
 
 
 
 
 
 
 
177
  = 4.7.0 =
178
  * added: lazy load (on ExactDN tab for now)
179
  * added: JS WebP supports background images via lazy load (div elements only for now)
5
  Requires at least: 4.9
6
  Tested up to: 5.1
7
  Requires PHP: 5.6
8
+ Stable tag: 4.7.1
9
  License: GPLv3
10
 
11
  Speed up your website and improve your visitors' experience by automatically compressing and resizing images and PDFs. Boost SEO and improve sales.
174
  * Feature requests can be viewed and submitted at https://github.com/nosilver4u/ewww-image-optimizer/labels/enhancement
175
  * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/
176
 
177
+ = 4.7.1 =
178
+ * added: CSS background image support for <li> elements
179
+ * added: ExactDN + Lazy Load will auto-calculate dimensions for img elements without srcset/responsive markup
180
+ * added: ExactDN parses thumbnail url for personalization.com + WooCommerce integration
181
+ * added: ExactDN can use data-actual-width attribute for srcset generation
182
+ * added: ExactDN + Lazy Load uses devicePixelRatio to provide clearer background images
183
+ * fixed: Lazy Load for CSS background images misfires when display height is greater than width
184
+ * fixed: visitors without JS see Lazy Load placeholder + fallback image
185
+
186
  = 4.7.0 =
187
  * added: lazy load (on ExactDN tab for now)
188
  * added: JS WebP supports background images via lazy load (div elements only for now)