ShortPixel Image Optimizer - Version 4.5.0

Version Description

  • replace img tags in front-end with picture tags, and include the webp images
  • actions menu in Media Library
  • option to compare the optimized (main) image with the original in Media Library
Download this release

Release Info

Developer ShortPixel
Plugin Icon 128x128 ShortPixel Image Optimizer
Version 4.5.0
Comparing to
See all releases

Code changes from version 4.4.2 to 4.5.0

class/db/shortpixel-meta-facade.php CHANGED
@@ -261,11 +261,11 @@ class ShortPixelMetaFacade {
261
  }
262
 
263
  public static function safeGetAttachmentUrl($id) {
264
- $attURL = wp_get_attachment_url($id);
265
  if(!$attURL || !strlen($attURL)) {
266
  throw new Exception("Post metadata is corrupt (No attachment URL)");
267
  }
268
- if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
269
  return get_site_url() . $attURL;//get the file URL
270
  }
271
  else {
261
  }
262
 
263
  public static function safeGetAttachmentUrl($id) {
264
+ $attURL = wp_get_attachment_url($id);
265
  if(!$attURL || !strlen($attURL)) {
266
  throw new Exception("Post metadata is corrupt (No attachment URL)");
267
  }
268
+ if ( !parse_url($attURL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
269
  return get_site_url() . $attURL;//get the file URL
270
  }
271
  else {
class/front/img-to-picture-webp.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class ImgToPictureWebp - convert an <img> tag to a <picture> tag and add the webp versions of the images
4
+ * thanks to the Responsify WP plugin for some of the code
5
+ */
6
+
7
+ class ImgToPictureWebp {
8
+
9
+ public static function convert($content) {
10
+ // Don't do anything with the RSS feed.
11
+ if ( is_feed() || is_admin() ) { return $content; }
12
+
13
+ return preg_replace_callback('/<img[^>]*>/', function ($match) {
14
+ // Do nothing with images that has the 'rwp-not-responsive' class.
15
+ if ( strpos($match[0], 'sp-no-webp') ) { return $match[0]; }
16
+
17
+ $img = self::get_attributes($match[0]);
18
+
19
+ $src = (isset($img['src'])) ? $img['src'] : false;
20
+ $srcset = (isset($img['srcset'])) ? $img['srcset'] : false;
21
+ $sizes = (isset($img['sizes'])) ? $img['sizes'] : false;
22
+
23
+ //check if there are webps
24
+ $id = self::url_to_attachment_id( $src );
25
+ if(!$id) { return $match[0]; }
26
+
27
+ $imageBase = dirname(get_attached_file($id)) . '/';
28
+
29
+ // We don't wanna have an src attribute on the <img>
30
+ unset($img['src']);
31
+ //unset($img['srcset']);
32
+ //unset($img['sizes']);
33
+
34
+ $srcsetWebP = '';
35
+ if($srcset) {
36
+ $defs = explode(",", $srcset);
37
+ foreach($defs as $item) {
38
+ $parts = preg_split('/\s+/', trim($item));
39
+
40
+ //echo(" file: " . $parts[0] . " ext: " . pathinfo($parts[0], PATHINFO_EXTENSION) . " basename: " . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)));
41
+
42
+ $fileWebP = $imageBase . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)) . '.webp';
43
+ if(file_exists($fileWebP)) {
44
+ $srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
45
+ . preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $parts[0])
46
+ . (isset($parts[1]) ? ' ' . $parts[1] : '');
47
+ }
48
+ }
49
+ //$srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+\s+/', '.webp ', $srcset);
50
+ } else {
51
+ $srcset = trim($src);
52
+
53
+ // die(var_dump($match));
54
+
55
+ $fileWebP = $imageBase . wp_basename($srcset, '.' . pathinfo($srcset, PATHINFO_EXTENSION)) . '.webp';
56
+ if(file_exists($fileWebP)) {
57
+ $srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $srcset);
58
+ }
59
+ }
60
+ if(!strlen($srcsetWebP)) { return $match[0]; }
61
+
62
+ return '<picture>'
63
+ .'<source srcset="' . $srcsetWebP . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . ' type="image/webp">'
64
+ .'<source srcset="' . $srcset . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . '>'
65
+ .'<img src="' . $src . '" ' . self::create_attributes($img) . '>'
66
+ .'</picture>';
67
+ }, $content);
68
+ }
69
+
70
+ protected static function get_attributes( $image_node )
71
+ {
72
+ $image_node = mb_convert_encoding($image_node, 'HTML-ENTITIES', 'UTF-8');
73
+ $dom = new DOMDocument();
74
+ @$dom->loadHTML($image_node);
75
+ $image = $dom->getElementsByTagName('img')->item(0);
76
+ $attributes = array();
77
+ foreach ( $image->attributes as $attr ) {
78
+ $attributes[$attr->nodeName] = $attr->nodeValue;
79
+ }
80
+ return $attributes;
81
+ }
82
+
83
+ /**
84
+ * Makes a string with all attributes.
85
+ *
86
+ * @param $attribute_array
87
+ * @return string
88
+ */
89
+ protected static function create_attributes( $attribute_array )
90
+ {
91
+ $attributes = '';
92
+ foreach ($attribute_array as $attribute => $value) {
93
+ $attributes .= $attribute . '="' . $value . '" ';
94
+ }
95
+ // Removes the extra space after the last attribute
96
+ return substr($attributes, 0, -1);
97
+ }
98
+
99
+ /**
100
+ * @param $image_url
101
+ * @return array
102
+ */
103
+ public static function url_to_attachment_id ( $image_url ) {
104
+ // Thx to https://github.com/kylereicks/picturefill.js.wp/blob/master/inc/class-model-picturefill-wp.php
105
+ global $wpdb;
106
+ $original_image_url = $image_url;
107
+ $image_url = preg_replace('/^(.+?)(-\d+x\d+)?\.(jpg|jpeg|png|gif)((?:\?|#).+)?$/i', '$1.$3', $image_url);
108
+ $prefix = $wpdb->prefix;
109
+ $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $image_url ));
110
+ if ( !empty($attachment_id) ) {
111
+ return $attachment_id[0];
112
+ } else {
113
+ $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $original_image_url ));
114
+ }
115
+ return !empty($attachment_id) ? $attachment_id[0] : false;
116
+ }
117
+
118
+ }
class/view/shortpixel_view.php CHANGED
@@ -333,9 +333,7 @@ class ShortPixelView {
333
  <?php }
334
  $settings = $this->ctrl->getSettings();
335
  $optType = ShortPixelAPI::getCompressionTypeName($settings->compressionType);
336
- $otherType = ShortPixelAPI::getCompressionTypeName($this->ctrl->getOtherCompressionType($settings->compressionType));
337
- $otherType2 = array_diff(array('lossy', 'glossy', 'lossless'), array($optType, $otherType));
338
- $otherType2 = reset($otherType2);
339
  $extraW = $extraO = '';
340
  if( !$this->ctrl->backupFolderIsEmpty()
341
  && ( ($quotaData['totalProcLossyFiles'] > 0 && $settings->compressionType != 1)
@@ -343,20 +341,20 @@ class ShortPixelView {
343
  || ($quotaData['totalProcLosslessFiles'] > 0 && $settings->compressionType != 0)))
344
  {
345
  $todo = $reopt = true;
346
- $statType = ucfirst($otherType);
347
  $thumbsCount = $quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files'];
348
 
349
- $statType2 = ucfirst($otherType2);
350
  $thumbsCount2 = $quotaData['totalProc'.$statType2.'Files'] - $quotaData['mainProc'.$statType2.'Files'];
351
  if($quotaData['totalProc'.$statType2.'Files'] > 0 ) {
352
  if($quotaData['totalProc'.$statType.'Files'] > 0) {
353
  $extraW = sprintf(__('%s images and %s thumbnails were optimized <strong>%s</strong>. ','shortpixel-image-optimiser'),
354
  number_format($quotaData['mainProc'.$statType2.'Files']),
355
- number_format($thumbsCount2), $otherType2);
356
  $extraO = sprintf(__('%s images were optimized <strong>%s</strong>. ','shortpixel-image-optimiser'),
357
- number_format($quotaData['mainProc'.$statType2.'Files']), $otherType2);
358
  } else {
359
- $extraW = $extraO = ''; $otherType = $otherType2; $statType = $statType2;
360
  }
361
  }
362
  ?>
@@ -364,13 +362,13 @@ class ShortPixelView {
364
  <?php echo($extraW);
365
  printf(__('%s images and %s thumbnails were optimized <strong>%s</strong>. You can re-optimize <strong>%s</strong> the ones that have backup.','shortpixel-image-optimiser'),
366
  number_format($quotaData['mainProc'.$statType.'Files']),
367
- number_format($thumbsCount), $otherType, $optType);?>
368
  </p>
369
  <p id="without-thumbs" <?php echo($settings->processThumbnails ? 'style="display:none;"' : "");?>>
370
  <?php echo($extraO);
371
  printf(__('%s images were optimized <strong>%s</strong>. You can re-optimize <strong>%s</strong> the ones that have backup. ','shortpixel-image-optimiser'),
372
  number_format($quotaData['mainProc'.$statType.'Files']),
373
- $otherType, $optType);?>
374
  <?php echo($thumbsCount + $thumbsCount2 ? number_format($thumbsCount + $thumbsCount2) . __(' thumbnails will be restored to originals.','shortpixel-image-optimiser') : '');?>
375
  </p>
376
  <?php
@@ -823,6 +821,7 @@ class ShortPixelView {
823
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
824
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
825
  $createWebp = ($settings->createWebp ? 'checked' : '');
 
826
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
827
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
828
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
@@ -910,9 +909,9 @@ class ShortPixelView {
910
  <p class="settings-info">
911
  <?php _e('Use the Select... button to select site folders. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.','shortpixel-image-optimiser');?>
912
  </p>
913
- <div class="sp-folder-picker-shade">
914
- <div class="sp-folder-picker-popup">
915
- <div class="sp-folder-picker-title"><?php _e('Select the images folder','shortpixel-image-optimiser');?></div>
916
  <div class="sp-folder-picker"></div>
917
  <input type="button" class="button button-info select-folder-cancel" value="<?php _e('Cancel','shortpixel-image-optimiser');?>" style="margin-right: 30px;">
918
  <input type="button" class="button button-primary select-folder" value="<?php _e('Select','shortpixel-image-optimiser');?>">
@@ -945,6 +944,15 @@ class ShortPixelView {
945
  </p>
946
  </td>
947
  </tr>
 
 
 
 
 
 
 
 
 
948
  <tr>
949
  <th scope="row"><label for="optimizeRetina"><?php _e('Optimize Retina images','shortpixel-image-optimiser');?></label></th>
950
  <td>
@@ -1171,7 +1179,7 @@ class ShortPixelView {
1171
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1172
  . $missingThumbs;
1173
  }
1174
- $this->renderListCell($id, $data['showActions'],
1175
  !$data['thumbsOpt'] && $data['thumbsTotal'], $data['thumbsTotal'], $data['backup'], $data['type'], $data['invType'], $successText);
1176
 
1177
  break;
@@ -1194,27 +1202,39 @@ class ShortPixelView {
1194
  .($retinasOpt ? '<br>' . sprintf(__('+%s Retina images optimized','shortpixel-image-optimiser') , $retinasOpt) : '' ) ;
1195
  }
1196
 
1197
- public function renderListCell($id, $showActions, $optimizeThumbs, $thumbsTotal, $backup, $type, $invType, $message) {
1198
  if($showActions) { ?>
1199
- <div class='sp-column-actions'>
1200
- <?php if($optimizeThumbs) { ?>
1201
- <a class='button button-smaller button-primary' href="javascript:optimizeThumbs(<?php echo($id)?>);">
1202
- <?php printf(__('Optimize %s thumbnails','shortpixel-image-optimiser'),$thumbsTotal);?>
1203
- </a>
1204
- <?php }
1205
- if($backup) {
1206
- if($type) {
1207
- //$invType = $type == 'lossy' ? 'lossless' : 'lossy'; ?>
1208
- <a class='button button-smaller' href="javascript:reoptimize('<?php echo($id)?>', '<?php echo($invType)?>');"
1209
- title="<?php _e('Reoptimize from the backed-up image','shortpixel-image-optimiser');?>">
1210
- <?php _e('Re-optimize','shortpixel-image-optimiser');?> <?php echo($invType)?>
1211
- </a><?php
1212
- } ?>
1213
- <a class='button button-smaller' href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>">
1214
- <?php _e('Restore backup','shortpixel-image-optimiser');?>
1215
- </a>
1216
- <?php } ?>
1217
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
1218
  <?php } ?>
1219
  <div class='sp-column-info'>
1220
  <?php echo($message);?>
@@ -1231,4 +1251,42 @@ class ShortPixelView {
1231
  "</a></div>
1232
  <div class='sp-column-info'>" . $message . " Quota Exceeded.</div>";
1233
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1234
  }
333
  <?php }
334
  $settings = $this->ctrl->getSettings();
335
  $optType = ShortPixelAPI::getCompressionTypeName($settings->compressionType);
336
+ $otherTypes = ShortPixelAPI::getCompressionTypeName($this->ctrl->getOtherCompressionTypes($settings->compressionType));
 
 
337
  $extraW = $extraO = '';
338
  if( !$this->ctrl->backupFolderIsEmpty()
339
  && ( ($quotaData['totalProcLossyFiles'] > 0 && $settings->compressionType != 1)
341
  || ($quotaData['totalProcLosslessFiles'] > 0 && $settings->compressionType != 0)))
342
  {
343
  $todo = $reopt = true;
344
+ $statType = ucfirst($otherTypes[0]);
345
  $thumbsCount = $quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files'];
346
 
347
+ $statType2 = ucfirst($otherTypes[1]);
348
  $thumbsCount2 = $quotaData['totalProc'.$statType2.'Files'] - $quotaData['mainProc'.$statType2.'Files'];
349
  if($quotaData['totalProc'.$statType2.'Files'] > 0 ) {
350
  if($quotaData['totalProc'.$statType.'Files'] > 0) {
351
  $extraW = sprintf(__('%s images and %s thumbnails were optimized <strong>%s</strong>. ','shortpixel-image-optimiser'),
352
  number_format($quotaData['mainProc'.$statType2.'Files']),
353
+ number_format($thumbsCount2), $otherTypes[1]);
354
  $extraO = sprintf(__('%s images were optimized <strong>%s</strong>. ','shortpixel-image-optimiser'),
355
+ number_format($quotaData['mainProc'.$statType2.'Files']), $otherTypes[1]);
356
  } else {
357
+ $extraW = $extraO = ''; $otherTypes[0] = $otherTypes[1]; $statType = $statType2;
358
  }
359
  }
360
  ?>
362
  <?php echo($extraW);
363
  printf(__('%s images and %s thumbnails were optimized <strong>%s</strong>. You can re-optimize <strong>%s</strong> the ones that have backup.','shortpixel-image-optimiser'),
364
  number_format($quotaData['mainProc'.$statType.'Files']),
365
+ number_format($thumbsCount), $otherTypes[0], $optType);?>
366
  </p>
367
  <p id="without-thumbs" <?php echo($settings->processThumbnails ? 'style="display:none;"' : "");?>>
368
  <?php echo($extraO);
369
  printf(__('%s images were optimized <strong>%s</strong>. You can re-optimize <strong>%s</strong> the ones that have backup. ','shortpixel-image-optimiser'),
370
  number_format($quotaData['mainProc'.$statType.'Files']),
371
+ $otherTypes[0], $optType);?>
372
  <?php echo($thumbsCount + $thumbsCount2 ? number_format($thumbsCount + $thumbsCount2) . __(' thumbnails will be restored to originals.','shortpixel-image-optimiser') : '');?>
373
  </p>
374
  <?php
821
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
822
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
823
  $createWebp = ($settings->createWebp ? 'checked' : '');
824
+ $createWebpMarkup = ($settings->createWebpMarkup ? 'checked' : '');
825
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
826
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
827
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
909
  <p class="settings-info">
910
  <?php _e('Use the Select... button to select site folders. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.','shortpixel-image-optimiser');?>
911
  </p>
912
+ <div class="sp-modal-shade">
913
+ <div class="shortpixel-modal">
914
+ <div class="sp-modal-title"><?php _e('Select the images folder','shortpixel-image-optimiser');?></div>
915
  <div class="sp-folder-picker"></div>
916
  <input type="button" class="button button-info select-folder-cancel" value="<?php _e('Cancel','shortpixel-image-optimiser');?>" style="margin-right: 30px;">
917
  <input type="button" class="button button-primary select-folder" value="<?php _e('Select','shortpixel-image-optimiser');?>">
944
  </p>
945
  </td>
946
  </tr>
947
+ <tr>
948
+ <th scope="row"><label for="createWebpMarkup"><?php _e('Generate WebP markup','shortpixel-image-optimiser');?></label></th>
949
+ <td>
950
+ <input name="createWebpMarkup" type="checkbox" id="createWebpMarkup" <?php echo( $createWebpMarkup );?>> <?php _e('Generate the &lt;picture&gt; markup in the front-end.','shortpixel-image-optimiser');?>
951
+ <p class="settings-info">
952
+ <?php _e('Each &lt;img&gt; will be replaced with a &lt;picture&gt; tag that will also provide the WebP image as a choice for browsers that support it. Also loads the picturefill.js for browsers that don\'t support the &lt;picture&gt; tag. You don\'t need to activate this if you\'re using the Cache Enabler plugin because your WebP images are already handled by this plugin. <strong>Please make a test before using this option</strong>, as if the styles that your theme is using rely on the position of your &lt;img&gt; tag, you might experience display problems.','shortpixel-image-optimiser');?>
953
+ </p>
954
+ </td>
955
+ </tr>
956
  <tr>
957
  <th scope="row"><label for="optimizeRetina"><?php _e('Optimize Retina images','shortpixel-image-optimiser');?></label></th>
958
  <td>
1179
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1180
  . $missingThumbs;
1181
  }
1182
+ $this->renderListCell($id, $data['status'], $data['showActions'],
1183
  !$data['thumbsOpt'] && $data['thumbsTotal'], $data['thumbsTotal'], $data['backup'], $data['type'], $data['invType'], $successText);
1184
 
1185
  break;
1202
  .($retinasOpt ? '<br>' . sprintf(__('+%s Retina images optimized','shortpixel-image-optimiser') , $retinasOpt) : '' ) ;
1203
  }
1204
 
1205
+ public function renderListCell($id, $status, $showActions, $optimizeThumbs, $thumbsTotal, $backup, $type, $invType, $message, $extraClass = '') {
1206
  if($showActions) { ?>
1207
+ <div class='sp-column-actions <?php echo($extraClass);?>'>
1208
+ <div class="sp-dropdown">
1209
+ <button onclick="ShortPixel.openImageMenu(event);" class="sp-dropbtn button <?php if($optimizeThumbs) { echo('button-primary'); } ?> dashicons dashicons-menu" title="ShortPixel Actions"></button>
1210
+ <div id="sp-dd-<?php echo($id);?>" class="sp-dropdown-content">
1211
+ <?php if($status == 'imgOptimized') { ?>
1212
+ <a class="sp-action-compare" href="javascript:ShortPixel.loadComparer('<?php echo($id);?>')" title="Compare optimized image with the original">Compare</a>
1213
+ <?php } ?>
1214
+ <?php if($optimizeThumbs) { ?>
1215
+ <a class="sp-action-optimize-thumbs" href="javascript:optimizeThumbs(<?php echo($id)?>);" style="background-color:#0085ba;color:white;">
1216
+ <?php printf(__('Optimize %s thumbnails','shortpixel-image-optimiser'),$thumbsTotal);?>
1217
+ </a>
1218
+ <?php }
1219
+ if($backup) {
1220
+ if($type) {
1221
+ //$invType = $type == 'lossy' ? 'lossless' : 'lossy'; ?>
1222
+ <a class="sp-action-reoptimize1" href="javascript:reoptimize('<?php echo($id)?>', '<?php echo($invType[0])?>');"
1223
+ title="<?php _e('Reoptimize from the backed-up image','shortpixel-image-optimiser');?>">
1224
+ <?php _e('Re-optimize','shortpixel-image-optimiser');?> <?php echo($invType[0])?>
1225
+ </a>
1226
+ <a class="sp-action-reoptimize2" href="javascript:reoptimize('<?php echo($id)?>', '<?php echo($invType[1])?>');"
1227
+ title="<?php _e('Reoptimize from the backed-up image','shortpixel-image-optimiser');?>">
1228
+ <?php _e('Re-optimize','shortpixel-image-optimiser');?> <?php echo($invType[1])?>
1229
+ </a><?php
1230
+ } ?>
1231
+ <a class="sp-action-restore" href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>">
1232
+ <?php _e('Restore backup','shortpixel-image-optimiser');?>
1233
+ </a>
1234
+ <?php } ?>
1235
+ </div>
1236
+ </div>
1237
+ </div>
1238
  <?php } ?>
1239
  <div class='sp-column-info'>
1240
  <?php echo($message);?>
1251
  "</a></div>
1252
  <div class='sp-column-info'>" . $message . " Quota Exceeded.</div>";
1253
  }
1254
+
1255
+ public function outputComparerHTML() {?>
1256
+ <div class="sp-modal-shade">
1257
+ <div id="spUploadCompare" class="shortpixel-modal shortpixel-hide">
1258
+ <div class="sp-modal-title">
1259
+ <button type="button" class="sp-close-button">&times;</button>
1260
+ Compare Images
1261
+ </div>
1262
+ <div class="sp-modal-body sptw-modal-spinner" style="height:400px;padding:0;">
1263
+ <div class="shortpixel-slider" style="z-index:2000;">
1264
+ <div class="twentytwenty-container" id="spCompareSlider">
1265
+ <img class="spUploadCompareOriginal"/>
1266
+ <img class="spUploadCompareOptimized"/>
1267
+ </div>
1268
+ </div>
1269
+ </div>
1270
+ </div>
1271
+ <div id="spUploadCompareSideBySide" class="shortpixel-modal shortpixel-hide">
1272
+ <div class="sp-modal-title">
1273
+ <button type="button" class="sp-close-button">&times;</button>
1274
+ Compare Images
1275
+ </div>
1276
+ <div class="sp-modal-body" style="height:400px;padding:0;">
1277
+ <div class="shortpixel-slider"style="text-align: center;">
1278
+ <div class="side-by-side" style="text-align: center; display:inline-block;">
1279
+ <img class="spUploadCompareOriginal" style="margin: 10px"/><br>
1280
+ Original
1281
+ </div>
1282
+ <div class="side-by-side" style="text-align: center; display:inline-block;">
1283
+ <img class="spUploadCompareOptimized" style="margin: 10px"/><br>
1284
+ Optimized
1285
+ </div>
1286
+ </div>
1287
+ </div>
1288
+ </div>
1289
+ </div>
1290
+ <?php
1291
+ }
1292
  }
class/wp-short-pixel.php CHANGED
@@ -74,6 +74,7 @@ class WPShortPixel {
74
 
75
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
76
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
 
77
 
78
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
79
  add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
@@ -245,7 +246,16 @@ class WPShortPixel {
245
  }
246
  }
247
 
248
- function shortPixelJS() { ?>
 
 
 
 
 
 
 
 
 
249
  <script type="text/javascript" >
250
  var ShortPixelConstants = {
251
  STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
@@ -267,9 +277,9 @@ class WPShortPixel {
267
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
268
  };
269
  </script> <?php
270
- wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',SHORTPIXEL_PLUGIN_FILE) );
271
 
272
- wp_register_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',SHORTPIXEL_PLUGIN_FILE) );
273
  $jsTranslation = array(
274
  'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
275
  'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
@@ -306,7 +316,7 @@ class WPShortPixel {
306
  $id = 'short-pixel-notice-toolbar';
307
  $tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
308
  $icon = "shortpixel.png";
309
- $successLink = $link = current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php';
310
  $blank = "";
311
  if($this->prioQ->processing()) {
312
  $extraClasses = " shortpixel-processing";
@@ -950,7 +960,7 @@ class WPShortPixel {
950
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
951
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
952
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
953
-
954
  $meta = $itemHandler->getMeta();
955
  //find thumbs that are not listed in the metadata and add them in the sizes array
956
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
@@ -1202,7 +1212,8 @@ class WPShortPixel {
1202
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
1203
  foreach($duplicates as $ID) {
1204
  $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
1205
- if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
 
1206
  $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
1207
  }
1208
  unset($crtMeta["ShortPixelImprovement"]);
@@ -1685,6 +1696,26 @@ class WPShortPixel {
1685
  die();
1686
  }
1687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1688
  public static function getCustomFolderBase() {
1689
  if(is_main_site()) {
1690
  $base = get_home_path();
@@ -1873,6 +1904,7 @@ class WPShortPixel {
1873
  }
1874
 
1875
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
 
1876
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1877
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
1878
 
@@ -2183,7 +2215,7 @@ class WPShortPixel {
2183
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2184
  $renderData['backup'] = $this->getBackupFolderAny($file, $sizesCount? $data['sizes'] : array());
2185
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2186
- $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionType(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
2187
  $renderData['thumbsTotal'] = $sizesCount;
2188
  $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
2189
  $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
@@ -2283,8 +2315,10 @@ class WPShortPixel {
2283
  public function columns( $defaults ) {
2284
  $defaults['wp-shortPixel'] = 'ShortPixel Compression';
2285
  if(current_user_can( 'manage_options' )) {
2286
- $defaults['wp-shortPixel'] .= '&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="'
2287
- . __('ShortPixel Statistics','shortpixel-image-optimiser') . '"><span class="dashicons dashicons-dashboard"></span></a>';
 
 
2288
  }
2289
  return $defaults;
2290
  }
@@ -2530,15 +2564,8 @@ class WPShortPixel {
2530
  return array('width' => max(100, $width), 'height' => max(100, $height));
2531
  }
2532
 
2533
- public function getOtherCompressionType($compressionType = false) {
2534
- $defCompType = 0 + $this->getCompressionType();
2535
- if($compressionType === false) {
2536
- return $defCompType == 1 ? 2 : $defCompType == 2 ? 0 : 1;
2537
- }
2538
- elseif($defCompType == 0 || $defCompType == 2) {
2539
- return (0 + $compressionType == 0 ? 2 : 0);
2540
- }
2541
- return $compressionType == 1 ? 0 : 1;
2542
  }
2543
 
2544
  /* public function getEncryptedData() {
74
 
75
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
76
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
77
+ add_action('wp_ajax_shortpixel_get_comparer_data', array(&$this, 'getComparerData'));
78
 
79
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
80
  add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
246
  }
247
  }
248
 
249
+ function shortPixelJS() {
250
+ $screen = get_current_screen();
251
+ if($screen->id == 'upload') {
252
+ //output the comparer html
253
+ $this->view->outputComparerHTML();
254
+ //render a template of the list cell to be used by the JS
255
+ $this->view->renderListCell("__SP_ID__", 'imgOptimized', true, true, "__SP_THUMBS_TOTAL__", true, true,
256
+ array("__SP_FIRST_TYPE__", "__SP_SECOND_TYPE__"), "__SP_CELL_MESSAGE__", 'sp-column-actions-template');
257
+ }
258
+ ?>
259
  <script type="text/javascript" >
260
  var ShortPixelConstants = {
261
  STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
277
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
278
  };
279
  </script> <?php
280
+ wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',SHORTPIXEL_PLUGIN_FILE), array(), PLUGIN_VERSION);
281
 
282
+ wp_register_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',SHORTPIXEL_PLUGIN_FILE), array(), PLUGIN_VERSION);
283
  $jsTranslation = array(
284
  'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
285
  'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
316
  $id = 'short-pixel-notice-toolbar';
317
  $tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
318
  $icon = "shortpixel.png";
319
+ $successLink = $link = admin_url(current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php');
320
  $blank = "";
321
  if($this->prioQ->processing()) {
322
  $extraClasses = " shortpixel-processing";
960
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
961
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
962
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
963
+
964
  $meta = $itemHandler->getMeta();
965
  //find thumbs that are not listed in the metadata and add them in the sizes array
966
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
1212
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
1213
  foreach($duplicates as $ID) {
1214
  $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
1215
+ if( isset($crtMeta["ShortPixelImprovement"]) && is_numeric($crtMeta["ShortPixelImprovement"])
1216
+ && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
1217
  $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
1218
  }
1219
  unset($crtMeta["ShortPixelImprovement"]);
1696
  die();
1697
  }
1698
 
1699
+ public function getComparerData() {
1700
+ if (!isset($_POST['id']) || !current_user_can( 'upload_files' ) && !current_user_can( 'edit_posts' ) ) {
1701
+ wp_die(json_encode((object)array('origUrl' => false, 'optUrl' => false, 'width' => 0, 'height' => 0)));
1702
+ }
1703
+
1704
+ $ret = array();
1705
+ $handle = new ShortPixelMetaFacade($_POST['id']);
1706
+ $meta = $handle->getMeta();
1707
+ $rawMeta = $handle->getRawMeta();
1708
+ $backupUrl = content_url() . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/";
1709
+ $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
1710
+ $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1711
+ $ret['origUrl'] = $backupUrl . $urlBkPath . $meta->getName();
1712
+ $ret['optUrl'] = $uploadsUrl . $urlBkPath . $meta->getName();
1713
+ $ret['width'] = $rawMeta['width'];
1714
+ $ret['height'] = $rawMeta['height'];
1715
+
1716
+ die(json_encode((object)$ret));
1717
+ }
1718
+
1719
  public static function getCustomFolderBase() {
1720
  if(is_main_site()) {
1721
  $base = get_home_path();
1904
  }
1905
 
1906
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1907
+ $this->_settings->createWebpMarkup = (isset($_POST['createWebpMarkup']) ? 1: 0);
1908
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1909
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
1910
 
2215
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2216
  $renderData['backup'] = $this->getBackupFolderAny($file, $sizesCount? $data['sizes'] : array());
2217
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2218
+ $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionTypes(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
2219
  $renderData['thumbsTotal'] = $sizesCount;
2220
  $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
2221
  $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
2315
  public function columns( $defaults ) {
2316
  $defaults['wp-shortPixel'] = 'ShortPixel Compression';
2317
  if(current_user_can( 'manage_options' )) {
2318
+ $defaults['wp-shortPixel'] .=
2319
+ '&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="'
2320
+ . __('ShortPixel Statistics','shortpixel-image-optimiser')
2321
+ . '"><span class="dashicons dashicons-dashboard"></span></a>';
2322
  }
2323
  return $defaults;
2324
  }
2564
  return array('width' => max(100, $width), 'height' => max(100, $height));
2565
  }
2566
 
2567
+ public function getOtherCompressionTypes($compressionType = false) {
2568
+ return array_values(array_diff(array(0, 1, 2), array(0 + $compressionType)));
 
 
 
 
 
 
 
2569
  }
2570
 
2571
  /* public function getEncryptedData() {
class/wp-shortpixel-settings.php CHANGED
@@ -26,6 +26,7 @@ class WPShortPixelSettings {
26
  'keepExif' => array('key' => 'wp-short-pixel-keep-exif', 'default' => 0),
27
  'CMYKtoRGBconversion' => array('key' => 'wp-short-pixel_cmyk2rgb', 'default' => 1),
28
  'createWebp' => array('key' => 'wp-short-create-webp', 'default' => null),
 
29
  'optimizeRetina' => array('key' => 'wp-short-pixel-optimize-retina', 'default' => 1),
30
  'backupImages' => array('key' => 'wp-short-backup_images', 'default' => 1),
31
  'resizeImages' => array('key' => 'wp-short-pixel-resize-images', 'default' => false),
26
  'keepExif' => array('key' => 'wp-short-pixel-keep-exif', 'default' => 0),
27
  'CMYKtoRGBconversion' => array('key' => 'wp-short-pixel_cmyk2rgb', 'default' => 1),
28
  'createWebp' => array('key' => 'wp-short-create-webp', 'default' => null),
29
+ 'createWebpMarkup' => array('key' => 'wp-short-pixel-create-webp-markup', 'default' => null),
30
  'optimizeRetina' => array('key' => 'wp-short-pixel-optimize-retina', 'default' => 1),
31
  'backupImages' => array('key' => 'wp-short-backup_images', 'default' => 1),
32
  'resizeImages' => array('key' => 'wp-short-pixel-resize-images', 'default' => false),
readme.txt CHANGED
@@ -6,7 +6,7 @@ Tags: compress, image, compression, optimize, image optimizer, image compression
6
 
7
  Requires at least: 3.2.0
8
  Tested up to: 4.8
9
- Stable tag: 4.4.2
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
@@ -222,6 +222,12 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
222
 
223
  == Changelog ==
224
 
 
 
 
 
 
 
225
  = 4.4.2 =
226
 
227
  * fix wrong custom path in some cases
6
 
7
  Requires at least: 3.2.0
8
  Tested up to: 4.8
9
+ Stable tag: 4.5.0
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
222
 
223
  == Changelog ==
224
 
225
+ = 4.5.0 =
226
+
227
+ * replace img tags in front-end with picture tags, and include the webp images
228
+ * actions menu in Media Library
229
+ * option to compare the optimized (main) image with the original in Media Library
230
+
231
  = 4.4.2 =
232
 
233
  * fix wrong custom path in some cases
res/css/short-pixel.css CHANGED
@@ -1,3 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  div.fb-like {
2
  transform: scale(1.3);
3
  -ms-transform: scale(1.3);
@@ -210,17 +257,60 @@ li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div,
210
  box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
211
  padding: 1px 12px;
212
  }
213
- li.shortpixel-hide {
214
  display:none;
215
  }
216
  .shortpixel-clearfix {
217
  width:100%;
218
  float:left;
219
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  .short-pixel-bulk-page p {
221
  margin: 0.6em 0;
222
  }
223
-
 
 
 
 
224
  .short-pixel-bulk-page form.start {
225
  display:table;
226
  content:" ";
1
+ /* Dropdown Button */
2
+ .sp-dropbtn.button {
3
+ padding: 1px 24px 20px 5px;
4
+ font-size: 20px;
5
+ /*background-color: #4CAF50;
6
+ color: white;
7
+ border: none;*/
8
+ cursor: pointer;
9
+ }
10
+
11
+ /* Dropdown button on hover & focus
12
+ .sp-dropbtn:hover, .sp-dropbtn:focus {
13
+ background-color: #3e8e41;
14
+ }
15
+ */
16
+
17
+ /* The container <div> - needed to position the dropdown content */
18
+ .sp-dropdown {
19
+ position: relative;
20
+ display: inline-block;
21
+ }
22
+
23
+ /* Dropdown Content (Hidden by Default) */
24
+ .sp-dropdown-content {
25
+ display: none;
26
+ right: 0;
27
+ position: absolute;
28
+ background-color: #f9f9f9;
29
+ min-width: 190px;
30
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
31
+ z-index: 1;
32
+ }
33
+
34
+ /* Links inside the dropdown */
35
+ .sp-dropdown-content a {
36
+ color: black;
37
+ padding: 12px 16px;
38
+ text-decoration: none;
39
+ display: block;
40
+ }
41
+
42
+ /* Change color of dropdown links on hover */
43
+ .sp-dropdown-content a:hover {background-color: #f1f1f1}
44
+
45
+ /* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
46
+ .sp-dropdown.sp-show .sp-dropdown-content {display:block;}
47
+
48
  div.fb-like {
49
  transform: scale(1.3);
50
  -ms-transform: scale(1.3);
257
  box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
258
  padding: 1px 12px;
259
  }
260
+ .shortpixel-hide {
261
  display:none;
262
  }
263
  .shortpixel-clearfix {
264
  width:100%;
265
  float:left;
266
  }
267
+ div.sp-modal-shade {
268
+ display: none; /* Hidden by default */
269
+ position: fixed; /* Stay in place */
270
+ z-index: 10; /* Sit on top */
271
+ left: 0;
272
+ top: 0;
273
+ width: 100%; /* Full width */
274
+ height: 100%; /* Full height */
275
+ overflow: auto; /* Enable scroll if needed */
276
+ background-color: rgb(0,0,0); /* Fallback color */
277
+ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
278
+ }
279
+ div.shortpixel-modal {
280
+ background-color: #fefefe;
281
+ margin: 8% auto; /* 15% from the top and centered */
282
+ padding: 20px;
283
+ border: 1px solid #888;
284
+ width: 30%; /* Could be more or less, depending on screen size */
285
+ min-width: 300px; /* Could be more or less, depending on screen size */
286
+ }
287
+ div.shortpixel-modal .sp-close-button {
288
+ float: right;
289
+ margin-top: 0px;
290
+ background: transparent;
291
+ border: none;
292
+ font-size: 22px;
293
+ line-height: 10px;
294
+ cursor: pointer;
295
+ }
296
+ .twentytwenty-horizontal .twentytwenty-before-label:before, .twentytwenty-horizontal .twentytwenty-after-label:before {
297
+ font-family: inherit;
298
+ font-size: 16px;
299
+ }
300
+ div.sp-modal-title {
301
+ font-size: 22px;
302
+ }
303
+ div.sp-modal-body {
304
+ margin-top: 20px;
305
+ }
306
  .short-pixel-bulk-page p {
307
  margin: 0.6em 0;
308
  }
309
+ div.shortpixel-modal .sptw-modal-spinner {
310
+ background-image: url("../img/spinner2.gif");
311
+ background-repeat: no-repeat;
312
+ background-position: center;
313
+ }
314
  .short-pixel-bulk-page form.start {
315
  display:table;
316
  content:" ";
res/css/sp-file-tree.css CHANGED
@@ -1,26 +1,3 @@
1
- div.sp-folder-picker-shade {
2
- display: none; /* Hidden by default */
3
- position: fixed; /* Stay in place */
4
- z-index: 10; /* Sit on top */
5
- left: 0;
6
- top: 0;
7
- width: 100%; /* Full width */
8
- height: 100%; /* Full height */
9
- overflow: auto; /* Enable scroll if needed */
10
- background-color: rgb(0,0,0); /* Fallback color */
11
- background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
12
- }
13
- div.sp-folder-picker-popup {
14
- background-color: #fefefe;
15
- margin: 15% auto; /* 15% from the top and centered */
16
- padding: 20px;
17
- border: 1px solid #888;
18
- width: 30%; /* Could be more or less, depending on screen size */
19
- min-width: 300px; /* Could be more or less, depending on screen size */
20
- }
21
- div.sp-folder-picker-title {
22
- font-size: 1.4em;
23
- }
24
  div.sp-folder-picker {
25
  margin: 20px 0; /* 15% from the top and centered */
26
  border: 1px solid #888;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  div.sp-folder-picker {
2
  margin: 20px 0; /* 15% from the top and centered */
3
  border: 1px solid #888;
res/css/twentytwenty.css ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .twentytwenty-horizontal .twentytwenty-handle:before, .twentytwenty-horizontal .twentytwenty-handle:after, .twentytwenty-vertical .twentytwenty-handle:before, .twentytwenty-vertical .twentytwenty-handle:after {
2
+ content: " ";
3
+ display: block;
4
+ background: white;
5
+ position: absolute;
6
+ z-index: 30;
7
+ -webkit-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
8
+ -moz-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
9
+ box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5); }
10
+
11
+ .twentytwenty-horizontal .twentytwenty-handle:before, .twentytwenty-horizontal .twentytwenty-handle:after {
12
+ width: 3px;
13
+ height: 9999px;
14
+ left: 50%;
15
+ margin-left: -1.5px; }
16
+
17
+ .twentytwenty-vertical .twentytwenty-handle:before, .twentytwenty-vertical .twentytwenty-handle:after {
18
+ width: 9999px;
19
+ height: 3px;
20
+ top: 50%;
21
+ margin-top: -1.5px; }
22
+
23
+ .twentytwenty-before-label, .twentytwenty-after-label, .twentytwenty-overlay {
24
+ position: absolute;
25
+ top: 0;
26
+ width: 100%;
27
+ height: 100%; }
28
+
29
+ .twentytwenty-before-label, .twentytwenty-after-label, .twentytwenty-overlay {
30
+ -webkit-transition-duration: 0.5s;
31
+ -moz-transition-duration: 0.5s;
32
+ transition-duration: 0.5s; }
33
+
34
+ .twentytwenty-before-label, .twentytwenty-after-label {
35
+ -webkit-transition-property: opacity;
36
+ -moz-transition-property: opacity;
37
+ transition-property: opacity; }
38
+
39
+ .twentytwenty-before-label:before, .twentytwenty-after-label:before {
40
+ color: white;
41
+ font-size: 13px;
42
+ letter-spacing: 0.1em;
43
+ }
44
+ .twentytwenty-before-label:before {
45
+ /*background: rgba(238, 40, 36, 0.9) none repeat scroll 0 0;*/
46
+ background: rgba(82, 82, 82, 0.9) none repeat scroll 0 0;
47
+ }
48
+ .twentytwenty-after-label:before {
49
+ background: rgba(28, 190, 203, 0.9) none repeat scroll 0 0;
50
+ }
51
+ .twentytwenty-before-label:before, .twentytwenty-after-label:before {
52
+ position: absolute;
53
+ line-height: 38px;
54
+ padding: 0 20px;
55
+ -webkit-border-radius: 2px;
56
+ -moz-border-radius: 2px;
57
+ font-family: montserratbold;
58
+ font-weight: bold;
59
+ }
60
+
61
+ .twentytwenty-horizontal .twentytwenty-before-label:before, .twentytwenty-horizontal .twentytwenty-after-label:before {
62
+ top: 20px;
63
+ }
64
+
65
+ .twentytwenty-vertical .twentytwenty-before-label:before, .twentytwenty-vertical .twentytwenty-after-label:before {
66
+ left: 50%;
67
+ margin-left: -45px;
68
+ text-align: center;
69
+ width: 90px; }
70
+
71
+ .twentytwenty-left-arrow, .twentytwenty-right-arrow, .twentytwenty-up-arrow, .twentytwenty-down-arrow {
72
+ width: 0;
73
+ height: 0;
74
+ border: 6px inset transparent;
75
+ position: absolute; }
76
+
77
+ .twentytwenty-left-arrow, .twentytwenty-right-arrow {
78
+ top: 50%;
79
+ margin-top: -6px; }
80
+
81
+ .twentytwenty-up-arrow, .twentytwenty-down-arrow {
82
+ left: 50%;
83
+ margin-left: -6px; }
84
+
85
+ .twentytwenty-container {
86
+ -webkit-box-sizing: content-box;
87
+ -moz-box-sizing: content-box;
88
+ box-sizing: content-box;
89
+ z-index: 0;
90
+ overflow: hidden;
91
+ position: relative;
92
+ -webkit-user-select: none;
93
+ -moz-user-select: none; }
94
+ .twentytwenty-container img {
95
+ max-width: 100%;
96
+ position: absolute;
97
+ top: 0;
98
+ display: block; }
99
+ .twentytwenty-container.active .twentytwenty-overlay, .twentytwenty-container.active :hover.twentytwenty-overlay {
100
+ background: rgba(0, 0, 0, 0); }
101
+ .twentytwenty-container.active .twentytwenty-overlay .twentytwenty-before-label,
102
+ .twentytwenty-container.active .twentytwenty-overlay .twentytwenty-after-label, .twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-before-label,
103
+ .twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-after-label {
104
+ opacity: 0; }
105
+ .twentytwenty-container * {
106
+ -webkit-box-sizing: content-box;
107
+ -moz-box-sizing: content-box;
108
+ box-sizing: content-box; }
109
+
110
+ .twentytwenty-before-label {
111
+ opacity: 0.7; }
112
+ .twentytwenty-before-label:before {
113
+ content: "ORIGINAL"; }
114
+
115
+ .twentytwenty-after-label {
116
+ opacity: 0.7; }
117
+ .twentytwenty-after-label:before {
118
+ content: "SHORTPIXEL"; }
119
+
120
+ .twentytwenty-horizontal .twentytwenty-before-label:before {
121
+ left: 20px; }
122
+
123
+ .twentytwenty-horizontal .twentytwenty-after-label:before {
124
+ right: 20px; }
125
+
126
+ .twentytwenty-vertical .twentytwenty-before-label:before {
127
+ top: 10px; }
128
+
129
+ .twentytwenty-vertical .twentytwenty-after-label:before {
130
+ bottom: 10px; }
131
+
132
+ .twentytwenty-overlay {
133
+ -webkit-transition-property: background;
134
+ -moz-transition-property: background;
135
+ transition-property: background;
136
+ background: rgba(0, 0, 0, 0);
137
+ z-index: 25; }
138
+ .twentytwenty-overlay:hover {
139
+ background: rgba(0, 0, 0, 0); }
140
+ .twentytwenty-overlay:hover .twentytwenty-after-label {
141
+ opacity: 1; }
142
+ .twentytwenty-overlay:hover .twentytwenty-before-label {
143
+ opacity: 1; }
144
+
145
+ .twentytwenty-before {
146
+ z-index: 20; }
147
+
148
+ .twentytwenty-after {
149
+ z-index: 10; }
150
+
151
+ .twentytwenty-handle {
152
+ height: 38px;
153
+ width: 38px;
154
+ position: absolute;
155
+ left: 50%;
156
+ top: 50%;
157
+ margin-left: -22px;
158
+ margin-top: -22px;
159
+ border: 3px solid white;
160
+ -webkit-border-radius: 1000px;
161
+ -moz-border-radius: 1000px;
162
+ border-radius: 1000px;
163
+ -webkit-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
164
+ -moz-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
165
+ box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
166
+ z-index: 40;
167
+ cursor: pointer; }
168
+
169
+ .twentytwenty-horizontal .twentytwenty-handle:before {
170
+ bottom: 50%;
171
+ margin-bottom: 22px;
172
+ -webkit-box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
173
+ -moz-box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
174
+ box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
175
+ .twentytwenty-horizontal .twentytwenty-handle:after {
176
+ top: 50%;
177
+ margin-top: 22px;
178
+ -webkit-box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
179
+ -moz-box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
180
+ box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
181
+
182
+ .twentytwenty-vertical .twentytwenty-handle:before {
183
+ left: 50%;
184
+ margin-left: 22px;
185
+ -webkit-box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
186
+ -moz-box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
187
+ box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
188
+ .twentytwenty-vertical .twentytwenty-handle:after {
189
+ right: 50%;
190
+ margin-right: 22px;
191
+ -webkit-box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
192
+ -moz-box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
193
+ box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
194
+
195
+ .twentytwenty-left-arrow {
196
+ border-right: 6px solid white;
197
+ left: 50%;
198
+ margin-left: -17px; }
199
+
200
+ .twentytwenty-right-arrow {
201
+ border-left: 6px solid white;
202
+ right: 50%;
203
+ margin-right: -17px; }
204
+
205
+ .twentytwenty-up-arrow {
206
+ border-bottom: 6px solid white;
207
+ top: 50%;
208
+ margin-top: -17px; }
209
+
210
+ .twentytwenty-down-arrow {
211
+ border-top: 6px solid white;
212
+ bottom: 50%;
213
+ margin-bottom: -17px; }
res/img/spinner2.gif ADDED
Binary file
res/js/jquery.twentytwenty.js ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+
3
+ $.fn.twentytwenty = function(options) {
4
+ var options = $.extend({
5
+ default_offset_pct: 0.5,
6
+ orientation: 'horizontal',
7
+ slider_move: "drag" //"drag" or "mousemove"
8
+ }, options);
9
+ return this.each(function() {
10
+
11
+ var sliderPct = options.default_offset_pct;
12
+ var container = $(this);
13
+ var sliderOrientation = options.orientation;
14
+ var beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left';
15
+ var afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right';
16
+
17
+
18
+ container.wrap("<div class='twentytwenty-wrapper twentytwenty-" + sliderOrientation + "'></div>");
19
+ container.append("<div class='twentytwenty-overlay'></div>");
20
+ var beforeImg = container.find("img:first");
21
+ var afterImg = container.find("img:last");
22
+ container.append("<div class='twentytwenty-handle'></div>");
23
+ var slider = container.find(".twentytwenty-handle");
24
+ slider.append("<span class='twentytwenty-" + beforeDirection + "-arrow'></span>");
25
+ slider.append("<span class='twentytwenty-" + afterDirection + "-arrow'></span>");
26
+ container.addClass("twentytwenty-container");
27
+ beforeImg.addClass("twentytwenty-before");
28
+ afterImg.addClass("twentytwenty-after");
29
+
30
+ var overlay = container.find(".twentytwenty-overlay");
31
+ overlay.append("<div class='twentytwenty-before-label'></div>");
32
+ overlay.append("<div class='twentytwenty-after-label'></div>");
33
+
34
+ var beforeLabel = container.find("div.twentytwenty-before-label");
35
+ var afterLabel = container.find("div.twentytwenty-after-label");
36
+
37
+ var calcOffset = function(dimensionPct) {
38
+ var w = beforeImg.width();
39
+ var h = beforeImg.height();
40
+ return {
41
+ w: w+"px",
42
+ h: h+"px",
43
+ cw: (dimensionPct*w)+"px",
44
+ ch: (dimensionPct*h)+"px",
45
+ };
46
+ };
47
+
48
+ var adjustContainer = function(offset) {
49
+ if (sliderOrientation === 'vertical') {
50
+ beforeImg.css("clip", "rect(0,"+offset.w+","+offset.ch+",0)");
51
+
52
+ }
53
+ else {
54
+ beforeImg.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
55
+ beforeLabel.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
56
+ afterLabel.css("clip", "rect(0,"+offset.w+","+offset.h+","+offset.cw+")"); //clip: rect(0px, 700px, 1000px, 600px);
57
+ }
58
+ container.css("height", offset.h);
59
+ };
60
+
61
+ var adjustSlider = function(pct) {
62
+ var offset = calcOffset(pct);
63
+ slider.css((sliderOrientation==="vertical") ? "top" : "left", (sliderOrientation==="vertical") ? offset.ch : offset.cw);
64
+ adjustContainer(offset);
65
+ }
66
+
67
+ $(window).on("resize.twentytwenty", function(e) {
68
+ adjustSlider(sliderPct);
69
+ });
70
+
71
+ var offsetX = 0;
72
+ var imgWidth = 0;
73
+
74
+ if(options.slider_move == "drag") {
75
+ slider.on("movestart", function(e) {
76
+ if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
77
+ e.preventDefault();
78
+ }
79
+ else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
80
+ e.preventDefault();
81
+ }
82
+ container.addClass("active");
83
+ offsetX = container.offset().left;
84
+ offsetY = container.offset().top;
85
+ imgWidth = beforeImg.width();
86
+ imgHeight = beforeImg.height();
87
+ });
88
+
89
+ slider.on("moveend", function(e) {
90
+ container.removeClass("active");
91
+ });
92
+
93
+ slider.on("move", function(e) {
94
+ if (container.hasClass("active")) {
95
+ sliderPct = (sliderOrientation === 'vertical') ? (e.pageY-offsetY)/imgHeight : (e.pageX-offsetX)/imgWidth;
96
+ if (sliderPct < 0) {
97
+ sliderPct = 0;
98
+ }
99
+ if (sliderPct > 1) {
100
+ sliderPct = 1;
101
+ }
102
+ adjustSlider(sliderPct);
103
+ }
104
+ });
105
+ } else {
106
+ container.mousemove(function(e) {
107
+ sliderPct = (sliderOrientation === 'vertical')
108
+ ? (e.pageY-container.offset().top)/beforeImg.height()
109
+ : (e.pageX-container.offset().left)/beforeImg.width();
110
+ if (sliderPct < 0) {
111
+ sliderPct = 0;
112
+ }
113
+ if (sliderPct > 1) {
114
+ sliderPct = 1;
115
+ }
116
+ adjustSlider(sliderPct);
117
+ });
118
+ }
119
+
120
+ container.find("img").on("mousedown", function(event) {
121
+ event.preventDefault();
122
+ });
123
+
124
+ $(window).trigger("resize.twentytwenty");
125
+ });
126
+ };
127
+
128
+ })(jQuery);
res/js/picturefill.min.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ /*! picturefill - v3.0.2 - 2016-02-12
2
+ * https://scottjehl.github.io/picturefill/
3
+ * Copyright (c) 2016 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT
4
+ */
5
+ !function(a){var b=navigator.userAgent;a.HTMLPictureElement&&/ecko/.test(b)&&b.match(/rv\:(\d+)/)&&RegExp.$1<45&&addEventListener("resize",function(){var b,c=document.createElement("source"),d=function(a){var b,d,e=a.parentNode;"PICTURE"===e.nodeName.toUpperCase()?(b=c.cloneNode(),e.insertBefore(b,e.firstElementChild),setTimeout(function(){e.removeChild(b)})):(!a._pfLastSize||a.offsetWidth>a._pfLastSize)&&(a._pfLastSize=a.offsetWidth,d=a.sizes,a.sizes+=",100vw",setTimeout(function(){a.sizes=d}))},e=function(){var a,b=document.querySelectorAll("picture > img, img[srcset][sizes]");for(a=0;a<b.length;a++)d(b[a])},f=function(){clearTimeout(b),b=setTimeout(e,99)},g=a.matchMedia&&matchMedia("(orientation: landscape)"),h=function(){f(),g&&g.addListener&&g.addListener(f)};return c.srcset="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",/^[c|i]|d$/.test(document.readyState||"")?h():document.addEventListener("DOMContentLoaded",h),f}())}(window),function(a,b,c){"use strict";function d(a){return" "===a||" "===a||"\n"===a||"\f"===a||"\r"===a}function e(b,c){var d=new a.Image;return d.onerror=function(){A[b]=!1,ba()},d.onload=function(){A[b]=1===d.width,ba()},d.src=c,"pending"}function f(){M=!1,P=a.devicePixelRatio,N={},O={},s.DPR=P||1,Q.width=Math.max(a.innerWidth||0,z.clientWidth),Q.height=Math.max(a.innerHeight||0,z.clientHeight),Q.vw=Q.width/100,Q.vh=Q.height/100,r=[Q.height,Q.width,P].join("-"),Q.em=s.getEmValue(),Q.rem=Q.em}function g(a,b,c,d){var e,f,g,h;return"saveData"===B.algorithm?a>2.7?h=c+1:(f=b-c,e=Math.pow(a-.6,1.5),g=f*e,d&&(g+=.1*e),h=a+g):h=c>1?Math.sqrt(a*b):a,h>c}function h(a){var b,c=s.getSet(a),d=!1;"pending"!==c&&(d=r,c&&(b=s.setRes(c),s.applySetCandidate(b,a))),a[s.ns].evaled=d}function i(a,b){return a.res-b.res}function j(a,b,c){var d;return!c&&b&&(c=a[s.ns].sets,c=c&&c[c.length-1]),d=k(b,c),d&&(b=s.makeUrl(b),a[s.ns].curSrc=b,a[s.ns].curCan=d,d.res||aa(d,d.set.sizes)),d}function k(a,b){var c,d,e;if(a&&b)for(e=s.parseSet(b),a=s.makeUrl(a),c=0;c<e.length;c++)if(a===s.makeUrl(e[c].url)){d=e[c];break}return d}function l(a,b){var c,d,e,f,g=a.getElementsByTagName("source");for(c=0,d=g.length;d>c;c++)e=g[c],e[s.ns]=!0,f=e.getAttribute("srcset"),f&&b.push({srcset:f,media:e.getAttribute("media"),type:e.getAttribute("type"),sizes:e.getAttribute("sizes")})}function m(a,b){function c(b){var c,d=b.exec(a.substring(m));return d?(c=d[0],m+=c.length,c):void 0}function e(){var a,c,d,e,f,i,j,k,l,m=!1,o={};for(e=0;e<h.length;e++)f=h[e],i=f[f.length-1],j=f.substring(0,f.length-1),k=parseInt(j,10),l=parseFloat(j),X.test(j)&&"w"===i?((a||c)&&(m=!0),0===k?m=!0:a=k):Y.test(j)&&"x"===i?((a||c||d)&&(m=!0),0>l?m=!0:c=l):X.test(j)&&"h"===i?((d||c)&&(m=!0),0===k?m=!0:d=k):m=!0;m||(o.url=g,a&&(o.w=a),c&&(o.d=c),d&&(o.h=d),d||c||a||(o.d=1),1===o.d&&(b.has1x=!0),o.set=b,n.push(o))}function f(){for(c(T),i="",j="in descriptor";;){if(k=a.charAt(m),"in descriptor"===j)if(d(k))i&&(h.push(i),i="",j="after descriptor");else{if(","===k)return m+=1,i&&h.push(i),void e();if("("===k)i+=k,j="in parens";else{if(""===k)return i&&h.push(i),void e();i+=k}}else if("in parens"===j)if(")"===k)i+=k,j="in descriptor";else{if(""===k)return h.push(i),void e();i+=k}else if("after descriptor"===j)if(d(k));else{if(""===k)return void e();j="in descriptor",m-=1}m+=1}}for(var g,h,i,j,k,l=a.length,m=0,n=[];;){if(c(U),m>=l)return n;g=c(V),h=[],","===g.slice(-1)?(g=g.replace(W,""),e()):f()}}function n(a){function b(a){function b(){f&&(g.push(f),f="")}function c(){g[0]&&(h.push(g),g=[])}for(var e,f="",g=[],h=[],i=0,j=0,k=!1;;){if(e=a.charAt(j),""===e)return b(),c(),h;if(k){if("*"===e&&"/"===a[j+1]){k=!1,j+=2,b();continue}j+=1}else{if(d(e)){if(a.charAt(j-1)&&d(a.charAt(j-1))||!f){j+=1;continue}if(0===i){b(),j+=1;continue}e=" "}else if("("===e)i+=1;else if(")"===e)i-=1;else{if(","===e){b(),c(),j+=1;continue}if("/"===e&&"*"===a.charAt(j+1)){k=!0,j+=2;continue}}f+=e,j+=1}}}function c(a){return k.test(a)&&parseFloat(a)>=0?!0:l.test(a)?!0:"0"===a||"-0"===a||"+0"===a?!0:!1}var e,f,g,h,i,j,k=/^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i,l=/^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i;for(f=b(a),g=f.length,e=0;g>e;e++)if(h=f[e],i=h[h.length-1],c(i)){if(j=i,h.pop(),0===h.length)return j;if(h=h.join(" "),s.matchesMedia(h))return j}return"100vw"}b.createElement("picture");var o,p,q,r,s={},t=!1,u=function(){},v=b.createElement("img"),w=v.getAttribute,x=v.setAttribute,y=v.removeAttribute,z=b.documentElement,A={},B={algorithm:""},C="data-pfsrc",D=C+"set",E=navigator.userAgent,F=/rident/.test(E)||/ecko/.test(E)&&E.match(/rv\:(\d+)/)&&RegExp.$1>35,G="currentSrc",H=/\s+\+?\d+(e\d+)?w/,I=/(\([^)]+\))?\s*(.+)/,J=a.picturefillCFG,K="position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)",L="font-size:100%!important;",M=!0,N={},O={},P=a.devicePixelRatio,Q={px:1,"in":96},R=b.createElement("a"),S=!1,T=/^[ \t\n\r\u000c]+/,U=/^[, \t\n\r\u000c]+/,V=/^[^ \t\n\r\u000c]+/,W=/[,]+$/,X=/^\d+$/,Y=/^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/,Z=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d||!1):a.attachEvent&&a.attachEvent("on"+b,c)},$=function(a){var b={};return function(c){return c in b||(b[c]=a(c)),b[c]}},_=function(){var a=/^([\d\.]+)(em|vw|px)$/,b=function(){for(var a=arguments,b=0,c=a[0];++b in a;)c=c.replace(a[b],a[++b]);return c},c=$(function(a){return"return "+b((a||"").toLowerCase(),/\band\b/g,"&&",/,/g,"||",/min-([a-z-\s]+):/g,"e.$1>=",/max-([a-z-\s]+):/g,"e.$1<=",/calc([^)]+)/g,"($1)",/(\d+[\.]*[\d]*)([a-z]+)/g,"($1 * e.$2)",/^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/gi,"")+";"});return function(b,d){var e;if(!(b in N))if(N[b]=!1,d&&(e=b.match(a)))N[b]=e[1]*Q[e[2]];else try{N[b]=new Function("e",c(b))(Q)}catch(f){}return N[b]}}(),aa=function(a,b){return a.w?(a.cWidth=s.calcListLength(b||"100vw"),a.res=a.w/a.cWidth):a.res=a.d,a},ba=function(a){if(t){var c,d,e,f=a||{};if(f.elements&&1===f.elements.nodeType&&("IMG"===f.elements.nodeName.toUpperCase()?f.elements=[f.elements]:(f.context=f.elements,f.elements=null)),c=f.elements||s.qsa(f.context||b,f.reevaluate||f.reselect?s.sel:s.selShort),e=c.length){for(s.setupRun(f),S=!0,d=0;e>d;d++)s.fillImg(c[d],f);s.teardownRun(f)}}};o=a.console&&console.warn?function(a){console.warn(a)}:u,G in v||(G="src"),A["image/jpeg"]=!0,A["image/gif"]=!0,A["image/png"]=!0,A["image/svg+xml"]=b.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1"),s.ns=("pf"+(new Date).getTime()).substr(0,9),s.supSrcset="srcset"in v,s.supSizes="sizes"in v,s.supPicture=!!a.HTMLPictureElement,s.supSrcset&&s.supPicture&&!s.supSizes&&!function(a){v.srcset="data:,a",a.src="data:,a",s.supSrcset=v.complete===a.complete,s.supPicture=s.supSrcset&&s.supPicture}(b.createElement("img")),s.supSrcset&&!s.supSizes?!function(){var a="data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==",c="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",d=b.createElement("img"),e=function(){var a=d.width;2===a&&(s.supSizes=!0),q=s.supSrcset&&!s.supSizes,t=!0,setTimeout(ba)};d.onload=e,d.onerror=e,d.setAttribute("sizes","9px"),d.srcset=c+" 1w,"+a+" 9w",d.src=c}():t=!0,s.selShort="picture>img,img[srcset]",s.sel=s.selShort,s.cfg=B,s.DPR=P||1,s.u=Q,s.types=A,s.setSize=u,s.makeUrl=$(function(a){return R.href=a,R.href}),s.qsa=function(a,b){return"querySelector"in a?a.querySelectorAll(b):[]},s.matchesMedia=function(){return a.matchMedia&&(matchMedia("(min-width: 0.1em)")||{}).matches?s.matchesMedia=function(a){return!a||matchMedia(a).matches}:s.matchesMedia=s.mMQ,s.matchesMedia.apply(this,arguments)},s.mMQ=function(a){return a?_(a):!0},s.calcLength=function(a){var b=_(a,!0)||!1;return 0>b&&(b=!1),b},s.supportsType=function(a){return a?A[a]:!0},s.parseSize=$(function(a){var b=(a||"").match(I);return{media:b&&b[1],length:b&&b[2]}}),s.parseSet=function(a){return a.cands||(a.cands=m(a.srcset,a)),a.cands},s.getEmValue=function(){var a;if(!p&&(a=b.body)){var c=b.createElement("div"),d=z.style.cssText,e=a.style.cssText;c.style.cssText=K,z.style.cssText=L,a.style.cssText=L,a.appendChild(c),p=c.offsetWidth,a.removeChild(c),p=parseFloat(p,10),z.style.cssText=d,a.style.cssText=e}return p||16},s.calcListLength=function(a){if(!(a in O)||B.uT){var b=s.calcLength(n(a));O[a]=b?b:Q.width}return O[a]},s.setRes=function(a){var b;if(a){b=s.parseSet(a);for(var c=0,d=b.length;d>c;c++)aa(b[c],a.sizes)}return b},s.setRes.res=aa,s.applySetCandidate=function(a,b){if(a.length){var c,d,e,f,h,k,l,m,n,o=b[s.ns],p=s.DPR;if(k=o.curSrc||b[G],l=o.curCan||j(b,k,a[0].set),l&&l.set===a[0].set&&(n=F&&!b.complete&&l.res-.1>p,n||(l.cached=!0,l.res>=p&&(h=l))),!h)for(a.sort(i),f=a.length,h=a[f-1],d=0;f>d;d++)if(c=a[d],c.res>=p){e=d-1,h=a[e]&&(n||k!==s.makeUrl(c.url))&&g(a[e].res,c.res,p,a[e].cached)?a[e]:c;break}h&&(m=s.makeUrl(h.url),o.curSrc=m,o.curCan=h,m!==k&&s.setSrc(b,h),s.setSize(b))}},s.setSrc=function(a,b){var c;a.src=b.url,"image/svg+xml"===b.set.type&&(c=a.style.width,a.style.width=a.offsetWidth+1+"px",a.offsetWidth+1&&(a.style.width=c))},s.getSet=function(a){var b,c,d,e=!1,f=a[s.ns].sets;for(b=0;b<f.length&&!e;b++)if(c=f[b],c.srcset&&s.matchesMedia(c.media)&&(d=s.supportsType(c.type))){"pending"===d&&(c=d),e=c;break}return e},s.parseSets=function(a,b,d){var e,f,g,h,i=b&&"PICTURE"===b.nodeName.toUpperCase(),j=a[s.ns];(j.src===c||d.src)&&(j.src=w.call(a,"src"),j.src?x.call(a,C,j.src):y.call(a,C)),(j.srcset===c||d.srcset||!s.supSrcset||a.srcset)&&(e=w.call(a,"srcset"),j.srcset=e,h=!0),j.sets=[],i&&(j.pic=!0,l(b,j.sets)),j.srcset?(f={srcset:j.srcset,sizes:w.call(a,"sizes")},j.sets.push(f),g=(q||j.src)&&H.test(j.srcset||""),g||!j.src||k(j.src,f)||f.has1x||(f.srcset+=", "+j.src,f.cands.push({url:j.src,d:1,set:f}))):j.src&&j.sets.push({srcset:j.src,sizes:null}),j.curCan=null,j.curSrc=c,j.supported=!(i||f&&!s.supSrcset||g&&!s.supSizes),h&&s.supSrcset&&!j.supported&&(e?(x.call(a,D,e),a.srcset=""):y.call(a,D)),j.supported&&!j.srcset&&(!j.src&&a.src||a.src!==s.makeUrl(j.src))&&(null===j.src?a.removeAttribute("src"):a.src=j.src),j.parsed=!0},s.fillImg=function(a,b){var c,d=b.reselect||b.reevaluate;a[s.ns]||(a[s.ns]={}),c=a[s.ns],(d||c.evaled!==r)&&((!c.parsed||b.reevaluate)&&s.parseSets(a,a.parentNode,b),c.supported?c.evaled=r:h(a))},s.setupRun=function(){(!S||M||P!==a.devicePixelRatio)&&f()},s.supPicture?(ba=u,s.fillImg=u):!function(){var c,d=a.attachEvent?/d$|^c/:/d$|^c|^i/,e=function(){var a=b.readyState||"";f=setTimeout(e,"loading"===a?200:999),b.body&&(s.fillImgs(),c=c||d.test(a),c&&clearTimeout(f))},f=setTimeout(e,b.body?9:99),g=function(a,b){var c,d,e=function(){var f=new Date-d;b>f?c=setTimeout(e,b-f):(c=null,a())};return function(){d=new Date,c||(c=setTimeout(e,b))}},h=z.clientHeight,i=function(){M=Math.max(a.innerWidth||0,z.clientWidth)!==Q.width||z.clientHeight!==h,h=z.clientHeight,M&&s.fillImgs()};Z(a,"resize",g(i,99)),Z(b,"readystatechange",e)}(),s.picturefill=ba,s.fillImgs=ba,s.teardownRun=u,ba._=s,a.picturefillCFG={pf:s,push:function(a){var b=a.shift();"function"==typeof s[b]?s[b].apply(s,a):(B[b]=a[0],S&&s.fillImgs({reselect:!0}))}};for(;J&&J.length;)a.picturefillCFG.push(J.shift());a.picturefill=ba,"object"==typeof module&&"object"==typeof module.exports?module.exports=ba:"function"==typeof define&&define.amd&&define("picturefill",function(){return ba}),s.supPicture||(A["image/webp"]=e("image/webp","data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA=="))}(window,document);
res/js/short-pixel.js CHANGED
@@ -189,25 +189,32 @@ var ShortPixel = function() {
189
  });
190
  }
191
 
192
- function successActions(id, type, thumbsCount, thumbsTotal, backupEnabled) {
193
  if(backupEnabled == 1) {
194
 
195
- var otherType;
 
 
 
196
  if(type.length == 0) {
197
- otherType = ShortPixel.DEFAULT_COMPRESSION == 1 ? 'glossy' : ShortPixel.DEFAULT_COMPRESSION == 2 ? 'lossless' : 'lossy';
 
 
 
 
 
 
 
198
  }
199
- else if(ShortPixel.DEFAULT_COMPRESSION == 0 || ShortPixel.DEFAULT_COMPRESSION == 2) {
200
- otherType = (type == 'lossless' ? 'glossy' : 'lossless');
 
 
 
201
  }
202
- else otherType = (type == 'lossy' ? 'lossless' : 'lossy');
203
-
204
-
205
- return '<div class="sp-column-actions">'
206
- + (thumbsTotal > thumbsCount ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">"
207
- + _spTr.optXThumbs.format(thumbsTotal - thumbsCount) + "</a>" : "")
208
- + (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">" + _spTr.reOptimizeAs.format(otherType) + "</a>" : "")
209
- + "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">" + _spTr.restoreBackup + "</a>"
210
- + "</div>";
211
  }
212
  return "";
213
  }
@@ -269,7 +276,7 @@ var ShortPixel = function() {
269
 
270
  function initFolderSelector() {
271
  jQuery(".select-folder-button").click(function(){
272
- jQuery(".sp-folder-picker-shade").css("display", "block");
273
  jQuery(".sp-folder-picker").fileTree({
274
  script: ShortPixel.browseContent,
275
  //folderEvent: 'dblclick',
@@ -277,17 +284,17 @@ var ShortPixel = function() {
277
  //onlyFolders: true
278
  });
279
  });
280
- jQuery(".sp-folder-picker-popup input.select-folder-cancel").click(function(){
281
- jQuery(".sp-folder-picker-shade").css("display", "none");
282
  });
283
- jQuery(".sp-folder-picker-popup input.select-folder").click(function(){
284
  var subPath = jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel").trim();
285
  if(subPath) {
286
  var fullPath = jQuery("#customFolderBase").val() + subPath;
287
  if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
288
  jQuery("#addCustomFolder").val(fullPath);
289
  jQuery("#addCustomFolderView").val(fullPath);
290
- jQuery(".sp-folder-picker-shade").css("display", "none");
291
  } else {
292
  alert("Please select a folder from the list.");
293
  }
@@ -357,6 +364,105 @@ var ShortPixel = function() {
357
  function recheckQuota() {
358
  window.location.href=window.location.href+(window.location.href.indexOf('?')>0?'&':'?')+'checkquota=1';
359
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
  return {
362
  setOptions : setOptions,
@@ -385,7 +491,20 @@ var ShortPixel = function() {
385
  bulkShowError : bulkShowError,
386
  removeBulkMsg : removeBulkMsg,
387
  isCustomImageId : isCustomImageId,
388
- recheckQuota : recheckQuota
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  }
390
  }();
391
 
@@ -589,7 +708,7 @@ function checkBulkProcessingCallApi(){
589
  //for now, until 4.1
590
  var successActions = ShortPixel.isCustomImageId(id)
591
  ? ""
592
- : ShortPixel.successActions(id, data["Type"], data['ThumbsCount'], data['ThumbsTotal'], data["BackupEnabled"]);
593
 
594
  setCellMessage(id, ShortPixel.successMsg(id, percent, data["Type"], data['ThumbsCount'], data['RetinasCount']), successActions);
595
  var actions = jQuery(['restore', 'view', 'redolossy', 'redoglossy', 'redolossless']).not(['redo'+data["Type"]]).get();
189
  });
190
  }
191
 
192
+ function successActions(id, type, thumbsCount, thumbsTotal, backupEnabled, fileName) {
193
  if(backupEnabled == 1) {
194
 
195
+ var successActions = jQuery('.sp-column-actions-template').clone();
196
+
197
+
198
+ var otherTypes;
199
  if(type.length == 0) {
200
+ otherTypes = ['lossy', 'lossless'];
201
+ } else {
202
+ otherTypes = ['lossy','glossy','lossless'].filter(function(el) {return !(el == type);});
203
+ }
204
+
205
+ successActions.html(successActions.html().replace(/__SP_ID__/g, id));
206
+ if(fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase() == 'pdf') {
207
+ jQuery('.sp-action-compare', successActions).remove();
208
  }
209
+ if(thumbsCount == 0) {
210
+ successActions.html(successActions.html().replace('__SP_THUMBS_TOTAL__', thumbsTotal));
211
+ } else {
212
+ jQuery('.sp-action-optimize-thumbs', successActions).remove();
213
+ jQuery('.sp-dropbtn', successActions).removeClass('button-primary');
214
  }
215
+ successActions.html(successActions.html().replace(/__SP_FIRST_TYPE__/g, otherTypes[0]));
216
+ successActions.html(successActions.html().replace(/__SP_SECOND_TYPE__/g, otherTypes[1]));
217
+ return successActions.html();
 
 
 
 
 
 
218
  }
219
  return "";
220
  }
276
 
277
  function initFolderSelector() {
278
  jQuery(".select-folder-button").click(function(){
279
+ jQuery(".sp-modal-shade").css("display", "block");
280
  jQuery(".sp-folder-picker").fileTree({
281
  script: ShortPixel.browseContent,
282
  //folderEvent: 'dblclick',
284
  //onlyFolders: true
285
  });
286
  });
287
+ jQuery(".shortpixel-modal input.select-folder-cancel").click(function(){
288
+ jQuery(".sp-modal-shade").css("display", "none");
289
  });
290
+ jQuery(".shortpixel-modal input.select-folder").click(function(){
291
  var subPath = jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel").trim();
292
  if(subPath) {
293
  var fullPath = jQuery("#customFolderBase").val() + subPath;
294
  if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
295
  jQuery("#addCustomFolder").val(fullPath);
296
  jQuery("#addCustomFolderView").val(fullPath);
297
+ jQuery(".sp-modal-shade").css("display", "none");
298
  } else {
299
  alert("Please select a folder from the list.");
300
  }
364
  function recheckQuota() {
365
  window.location.href=window.location.href+(window.location.href.indexOf('?')>0?'&':'?')+'checkquota=1';
366
  }
367
+
368
+ function openImageMenu(e) {
369
+ e.preventDefault();
370
+ //install (lazily) a window click event to close the menus
371
+ if(!this.menuCloseEvent) {
372
+ jQuery(window).click(function(e){
373
+ if (!e.target.matches('.sp-dropbtn')) {
374
+ jQuery('.sp-dropdown.sp-show').removeClass('sp-show');
375
+ }
376
+ });
377
+ this.menuCloseEvent = true;
378
+ }
379
+ var shown = e.target.parentElement.classList.contains("sp-show");
380
+ jQuery('.sp-dropdown.sp-show').removeClass('sp-show');
381
+ if(!shown) e.target.parentElement.classList.add("sp-show");
382
+ }
383
+
384
+ function loadComparer(id) {
385
+ this.comparerData.origUrl = false;
386
+
387
+ if(this.comparerData.cssLoaded === false) {
388
+ jQuery('<link>')
389
+ .appendTo('head')
390
+ .attr({
391
+ type: 'text/css',
392
+ rel: 'stylesheet',
393
+ href: this.WP_PLUGIN_URL + '/res/css/twentytwenty.css'
394
+ });
395
+ this.comparerData.cssLoaded = 2;
396
+ }
397
+ if(this.comparerData.jsLoaded === false) {
398
+ jQuery.getScript(this.WP_PLUGIN_URL + '/res/js/jquery.twentytwenty.js', function(){
399
+ ShortPixel.comparerData.jsLoaded = 2;
400
+ if(ShortPixel.comparerData.origUrl.length > 0) {
401
+ ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
402
+ }
403
+ });
404
+ this.comparerData.jsLoaded = 1;
405
+ jQuery(".sp-close-button").click(ShortPixel.closeComparerPopup);
406
+ }
407
+ if(this.comparerData.origUrl === false) {
408
+ jQuery.ajax({
409
+ type: "POST",
410
+ url: ShortPixel.AJAX_URL,
411
+ data: { action : 'shortpixel_get_comparer_data', id : id },
412
+ success: function(response) {
413
+ data = JSON.parse(response);
414
+ jQuery.extend(ShortPixel.comparerData, data);
415
+ if(ShortPixel.comparerData.jsLoaded == 2) {
416
+ ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
417
+ }
418
+ }
419
+ });
420
+ this.comparerData.origUrl = '';
421
+ }
422
+ }
423
+
424
+ function displayComparerPopup(width, height, imgOriginal, imgOptimized) {
425
+ //image sizes
426
+ var origWidth = width;
427
+ //depending on the sizes choose the right modal
428
+ var sideBySide = (height < 150 || width < 350);
429
+ var modal = jQuery(sideBySide ? '#spUploadCompareSideBySide' : '#spUploadCompare');
430
+ if(!sideBySide) {
431
+ jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>');
432
+ }
433
+ //calculate the modal size
434
+ width = Math.max(350, Math.min(800, (width < 350 ? (width + 25) * 2 : (height < 150 ? width + 25 : width))));
435
+ height = Math.max(150, (sideBySide ? (origWidth > 350 ? 2 * (height + 45) : height + 45) : height * width / origWidth));
436
+ //set modal sizes and display
437
+ jQuery(".sp-modal-body", modal).css("width", width);
438
+ jQuery(".shortpixel-slider", modal).css("width", width);
439
+ modal.css("width", width);
440
+ jQuery(".sp-modal-body", modal).css("height", height);
441
+ modal.css('display', 'block');
442
+ modal.parent().css('display', 'block');
443
+ if(!sideBySide) {
444
+ jQuery("#spCompareSlider").twentytwenty({slider_move: "mousemove"});
445
+ }
446
+ jQuery(document).on('keyup.sp_modal_active', ShortPixel.closeComparerPopup);
447
+ //change images srcs
448
+ var imgOpt = jQuery(".spUploadCompareOptimized", modal);
449
+ jQuery(".spUploadCompareOriginal", modal).attr("src", imgOriginal);
450
+ //these timeouts are for the slider - it needs a punch to work :)
451
+ setTimeout(function(){
452
+ jQuery(window).trigger('resize');
453
+ }, 1000);
454
+ imgOpt.load(function(){
455
+ jQuery(window).trigger('resize');
456
+ });
457
+ imgOpt.attr("src", imgOptimized);
458
+ }
459
+
460
+ function closeComparerPopup(e) {
461
+ jQuery("#spUploadCompareSideBySide").parent().css("display", 'none');
462
+ jQuery("#spUploadCompareSideBySide").css("display", 'none');
463
+ jQuery("#spUploadCompare").css("display", 'none');
464
+ jQuery(document).unbind('keyup.sp_modal_active');
465
+ }
466
 
467
  return {
468
  setOptions : setOptions,
491
  bulkShowError : bulkShowError,
492
  removeBulkMsg : removeBulkMsg,
493
  isCustomImageId : isCustomImageId,
494
+ recheckQuota : recheckQuota,
495
+ openImageMenu : openImageMenu,
496
+ menuCloseEvent : false,
497
+ loadComparer : loadComparer,
498
+ displayComparerPopup: displayComparerPopup,
499
+ closeComparerPopup : closeComparerPopup,
500
+ comparerData : {
501
+ cssLoaded : false,
502
+ jsLoaded : false,
503
+ origUrl : false,
504
+ optUrl : false,
505
+ width : 0,
506
+ height : 0
507
+ }
508
  }
509
  }();
510
 
708
  //for now, until 4.1
709
  var successActions = ShortPixel.isCustomImageId(id)
710
  ? ""
711
+ : ShortPixel.successActions(id, data["Type"], data['ThumbsCount'], data['ThumbsTotal'], data["BackupEnabled"], data['Filename']);
712
 
713
  setCellMessage(id, ShortPixel.successMsg(id, percent, data["Type"], data['ThumbsCount'], data['RetinasCount']), successActions);
714
  var actions = jQuery(['restore', 'view', 'redolossy', 'redoglossy', 'redolossless']).not(['redo'+data["Type"]]).get();
shortpixel_api.php CHANGED
@@ -651,6 +651,9 @@ class ShortPixelAPI {
651
  }
652
 
653
  static public function getCompressionTypeName($compressionType) {
 
 
 
654
  return 0 + $compressionType == 2 ? 'glossy' : (0 + $compressionType == 1 ? 'lossy' : 'lossless');
655
  }
656
 
651
  }
652
 
653
  static public function getCompressionTypeName($compressionType) {
654
+ if(is_array($compressionType)) {
655
+ return array_map(array('ShortPixelAPI', 'getCompressionTypeName'), $compressionType);
656
+ }
657
  return 0 + $compressionType == 2 ? 'glossy' : (0 + $compressionType == 1 ? 'lossy' : 'lossless');
658
  }
659
 
wp-shortpixel.php CHANGED
@@ -1,9 +1,9 @@
1
- <?php
2
  /**
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.4.2
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -17,7 +17,7 @@ define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
17
 
18
  define('SP_AFFILIATE_CODE', '');
19
 
20
- define('PLUGIN_VERSION', "4.4.2");
21
  define('SP_MAX_TIMEOUT', 10);
22
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
23
  define('SP_BACKUP', 'ShortpixelBackups');
@@ -93,6 +93,101 @@ function shortPixelDeactivatePlugin () {
93
  WPShortPixel::shortPixelDeactivatePlugin();
94
  }
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle incompatibility with Visual Composer
97
  add_action( 'init', 'shortpixelInit');
98
  add_action('ngg_added_new_image', 'shortpixelNggAdd');
@@ -105,4 +200,4 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
105
  register_activation_hook( __FILE__, 'shortPixelActivatePlugin' );
106
  register_deactivation_hook( __FILE__, 'shortPixelDeactivatePlugin' );
107
  }
108
- ?>
1
+ <?php
2
  /**
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.5.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
17
 
18
  define('SP_AFFILIATE_CODE', '');
19
 
20
+ define('PLUGIN_VERSION', "4.5.0");
21
  define('SP_MAX_TIMEOUT', 10);
22
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
23
  define('SP_BACKUP', 'ShortpixelBackups');
93
  WPShortPixel::shortPixelDeactivatePlugin();
94
  }
95
 
96
+
97
+ /**
98
+ * filter function to force wordpress to add our custom srcset values
99
+ * @param array $sources {
100
+ * One or more arrays of source data to include in the 'srcset'.
101
+ *
102
+ * @type type array $width {
103
+ * @type type string $url The URL of an image source.
104
+ * @type type string $descriptor The descriptor type used in the image candidate string,
105
+ * either 'w' or 'x'.
106
+ * @type type int $value The source width, if paired with a 'w' descriptor or a
107
+ * pixel density value if paired with an 'x' descriptor.
108
+ * }
109
+ * }
110
+ * @param array $size_array Array of width and height values in pixels (in that order).
111
+ * @param string $image_src The 'src' of the image.
112
+ * @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
113
+ * @param int $attachment_id Image attachment ID.
114
+ */
115
+ function sp_add_webp_image_srcset( $sources, $size_array, $image_src, $image_meta, $attachment_id ){
116
+
117
+ // image base name
118
+ $image_basename = wp_basename( $image_meta['file'] );
119
+ // upload directory info array
120
+ $upload_dir_info_arr = wp_upload_dir();
121
+ // base url of upload directory
122
+ $image_baseurl = $baseurl = $upload_dir_info_arr['baseurl'];
123
+ $image_basedir = $basedir = $upload_dir_info_arr['basedir'];
124
+
125
+ // Uploads are (or have been) in year/month sub-directories.
126
+ if ( $image_basename !== $image_meta['file'] ) {
127
+ $dirname = dirname( $image_meta['file'] );
128
+
129
+ if ( $dirname !== '.' ) {
130
+ $image_baseurl = trailingslashit( $baseurl ) . $dirname;
131
+ $image_basedir = trailingslashit( $basedir ) . $dirname;
132
+ }
133
+ }
134
+
135
+ $image_baseurl = trailingslashit( $image_baseurl );
136
+ $image_basedir = trailingslashit( $image_basedir );
137
+ // check whether our custom image size exists in image meta
138
+ foreach($image_meta['sizes'] as $key => $size) {
139
+ $fn = $size['file'];
140
+ $ext = pathinfo($fn, PATHINFO_EXTENSION);
141
+ $webp = substr($fn, 0, strlen($fn) - strlen($ext)) . 'webp';
142
+ if( file_exists($image_basedir . $webp) ){
143
+ // add source value to create srcset
144
+ $sources[ 'webp-' . $size['width'] ] = array(
145
+ 'url' => $image_baseurl . $webp,
146
+ 'descriptor' => 'w',
147
+ 'value' => $size['width'],
148
+ );
149
+ }
150
+ }
151
+ //return sources with new srcset value
152
+ return $sources;
153
+ }
154
+ //not really working, the srcset does not accept webp AND other type of image together. Below trying with <picture> ...
155
+ //add_filter( 'wp_calculate_image_srcset', 'sp_add_webp_image_srcset', 10, 5 );
156
+
157
+
158
+
159
+
160
+ //Picture generation, hooked on the_content filter
161
+ function spConvertImgToPictureAddWebp($content) {
162
+ require_once('class/front/img-to-picture-webp.php');
163
+ //require_once('class/responsive-image.php');
164
+ return ImgToPictureWebp::convert($content);
165
+ }
166
+ function spAddPictureJs() {
167
+ // Don't do anything with the RSS feed.
168
+ if ( is_feed() || is_admin() ) { return; }
169
+
170
+ echo '<script>'
171
+ . 'var spPicTest = document.createElement( "picture" );'
172
+ . 'if(!window.HTMLPictureElement && document.addEventListener) {'
173
+ . 'window.addEventListener("DOMContentLoaded", function() {'
174
+ . 'var scriptTag = document.createElement("script");'
175
+ . 'scriptTag.src = "' . plugins_url('/res/js/picturefill.min.js', __FILE__) . '";'
176
+ . 'document.body.appendChild(scriptTag);'
177
+ . '});'
178
+ . '}'
179
+ . '</script>';
180
+ }
181
+ //function spAddPicturefillJs() {
182
+ // wp_enqueue_script( 'picturefill', plugins_url('/res/js/picturefill.min.js', __FILE__), null, null, true);
183
+ //}
184
+ if ( get_option('wp-short-pixel-create-webp-markup')) {
185
+ add_filter( 'the_content', 'spConvertImgToPictureAddWebp' );
186
+ add_action( 'wp_head', 'spAddPictureJs');
187
+ // add_action( 'wp_enqueue_scripts', 'spAddPicturefillJs' );
188
+ }
189
+
190
+
191
  if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle incompatibility with Visual Composer
192
  add_action( 'init', 'shortpixelInit');
193
  add_action('ngg_added_new_image', 'shortpixelNggAdd');
200
  register_activation_hook( __FILE__, 'shortPixelActivatePlugin' );
201
  register_deactivation_hook( __FILE__, 'shortPixelDeactivatePlugin' );
202
  }
203
+ ?>