Changeset 1351884
- Timestamp:
- 02/16/2016 02:38:33 PM (10 years ago)
- Location:
- kraken-image-optimizer
- Files:
-
- 10 edited
-
assets/screenshot-1.png (modified) (previous)
-
assets/screenshot-2.png (modified) (previous)
-
assets/screenshot-3.png (modified) (previous)
-
trunk/css/admin.css (modified) (6 diffs)
-
trunk/css/dist/kraken.min.css (modified) (1 diff)
-
trunk/js/ajax.js (modified) (14 diffs)
-
trunk/js/dist/kraken.min.js (modified) (1 diff)
-
trunk/kraken.php (modified) (28 diffs)
-
trunk/lib/Kraken.php (modified) (5 diffs)
-
trunk/readme.txt (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
kraken-image-optimizer/trunk/css/admin.css
r1144921 r1351884 35 35 clear: left; 36 36 } 37 37 38 .kraken_req, .kraken_req_bulk { 38 border: 1px solid #efab00;39 color: # 222;39 border: none; 40 color: #fff; 40 41 padding: 3px 8px 4px; 41 42 font-size: 11px; 42 text-shadow: 0 1px 0 rgba(255,255,255,0.5); 43 background: #ffc942; 44 background-image: -webkit-gradient(linear,left top,left bottom,from(#ffc942),to(#efab00)); 45 background-image: -webkit-linear-gradient(top,#ffc942,#efab00); 46 background-image: -moz-linear-gradient(top,#ffc942,#efab00); 47 background-image: -o-linear-gradient(top,#ffc942,#efab00); 48 background-image: linear-gradient(to bottom,#ffc942,#efab00); 43 background: #3498DB; 49 44 -webkit-border-radius: 2px; 50 45 -moz-border-radius: 2px; 51 46 border-radius: 2px; 52 47 cursor: pointer; 53 font-weight: bold; 54 } 48 transition: all 0.15s; 49 } 50 51 .kraken_req:hover, 52 .kraken_req_bulk:hover { 53 background: #2881BD; 54 } 55 56 .kraken_req { 57 margin-right: 2px; 58 } 59 55 60 .kraken_req_bulk { 56 61 font-size: 16px; 62 margin: 0 auto; 63 width: 150px; 64 padding: 10px 0; 65 display: block; 66 } 67 68 td.kraken-bulk-filename { 69 width: 360px; 70 max-width: 360px; 71 overflow: hidden; 72 text-overflow: ellipsis; 73 white-space: nowrap; 74 } 75 td.kraken-krakedsize { 76 width: 170px; 57 77 } 58 78 .buttonWrap { … … 116 136 margin-bottom: 10px; 117 137 font-weight: bold; 118 } 138 padding: 15px 20px; 139 border-bottom: 1px solid #ddd; 140 margin: 0; 141 background: #fafafa; 142 position: relative; 143 } 144 145 .krakenBulkHeader span { 146 position: absolute; 147 top: 5px; 148 right: 15px; 149 font-size: 30px; 150 color: #777; 151 } 152 153 .krakenBulkHeader span:hover { 154 color: #222; 155 } 156 119 157 #kraken-bulk-modal { 120 158 position: absolute !important; 121 top: 100px; 159 top: 100px; 122 160 width: 785px; 161 padding: 0 0 20px 0; 123 162 } 124 163 #kraken-bulk-modal label { 125 164 margin-bottom: 11px; 126 165 } 166 127 167 #kraken-bulk { 128 width: 780px; 129 margin: 0 auto; 130 margin-bottom: 10px; 131 border-spacing: 1px; 132 border-collapse: separate; 133 } 168 width: 770px; 169 margin: 0 auto 20px; 170 border-collapse: collapse; 171 } 172 173 #kraken-bulk td { 174 border: 1px solid #ddd; 175 padding: 5px 10px; 176 } 177 178 #kraken-bulk tr:nth-child(odd) { 179 background-color: #eee; 180 } 181 182 #kraken-bulk-modal .the-following { 183 margin: 0; 184 text-align: center; 185 padding: 15px 0; 186 } 187 134 188 .kraken-bulk-header td { 135 189 font-weight: bold; 136 font-size: 14px; 137 padding: 4px 0 4px 2px; 138 } 190 font-size: 13px; 191 padding: 7px 10px !important; 192 background: #ddd; 193 color: #212121; 194 border: 1px solid #ccc !important; 195 } 196 139 197 td.kraken-krakedsize { 140 198 text-align: left; … … 157 215 cursor: pointer; 158 216 } 217 159 218 .radiosWrap { 160 display: inline-block; 161 margin: 0 0 5px 4px; 162 } 219 width: 100%; 220 text-align: center; 221 padding: 15px 0; 222 border-bottom: 1px solid #ddd; 223 } 224 225 .radiosWrap p { 226 padding: 0; 227 margin: 0 0 5px 0; 228 font-weight: bold; 229 } 230 231 .radiosWrap input[type="radio"] { 232 margin-top: -1px; 233 vertical-align: middle; 234 } 235 163 236 .kraken-bulk-small { 164 237 font-size: 12px; … … 178 251 height: 10px; 179 252 background: url('https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif') no-repeat 0 0; 180 background-size: 10px; 253 background-size: 10px; 181 254 } 182 255 h1.kraken-admin-section-title { … … 197 270 } 198 271 td.krakenAdvancedSettings { 199 padding: 0;272 padding: 20px 0 0 0 !important; 200 273 } 201 274 td.krakenAdvancedSettingsDescription { 202 275 padding: 0; 203 padding -bottom: 10px;276 padding: 10px 0 !important; 204 277 } 205 278 td.krakenAdvancedSettings h3 { … … 231 304 } 232 305 .kraken-advanced-settings { 233 display: none;306 /*display: none;*/ 234 307 } 235 308 #krakenSettings .form-table { 236 309 margin-bottom: 30px; 237 310 } 311 238 312 #krakenSettings .form-table th { 239 width: 370px; 240 } 313 width: 270px; 314 border-bottom: 1px solid #ddd; 315 padding: 25px 0; 316 } 317 318 #krakenSettings .form-table td { 319 border-bottom: 1px solid #ddd; 320 padding: 25px 0; 321 } 322 323 #krakenSettings .form-table .no-border td, 324 #krakenSettings .form-table .no-border th { 325 border: none; 326 } 327 328 #krakenSettings .form-table .with-tip td, 329 #krakenSettings .form-table .with-tip th { 330 border-bottom: none; 331 padding-bottom: 10px; 332 } 333 334 .tip td { 335 padding: 10px 0 20px 0 !important; 336 } 337 338 .tip td div { 339 border: 1px solid #BCE8F1; 340 background: #D9EDF7; 341 padding: 5px 10px; 342 line-height: 20px; 343 font-size: 12px; 344 } 345 241 346 .kraken.error.settings-error, .kraken.updated.settings-error { 242 347 margin-bottom: 30px; 243 348 } 349 .blog-kraker-info-block-wrap { 350 margin-top: 10px; 351 margin-left: 10px; 352 padding-bottom: 110px; 353 width: 600px; 354 } 355 .blog-kraker-image-summary { 356 width: 50%; 357 float: left; 358 } 359 .blog-kraker-kraken-statistics { 360 width: 50%; 361 float: right; 362 } 363 input[name=blog_kraker_mode] { 364 margin-right: 10px; 365 } 366 label[for=blog_kraker_mode_thumbs] { 367 margin-right: 10px; 368 } 369 .kraken-item-details { 370 cursor: pointer; 371 text-decoration: underline; 372 } -
kraken-image-optimizer/trunk/css/dist/kraken.min.css
r1144921 r1351884 1 .tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow{border-top:none;top:0;border-bottom-style:solid}. tipsy-inner,td.kraken-krakedsize{text-align:left}.kraken-plus-minus,td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none}.kraken-modal{display:none;width:600px;background:#fff;padding:15px 30px;border-radius:8px;-webkit-box-shadow:0 0 10px #000;-moz-box-shadow:0 0 10px #000;-o-box-shadow:0 0 10px #000;-ms-box-shadow:0 0 10px #000;box-shadow:0 0 10px #000}.kraken-modal,.kraken-modal-spinner{-o-border-radius:8px;-ms-border-radius:8px;-webkit-border-radius:8px;-moz-border-radius:8px}.kraken-modal-spinner{display:none;width:64px;height:64px;position:fixed;top:50%;left:50%;margin-right:-32px;margin-top:-32px;background:url(spinner.gif)center center no-repeat #111;border-radius:8px}.tipsy{font-size:10px;position:absolute;padding:5px;z-index:100000}.tipsy-inner{background-color:#000;color:#FFF;max-width:300px;padding:5px 8px 4px;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:0 0 5px #000;-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000}.head_cell,.head_file_name,.item_file_name{height:20px;padding-top:5px}.tipsy-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.tipsy-arrow-n{border-bottom-color:#000}.tipsy-arrow-s{border-top-color:#000}.tipsy-arrow-e{border-left-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-left-color:transparent}.tipsy-arrow-w{border-right-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-right-color:transparent}.tipsy-n .tipsy-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none}.tipsy-nw .tipsy-arrow{left:10px}.tipsy-ne .tipsy-arrow{right:10px}.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-bottom:none;border-top-style:solid}.tipsy-e .tipsy-arrow,.tipsy-w .tipsy-arrow{border-bottom-color:transparent;top:50%;border-top-color:transparent}.tipsy-s .tipsy-arrow{bottom:0;left:50%;margin-left:-5px}.tipsy-sw .tipsy-arrow{bottom:0;left:10px}.tipsy-se .tipsy-arrow{bottom:0;right:10px}.tipsy-e .tipsy-arrow{right:0;margin-top:-5px;border-left-style:solid;border-right:none}.tipsy-w .tipsy-arrow{left:0;margin-top:-5px;border-right-style:solid;border-left:none}.item_cell,.item_file_name{background-color:#F8F8F8;margin-top:5px}.head_cell{float:left;width:10em;background-color:#F0F0F0}.head_file_name{float:left;width:30em;background-color:#F0F0F0;padding-left:2px}.item_cell{float:left;width:10em;height:20px;padding-top:5px}.item_file_name{float:left;width:30em;padding-left:2px}.apiInvalid,.apiValid{position:absolute;width:16px}#kraken_loading{float:left;clear:left}.kraken_req,.kraken_req_bulk{border:1px solid #efab00;color:#222;padding:3px 8px 4px;font-size:11px;text-shadow:0 1px 0 rgba(255,255,255,.5);background:#ffc942;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffc942),to(#efab00));background-image:-webkit-linear-gradient(top,#ffc942,#efab00);background-image:-moz-linear-gradient(top,#ffc942,#efab00);background-image:-o-linear-gradient(top,#ffc942,#efab00);background-image:linear-gradient(to bottom,#ffc942,#efab00);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;font-weight:700}.krakenBulkSpinner,.krakenSpinner,.resetSpinner{background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat}.kraken_req_bulk{font-size:16px}.buttonWrap{position:relative;margin-bottom:5px}.apiValid{left:0;display:inline-block;height:16px;top:3px}.apiInvalid{left:0;display:inline-block;height:16px;top:2px}p.apiStatus{padding-left:26px;position:relative;width:400px}.krakenSpinner{display:none;position:absolute;width:16px;height:16px;top:5px}.krakenBulkSpinner{display:none;padding:0;margin:0;width:16px;height:16px}.krakenError,.noSavings{margin-left:2px}.kraken-bulk-small,.kraken-plus-minus,.radiosWrap,.resetSpinner,.visible{display:inline-block}.krakenErrorWrap{margin-top:10px;margin-bottom:4px}.krakenError{font-weight:700;color:#dd3d36}.krakenBulkHeader{font-size:16px;margin-bottom:10px;font-weight:700}#kraken-bulk-modal{position:absolute!important;top:100px;width:785px}#kraken-bulk-modal label{margin-bottom:11px}#kraken-bulk{width:780px;margin:0 auto 10px;border-spacing:1px;border-collapse:separate}.kraken-bulk-header td{font-weight:700;font-size:14px;padding:4px 0 4px 2px}tr.kraken-item-row td{padding:2px;height:20px}span.kraken-bulk-choose-type{font-weight:700;margin-right:5px}#kraken-bulk-type-lossy{margin-right:5px}.close-kraken-bulk{font-size:12px;margin-left:10px;font-weight:700;cursor:pointer}.radiosWrap{margin:0 0 5px 4px}.kraken-bulk-small{font-size:12px;margin:0 0 4px 4px}small.krakenReset{text-decoration:underline;cursor:pointer}.resetSpinner{margin-right:3px;margin-top:4px;vertical-align:baseline;width:10px;height:10px;background-size:10px}h1.kraken-admin-section-title{margin-bottom:30px}.kraken_show_reset{margin-right:11px}small.krakenWhatsThis{font-size:9px}span.kraken-reset-all{font-size:11px}span.kraken-reset-all.enabled{text-decoration:underline;cursor:pointer}td.krakenAdvancedSettings{padding:0}td.krakenAdvancedSettingsDescription{padding:0 0 10px}td.krakenAdvancedSettings h3{margin-bottom:2px}#krakenSettings .form-table,.kraken.error.settings-error,.kraken.updated.settings-error{margin-bottom:30px}td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{cursor:pointer;color:#45bbe6;user-select:none}td.krakenAdvancedSettings h3 span.kraken-advanced-toggle{color:#45bbe6;font-size:10px}.kraken-plus-minus{cursor:pointer;line-height:24px;width:20px;user-select:none}.kraken-advanced-settings{display:none}#krakenSettings .form-table th{width:370px}1 .tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow{border-top:none;top:0;border-bottom-style:solid}.kraken-plus-minus,td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none}.kraken-modal{display:none;width:600px;background:#fff;padding:15px 30px;border-radius:8px;-webkit-box-shadow:0 0 10px #000;-moz-box-shadow:0 0 10px #000;-o-box-shadow:0 0 10px #000;-ms-box-shadow:0 0 10px #000;box-shadow:0 0 10px #000}.kraken-modal,.kraken-modal-spinner{-o-border-radius:8px;-ms-border-radius:8px;-webkit-border-radius:8px;-moz-border-radius:8px}.kraken-modal-spinner{display:none;width:64px;height:64px;position:fixed;top:50%;left:50%;margin-right:-32px;margin-top:-32px;background:url(spinner.gif)center center no-repeat #111;border-radius:8px}.tipsy{font-size:10px;position:absolute;padding:5px;z-index:100000}.tipsy-inner{background-color:#000;color:#FFF;max-width:300px;padding:5px 8px 4px;text-align:left;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:0 0 5px #000;-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000}.head_cell,.head_file_name,.item_file_name{height:20px;padding-top:5px}.tipsy-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.tipsy-arrow-n{border-bottom-color:#000}.tipsy-arrow-s{border-top-color:#000}.tipsy-arrow-e{border-left-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-left-color:transparent}.tipsy-arrow-w{border-right-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-right-color:transparent}.tipsy-n .tipsy-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none}.tipsy-nw .tipsy-arrow{left:10px}.tipsy-ne .tipsy-arrow{right:10px}.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-bottom:none;border-top-style:solid}.tipsy-e .tipsy-arrow,.tipsy-w .tipsy-arrow{border-bottom-color:transparent;top:50%;border-top-color:transparent}.tipsy-s .tipsy-arrow{bottom:0;left:50%;margin-left:-5px}.tipsy-sw .tipsy-arrow{bottom:0;left:10px}.tipsy-se .tipsy-arrow{bottom:0;right:10px}.tipsy-e .tipsy-arrow{right:0;margin-top:-5px;border-left-style:solid;border-right:none}.tipsy-w .tipsy-arrow{left:0;margin-top:-5px;border-right-style:solid;border-left:none}.item_cell,.item_file_name{background-color:#F8F8F8;margin-top:5px}.head_cell{float:left;width:10em;background-color:#F0F0F0}.head_file_name{float:left;width:30em;background-color:#F0F0F0;padding-left:2px}.item_cell{float:left;width:10em;height:20px;padding-top:5px}.item_file_name{float:left;width:30em;padding-left:2px}#kraken_loading{float:left;clear:left}.kraken_req,.kraken_req_bulk{border:none;color:#fff;padding:3px 8px 4px;font-size:11px;background:#3498DB;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;transition:all .15s}.kraken_req:hover,.kraken_req_bulk:hover{background:#2881BD}.krakenBulkSpinner,.krakenSpinner{background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat}.kraken_req{margin-right:2px}.kraken_req_bulk{font-size:16px;margin:0 auto;width:150px;padding:10px 0;display:block}td.kraken-bulk-filename{width:360px;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}td.kraken-krakedsize{width:170px}.apiInvalid,.apiValid{position:absolute;width:16px}.buttonWrap{position:relative;margin-bottom:5px}.apiValid{left:0;display:inline-block;height:16px;top:3px}.apiInvalid{left:0;display:inline-block;height:16px;top:2px}p.apiStatus{padding-left:26px;position:relative;width:400px}.krakenSpinner{display:none;position:absolute;width:16px;height:16px;top:5px}.krakenBulkSpinner{display:none;padding:0;margin:0;width:16px;height:16px}.krakenError,.noSavings{margin-left:2px}.kraken-bulk-small,.kraken-plus-minus,.resetSpinner,.visible{display:inline-block}.krakenErrorWrap{margin-top:10px;margin-bottom:4px}.krakenError{font-weight:700;color:#dd3d36}.krakenBulkHeader{font-size:16px;font-weight:700;padding:15px 20px;border-bottom:1px solid #ddd;margin:0;background:#fafafa;position:relative}.krakenBulkHeader span{position:absolute;top:5px;right:15px;font-size:30px;color:#777}.krakenBulkHeader span:hover{color:#222}#kraken-bulk-modal{position:absolute!important;top:100px;width:785px;padding:0 0 20px}#kraken-bulk-modal label{margin-bottom:11px}#kraken-bulk{width:770px;margin:0 auto 20px;border-collapse:collapse}#kraken-bulk td{border:1px solid #ddd;padding:5px 10px}#kraken-bulk tr:nth-child(odd){background-color:#eee}#kraken-bulk-modal .the-following{margin:0;text-align:center;padding:15px 0}.kraken-bulk-header td{font-weight:700;font-size:13px;padding:7px 10px!important;background:#ddd;color:#212121;border:1px solid #ccc!important}td.kraken-krakedsize{text-align:left}tr.kraken-item-row td{padding:2px;height:20px}span.kraken-bulk-choose-type{font-weight:700;margin-right:5px}#kraken-bulk-type-lossy{margin-right:5px}.close-kraken-bulk{font-size:12px;margin-left:10px;font-weight:700;cursor:pointer}.radiosWrap{width:100%;text-align:center;padding:15px 0;border-bottom:1px solid #ddd}.radiosWrap p{padding:0;margin:0 0 5px;font-weight:700}.radiosWrap input[type=radio]{margin-top:-1px;vertical-align:middle}.kraken-bulk-small{font-size:12px;margin:0 0 4px 4px}small.krakenReset{text-decoration:underline;cursor:pointer}.resetSpinner{margin-right:3px;margin-top:4px;vertical-align:baseline;width:10px;height:10px;background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat;background-size:10px}h1.kraken-admin-section-title{margin-bottom:30px}.kraken_show_reset{margin-right:11px}small.krakenWhatsThis{font-size:9px}span.kraken-reset-all{font-size:11px}span.kraken-reset-all.enabled{text-decoration:underline;cursor:pointer}td.krakenAdvancedSettings{padding:20px 0 0!important}td.krakenAdvancedSettingsDescription{padding:10px 0!important}td.krakenAdvancedSettings h3{margin-bottom:2px}#krakenSettings .form-table,.kraken.error.settings-error,.kraken.updated.settings-error{margin-bottom:30px}td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{cursor:pointer;color:#45bbe6;user-select:none}td.krakenAdvancedSettings h3 span.kraken-advanced-toggle{color:#45bbe6;font-size:10px}.kraken-plus-minus{cursor:pointer;line-height:24px;width:20px;user-select:none}#krakenSettings .form-table th{width:270px;border-bottom:1px solid #ddd;padding:25px 0}#krakenSettings .form-table td{border-bottom:1px solid #ddd;padding:25px 0}#krakenSettings .form-table .no-border td,#krakenSettings .form-table .no-border th{border:none}#krakenSettings .form-table .with-tip td,#krakenSettings .form-table .with-tip th{border-bottom:none;padding-bottom:10px}.tip td{padding:10px 0 20px!important}.tip td div{border:1px solid #BCE8F1;background:#D9EDF7;padding:5px 10px;line-height:20px;font-size:12px}.blog-kraker-info-block-wrap{margin-top:10px;margin-left:10px;padding-bottom:110px;width:600px}.blog-kraker-image-summary{width:50%;float:left}.blog-kraker-kraken-statistics{width:50%;float:right}input[name=blog_kraker_mode],label[for=blog_kraker_mode_thumbs]{margin-right:10px}.kraken-item-details{cursor:pointer;text-decoration:underline} -
kraken-image-optimizer/trunk/js/ajax.js
r1144921 r1351884 1 1 jQuery(document).ready(function($) { 2 2 3 var errors = [{ 4 code: 401, 5 msg: 'Unnknown API Key. Please check your API key and try again' 6 }, { 7 code: 403, 8 msg: 'Your account has been temporarily suspended' 9 }, { 10 code: 413, 11 msg: 'File size too large. The maximum file size for your plan is 1048576 bytes' 12 }, { 13 code: 415, 14 msg: 'File type not supported' 15 }, { 16 code: 415, 17 msg: 'WebP compression is non available for SVG images' 18 }, { 19 code: 422, 20 msg: 'You need to specify either callback_url or wait flag' 21 }, { 22 code: 422, 23 msg: 'This image can not be optimized any further' 24 }, { 25 code: 500, 26 msg: 'Kraken has encountered an unexpected error and cannot fulfill your request' 27 }, { 28 code: 502, 29 msg: 'Couldn\'t get this file' 30 }]; 31 3 var tipsySettings = { 4 gravity: 'e', 5 html: true, 6 trigger: 'manual', 7 className: function() { 8 return 'tipsy-' + $(this).data('id'); 9 }, 10 title: function() { 11 activeId = $(this).data('id'); 12 return $(this).attr('original-title'); 13 } 14 } 32 15 33 16 $('.krakenWhatsThis').tipsy({ 34 17 fade: true, 35 18 gravity: 'w' 19 }); 20 21 $('.krakenError').tipsy({ 22 fade: true, 23 gravity: 'e' 36 24 }); 37 25 … … 49 37 var requestSuccess = function(data, textStatus, jqXHR) { 50 38 var $button = $(this), 51 $parent = $(this). parent(),39 $parent = $(this).closest('.kraken-wrap, .buttonWrap'), 52 40 $cell = $(this).closest("td"); 53 41 54 if (data.success && typeof data.error === 'undefined') { 55 42 if (data.html) { 56 43 $button.text("Image optimized"); 57 44 58 45 var type = data.type, 59 krakedSize = data.kraked_size,60 46 originalSize = data.original_size, 61 savingsPercent = data.savings_percent,62 47 $originalSizeColumn = $(this).parent().prev("td.original_size"), 63 48 krakedData = ''; 64 49 65 50 $parent.fadeOut("fast", function() { 66 $cell.find(".noSavings, .krakenErrorWrap").remove(); 67 $(this).replaceWith(data.html); 51 $cell 52 .find(".noSavings, .krakenErrorWrap") 53 .remove(); 54 $cell.html(data.html); 55 $cell.find('.kraken-item-details') 56 .tipsy(tipsySettings); 68 57 $originalSizeColumn.html(originalSize); 69 58 $parent.remove(); … … 138 127 }; 139 128 129 var bulkModalOptions = { 130 zIndex: 4, 131 escapeClose: true, 132 clickClose: false, 133 closeText: 'close', 134 showClose: false 135 }; 136 140 137 var renderBulkImageSummary = function(bulkImageData) { 141 var modalOptions = { 142 zIndex: 4, 143 escapeClose: true, 144 clickClose: false, 145 closeText: 'close', 146 showClose: false 147 }, 148 setting = kraken_settings.api_lossy, 149 nImages = bulkImageData.length, 150 header = '<p class="krakenBulkHeader">Kraken Bulk Image Optimization</p>', 151 krakEmAll = '<button class="kraken_req_bulk">Krak \'em all</button>', 152 typeRadios = '<span class="radiosWrap"><span class="kraken-bulk-choose-type">Choose:</span>' + '<input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>' + '<label for="kraken-bulk-type-lossy">Lossy</label> ' + '<input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>' + '<label for="kraken-bulk-type-lossless">Lossless</label></span>', 153 $modal = $('<div id="kraken-bulk-modal" class="kraken-modal"></div>') 154 .html(header) 155 .append(typeRadios) 156 .append('<br /><small class="kraken-bulk-small">The following <strong>' + nImages + '</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">' + setting + '</strong> setting:</small><br />') 157 .appendTo("body") 158 .kmodal(modalOptions) 159 .bind($.kmodal.BEFORE_CLOSE, function(event, modal) { 160 161 }) 162 .bind($.kmodal.OPEN, function(event, modal) { 163 164 }) 165 .bind($.kmodal.CLOSE, function(event, modal) { 166 $("#kraken-bulk-modal").remove(); 167 }) 168 .css({ 169 top: "10px", 170 marginTop: "40px" 171 }); 172 173 if (setting === 'lossy') { 138 var setting = kraken_settings.api_lossy; 139 var nImages = bulkImageData.length; 140 var header = '<p class="krakenBulkHeader">Kraken Bulk Image Optimization <span class="close-kraken-bulk">×</span></p>'; 141 var krakEmAll = '<button class="kraken_req_bulk">Krak \'em all</button>'; 142 var typeRadios = '<div class="radiosWrap"><p>Choose optimization mode:</p><label><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>Intelligent Lossy</label> <label><input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>Lossless</label></div>'; 143 144 var $modal = $('<div id="kraken-bulk-modal" class="kraken-modal"></div>') 145 .html(header) 146 .append(typeRadios) 147 .append('<p class="the-following">The following <strong>' + nImages + '</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">' + setting + '</strong> setting:</p>') 148 .appendTo("body") 149 .kmodal(bulkModalOptions) 150 .bind($.kmodal.BEFORE_CLOSE, function(event, modal) { 151 152 }) 153 .bind($.kmodal.OPEN, function(event, modal) { 154 155 }) 156 .bind($.kmodal.CLOSE, function(event, modal) { 157 $("#kraken-bulk-modal").remove(); 158 }) 159 .css({ 160 top: "10px", 161 marginTop: "40px" 162 }); 163 164 if (setting === "lossy") { 174 165 $("#kraken-bulk-type-lossy").attr("checked", true); 175 166 } else { … … 194 185 195 186 var $table = $('<table id="kraken-bulk"></table>'), 196 $headerRow = $('<tr class="kraken-bulk-header"><td>File </td><td style="width:120px">Original Size</td><td style="width:120px">Kraked Size</td><td style="width:120px">Savings</td><td style="width:120px">% Savings</td></tr>');187 $headerRow = $('<tr class="kraken-bulk-header"><td>File Name</td><td style="width:120px">Original Size</td><td style="width:120px">Kraken.io Stats</td></tr>'); 197 188 198 189 $table.append($headerRow); 199 190 $.each(bulkImageData, function(index, element) { 200 $table.append('<tr class="kraken-item-row" data-krakenbulkid="' + element.id + '"><td class="kraken- filename">' + element.filename + '</td><td class="kraken-originalsize">' + element.originalSize + '</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td><td class="kraken-savings"></td><td class="kraken-savingsPercent"></td></tr>');191 $table.append('<tr class="kraken-item-row" data-krakenbulkid="' + element.id + '"><td class="kraken-bulk-filename">' + element.filename + '</td><td class="kraken-originalsize">' + element.originalSize + '</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td></tr>'); 201 192 }); 202 193 203 194 $modal 204 195 .append($table) 205 .append(krakEmAll) 206 .append('<span class="close-kraken-bulk">Close Window</span>'); 196 .append(krakEmAll); 207 197 208 198 $(".close-kraken-bulk").click(function() { … … 218 208 } 219 209 }; 210 220 211 221 212 var bulkAction = function(bulkImageData) { … … 243 234 'action': 'kraken_request', 244 235 'id': id, 245 'type': $("input[name='kraken-bulk-type']:checked").val().toLowerCase() 236 'type': $("input[name='kraken-bulk-type']:checked").val().toLowerCase(), 237 'origin': 'bulk_optimizer' 246 238 }, 247 239 type: "post", … … 250 242 }) 251 243 .done(function(data, textStatus, jqXHR) { 252 if (data.success && typeof data. error=== 'undefined') {244 if (data.success && typeof data.message === 'undefined') { 253 245 var type = data.type, 254 246 originalSize = data.original_size, 255 krakedSize = data. kraked_size,247 krakedSize = data.html, 256 248 savingsPercent = data.savings_percent, 257 249 savingsBytes = data.saved_bytes; 258 250 259 $krakedSizeColumn.text(krakedSize); 251 $krakedSizeColumn.html(data.html); 252 253 $krakedSizeColumn 254 .find('.kraken-item-details') 255 .remove(); 256 260 257 $savingsPercentColumn.text(savingsPercent); 261 258 $savingsBytesColumn.text(savingsBytes); … … 264 261 $parent = $button.parent(), 265 262 $cell = $button.closest("td"), 266 $originalSizeColumn = $button.parent().prev("td.original_size") 263 $originalSizeColumn = $button.parent().prev("td.original_size"); 267 264 268 265 269 266 $parent.fadeOut("fast", function() { 270 267 $cell.find(".noSavings, .krakenErrorWrap").remove(); 271 krakedData = '<strong>' + krakedSize + '</strong><br /><small>Type: ' + type + '</small><br /><small>Savings: ' + savingsPercent + '</small>'; 272 if (typeof data.thumbs_data !== 'undefined') { 273 krakedData += '<br /><small>' + data.thumbs_data.length + ' thumbs optimized</small>'; 274 } 275 $(this).replaceWith(krakedData); 268 $cell 269 .empty() 270 .html(data.html); 271 $cell 272 .find('.kraken-item-details') 273 .tipsy(tipsySettings); 276 274 $originalSizeColumn.html(originalSize); 277 275 $parent.remove(); … … 285 283 } 286 284 } 287 288 285 }) 289 286 … … 339 336 }); 340 337 338 var activeId = null; 339 $('.kraken-item-details').tipsy(tipsySettings); 340 341 var $activePopup = null; 342 $('body').on('click', '.kraken-item-details', function(e) { 343 //$('.tipsy[class="tipsy-' + activeId + '"]').remove(); 344 345 var id = $(this).data('id'); 346 $('.tipsy').remove(); 347 if (id == activeId) { 348 activeId = null; 349 $(this).text('Show details'); 350 return; 351 } 352 $('.kraken-item-details').text('Show details'); 353 $(this).tipsy('show'); 354 $(this).text('Hide details'); 355 }); 356 357 $('body').on('click', function(e) { 358 var $t = $(e.target); 359 if (($t.hasClass('tipsy') || $t.closest('.tipsy').length) || $t.hasClass('kraken-item-details')) { 360 return; 361 } else { 362 activeId = null; 363 $('.kraken-item-details').text('Show details'); 364 $('.tipsy').remove(); 365 } 366 }); 367 341 368 $('body').on('click', 'small.krakenReset', function(e) { 342 369 e.preventDefault(); … … 345 372 action: 'kraken_reset' 346 373 }; 374 347 375 resetData.id = $(this).data("id"); 376 $row = $('#post-' + resetData.id).find('.kraked_size'); 348 377 349 378 var $spinner = $('<span class="resetSpinner"></span>'); … … 359 388 .done(function(data, textStatus, jqXHR) { 360 389 if (data.success !== 'undefined') { 361 $resetButton 362 .closest('.kraked_size.column-kraked_size') 390 $row 363 391 .hide() 364 392 .html(data.html) … … 366 394 .prev(".original_size.column-original_size") 367 395 .html(data.original_size); 396 397 $('.tipsy').remove(); 368 398 } 369 399 }); … … 418 448 $plusMinus 419 449 .removeClass('dashicons-arrow-right') 420 .addClass('dashicons-arrow-down'); 450 .addClass('dashicons-arrow-down'); 421 451 } 422 452 }); -
kraken-image-optimizer/trunk/js/dist/kraken.min.js
r1144921 r1351884 1 !function(){function only_once(fn){var called=!1;return function(){if(called)throw new Error("Callback was already called.");called=!0,fn.apply(root,arguments)}}var root,previous_async,async={};root=this,null!=root&&(previous_async=root.async),async.noConflict=function(){return root.async=previous_async,async};var _each=function(arr,iterator){if(arr.forEach)return arr.forEach(iterator);for(var i=0;i<arr.length;i+=1)iterator(arr[i],i,arr)},_map=function(arr,iterator){if(arr.map)return arr.map(iterator);var results=[];return _each(arr,function(x,i,a){results.push(iterator(x,i,a))}),results},_reduce=function(arr,iterator,memo){return arr.reduce?arr.reduce(iterator,memo):(_each(arr,function(x,i,a){memo=iterator(memo,x,i,a)}),memo)},_keys=function(obj){if(Object.keys)return Object.keys(obj);var keys=[];for(var k in obj)obj.hasOwnProperty(k)&&keys.push(k);return keys};"undefined"!=typeof process&&process.nextTick?(async.nextTick=process.nextTick,"undefined"!=typeof setImmediate?async.setImmediate=function(fn){setImmediate(fn)}:async.setImmediate=async.nextTick):"function"==typeof setImmediate?(async.nextTick=function(fn){setImmediate(fn)},async.setImmediate=async.nextTick):(async.nextTick=function(fn){setTimeout(fn,0)},async.setImmediate=async.nextTick),async.each=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0;_each(arr,function(x){iterator(x,only_once(function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length&&callback(null))}))})},async.forEach=async.each,async.eachSeries=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0,iterate=function(){iterator(arr[completed],function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length?callback(null):iterate())})};iterate()},async.forEachSeries=async.eachSeries,async.eachLimit=function(arr,limit,iterator,callback){var fn=_eachLimit(limit);fn.apply(null,[arr,iterator,callback])},async.forEachLimit=async.eachLimit;var _eachLimit=function(limit){return function(arr,iterator,callback){if(callback=callback||function(){},!arr.length||0>=limit)return callback();var completed=0,started=0,running=0;!function replenish(){if(completed>=arr.length)return callback();for(;limit>running&&started<arr.length;)started+=1,running+=1,iterator(arr[started-1],function(err){err?(callback(err),callback=function(){}):(completed+=1,running-=1,completed>=arr.length?callback():replenish())})}()}},doParallel=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.each].concat(args))}},doParallelLimit=function(limit,fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[_eachLimit(limit)].concat(args))}},doSeries=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.eachSeries].concat(args))}},_asyncMap=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(err,v){results[x.index]=v,callback(err)})},function(err){callback(err,results)})};async.map=doParallel(_asyncMap),async.mapSeries=doSeries(_asyncMap),async.mapLimit=function(arr,limit,iterator,callback){return _mapLimit(limit)(arr,iterator,callback)};var _mapLimit=function(limit){return doParallelLimit(limit,_asyncMap)};async.reduce=function(arr,memo,iterator,callback){async.eachSeries(arr,function(x,callback){iterator(memo,x,function(err,v){memo=v,callback(err)})},function(err){callback(err,memo)})},async.inject=async.reduce,async.foldl=async.reduce,async.reduceRight=function(arr,memo,iterator,callback){var reversed=_map(arr,function(x){return x}).reverse();async.reduce(reversed,memo,iterator,callback)},async.foldr=async.reduceRight;var _filter=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v&&results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.filter=doParallel(_filter),async.filterSeries=doSeries(_filter),async.select=async.filter,async.selectSeries=async.filterSeries;var _reject=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v||results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.reject=doParallel(_reject),async.rejectSeries=doSeries(_reject);var _detect=function(eachfn,arr,iterator,main_callback){eachfn(arr,function(x,callback){iterator(x,function(result){result?(main_callback(x),main_callback=function(){}):callback()})},function(err){main_callback()})};async.detect=doParallel(_detect),async.detectSeries=doSeries(_detect),async.some=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v&&(main_callback(!0),main_callback=function(){}),callback()})},function(err){main_callback(!1)})},async.any=async.some,async.every=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v||(main_callback(!1),main_callback=function(){}),callback()})},function(err){main_callback(!0)})},async.all=async.every,async.sortBy=function(arr,iterator,callback){async.map(arr,function(x,callback){iterator(x,function(err,criteria){err?callback(err):callback(null,{value:x,criteria:criteria})})},function(err,results){if(err)return callback(err);var fn=function(left,right){var a=left.criteria,b=right.criteria;return b>a?-1:a>b?1:0};callback(null,_map(results.sort(fn),function(x){return x.value}))})},async.auto=function(tasks,callback){callback=callback||function(){};var keys=_keys(tasks);if(!keys.length)return callback(null);var results={},listeners=[],addListener=function(fn){listeners.unshift(fn)},removeListener=function(fn){for(var i=0;i<listeners.length;i+=1)if(listeners[i]===fn)return void listeners.splice(i,1)},taskComplete=function(){_each(listeners.slice(0),function(fn){fn()})};addListener(function(){_keys(results).length===keys.length&&(callback(null,results),callback=function(){})}),_each(keys,function(k){var task=tasks[k]instanceof Function?[tasks[k]]:tasks[k],taskCallback=function(err){var args=Array.prototype.slice.call(arguments,1);if(args.length<=1&&(args=args[0]),err){var safeResults={};_each(_keys(results),function(rkey){safeResults[rkey]=results[rkey]}),safeResults[k]=args,callback(err,safeResults),callback=function(){}}else results[k]=args,async.setImmediate(taskComplete)},requires=task.slice(0,Math.abs(task.length-1))||[],ready=function(){return _reduce(requires,function(a,x){return a&&results.hasOwnProperty(x)},!0)&&!results.hasOwnProperty(k)};if(ready())task[task.length-1](taskCallback,results);else{var listener=function(){ready()&&(removeListener(listener),task[task.length-1](taskCallback,results))};addListener(listener)}})},async.waterfall=function(tasks,callback){if(callback=callback||function(){},tasks.constructor!==Array){var err=new Error("First argument to waterfall must be an array of functions");return callback(err)}if(!tasks.length)return callback();var wrapIterator=function(iterator){return function(err){if(err)callback.apply(null,arguments),callback=function(){};else{var args=Array.prototype.slice.call(arguments,1),next=iterator.next();args.push(next?wrapIterator(next):callback),async.setImmediate(function(){iterator.apply(null,args)})}}};wrapIterator(async.iterator(tasks))()};var _parallel=function(eachfn,tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)eachfn.map(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};eachfn.each(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}};async.parallel=function(tasks,callback){_parallel({map:async.map,each:async.each},tasks,callback)},async.parallelLimit=function(tasks,limit,callback){_parallel({map:_mapLimit(limit),each:_eachLimit(limit)},tasks,callback)},async.series=function(tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)async.mapSeries(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};async.eachSeries(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}},async.iterator=function(tasks){var makeCallback=function(index){var fn=function(){return tasks.length&&tasks[index].apply(null,arguments),fn.next()};return fn.next=function(){return index<tasks.length-1?makeCallback(index+1):null},fn};return makeCallback(0)},async.apply=function(fn){var args=Array.prototype.slice.call(arguments,1);return function(){return fn.apply(null,args.concat(Array.prototype.slice.call(arguments)))}};var _concat=function(eachfn,arr,fn,callback){var r=[];eachfn(arr,function(x,cb){fn(x,function(err,y){r=r.concat(y||[]),cb(err)})},function(err){callback(err,r)})};async.concat=doParallel(_concat),async.concatSeries=doSeries(_concat),async.whilst=function(test,iterator,callback){test()?iterator(function(err){return err?callback(err):void async.whilst(test,iterator,callback)}):callback()},async.doWhilst=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?async.doWhilst(iterator,test,callback):callback())})},async.until=function(test,iterator,callback){test()?callback():iterator(function(err){return err?callback(err):void async.until(test,iterator,callback)})},async.doUntil=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?callback():async.doUntil(iterator,test,callback))})},async.queue=function(worker,concurrency){function _insert(q,data,pos,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){var item={data:task,callback:"function"==typeof callback?callback:null};pos?q.tasks.unshift(item):q.tasks.push(item),q.saturated&&q.tasks.length===concurrency&&q.saturated(),async.setImmediate(q.process)})}void 0===concurrency&&(concurrency=1);var workers=0,q={tasks:[],concurrency:concurrency,saturated:null,empty:null,drain:null,push:function(data,callback){_insert(q,data,!1,callback)},unshift:function(data,callback){_insert(q,data,!0,callback)},process:function(){if(workers<q.concurrency&&q.tasks.length){var task=q.tasks.shift();q.empty&&0===q.tasks.length&&q.empty(),workers+=1;var next=function(){workers-=1,task.callback&&task.callback.apply(task,arguments),q.drain&&q.tasks.length+workers===0&&q.drain(),q.process()},cb=only_once(next);worker(task.data,cb)}},length:function(){return q.tasks.length},running:function(){return workers}};return q},async.cargo=function(worker,payload){var working=!1,tasks=[],cargo={tasks:tasks,payload:payload,saturated:null,empty:null,drain:null,push:function(data,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){tasks.push({data:task,callback:"function"==typeof callback?callback:null}),cargo.saturated&&tasks.length===payload&&cargo.saturated()}),async.setImmediate(cargo.process)},process:function process(){if(!working){if(0===tasks.length)return void(cargo.drain&&cargo.drain());var ts="number"==typeof payload?tasks.splice(0,payload):tasks.splice(0),ds=_map(ts,function(task){return task.data});cargo.empty&&cargo.empty(),working=!0,worker(ds,function(){working=!1;var args=arguments;_each(ts,function(data){data.callback&&data.callback.apply(null,args)}),process()})}},length:function(){return tasks.length},running:function(){return working}};return cargo};var _console_fn=function(name){return function(fn){var args=Array.prototype.slice.call(arguments,1);fn.apply(null,args.concat([function(err){var args=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(err?console.error&&console.error(err):console[name]&&_each(args,function(x){console[name](x)}))}]))}};async.log=_console_fn("log"),async.dir=_console_fn("dir"),async.memoize=function(fn,hasher){var memo={},queues={};hasher=hasher||function(x){return x};var memoized=function(){var args=Array.prototype.slice.call(arguments),callback=args.pop(),key=hasher.apply(null,args);key in memo?callback.apply(null,memo[key]):key in queues?queues[key].push(callback):(queues[key]=[callback],fn.apply(null,args.concat([function(){memo[key]=arguments;var q=queues[key];delete queues[key];for(var i=0,l=q.length;l>i;i++)q[i].apply(null,arguments)}])))};return memoized.memo=memo,memoized.unmemoized=fn,memoized},async.unmemoize=function(fn){return function(){return(fn.unmemoized||fn).apply(null,arguments)}},async.times=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.map(counter,iterator,callback)},async.timesSeries=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.mapSeries(counter,iterator,callback)},async.compose=function(){var fns=Array.prototype.reverse.call(arguments);return function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();async.reduce(fns,args,function(newargs,fn,cb){fn.apply(that,newargs.concat([function(){var err=arguments[0],nextargs=Array.prototype.slice.call(arguments,1);cb(err,nextargs)}]))},function(err,results){callback.apply(that,[err].concat(results))})}};var _applyEach=function(eachfn,fns){var go=function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();return eachfn(fns,function(fn,cb){fn.apply(that,args.concat([cb]))},callback)};if(arguments.length>2){var args=Array.prototype.slice.call(arguments,2);return go.apply(this,args)}return go};async.applyEach=doParallel(_applyEach),async.applyEachSeries=doSeries(_applyEach),async.forever=function(fn,callback){function next(err){if(err){if(callback)return callback(err);throw err}fn(next)}next()},"undefined"!=typeof define&&define.amd?define([],function(){return async}):"undefined"!=typeof module&&module.exports?module.exports=async:root.async=async}(),function($){function maybeCall(thing,ctx){return"function"==typeof thing?thing.call(ctx):thing}function isElementInDOM(ele){for(;ele=ele.parentNode;)if(ele==document)return!0;return!1}function Tipsy(element,options){this.$element=$(element),this.options=options,this.enabled=!0,this.fixTitle()}Tipsy.prototype={show:function(){var title=this.getTitle();if(title&&this.enabled){var $tip=this.tip();$tip.find(".tipsy-inner")[this.options.html?"html":"text"](title),$tip[0].className="tipsy",$tip.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var tp,pos=$.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight}),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,gravity=maybeCall(this.options.gravity,this.$element[0]);switch(gravity.charAt(0)){case"n":tp={top:pos.top+pos.height+this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"s":tp={top:pos.top-actualHeight-this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"e":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth-this.options.offset};break;case"w":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width+this.options.offset}}2==gravity.length&&("w"==gravity.charAt(1)?tp.left=pos.left+pos.width/2-15:tp.left=pos.left+pos.width/2-actualWidth+15),$tip.css(tp).addClass("tipsy-"+gravity),$tip.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+gravity.charAt(0),this.options.className&&$tip.addClass(maybeCall(this.options.className,this.$element[0])),this.options.fade?$tip.stop().css({opacity:0,display:"block",visibility:"visible"}).animate({opacity:this.options.opacity}):$tip.css({visibility:"visible",opacity:this.options.opacity})}},hide:function(){this.options.fade?this.tip().stop().fadeOut(function(){$(this).remove()}):this.tip().remove()},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("original-title"))&&$e.attr("original-title",$e.attr("title")||"").removeAttr("title")},getTitle:function(){var title,$e=this.$element,o=this.options;this.fixTitle();var title,o=this.options;return"string"==typeof o.title?title=$e.attr("title"==o.title?"original-title":o.title):"function"==typeof o.title&&(title=o.title.call($e[0])),title=(""+title).replace(/(^\s*|\s*$)/,""),title||o.fallback},tip:function(){return this.$tip||(this.$tip=$('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>'),this.$tip.data("tipsy-pointee",this.$element[0])),this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled}},$.fn.tipsy=function(options){function get(ele){var tipsy=$.data(ele,"tipsy");return tipsy||(tipsy=new Tipsy(ele,$.fn.tipsy.elementOptions(ele,options)),$.data(ele,"tipsy",tipsy)),tipsy}function enter(){var tipsy=get(this);tipsy.hoverState="in",0==options.delayIn?tipsy.show():(tipsy.fixTitle(),setTimeout(function(){"in"==tipsy.hoverState&&tipsy.show()},options.delayIn))}function leave(){var tipsy=get(this);tipsy.hoverState="out",0==options.delayOut?tipsy.hide():setTimeout(function(){"out"==tipsy.hoverState&&tipsy.hide()},options.delayOut)}if(options===!0)return this.data("tipsy");if("string"==typeof options){var tipsy=this.data("tipsy");return tipsy&&tipsy[options](),this}if(options=$.extend({},$.fn.tipsy.defaults,options),options.live||this.each(function(){get(this)}),"manual"!=options.trigger){var binder=options.live?"live":"bind",eventIn="hover"==options.trigger?"mouseenter":"focus",eventOut="hover"==options.trigger?"mouseleave":"blur";this[binder](eventIn,enter)[binder](eventOut,leave)}return this},$.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:.8,title:"title",trigger:"hover"},$.fn.tipsy.revalidate=function(){$(".tipsy").each(function(){var pointee=$.data(this,"tipsy-pointee");pointee&&isElementInDOM(pointee)||$(this).remove()})},$.fn.tipsy.elementOptions=function(ele,options){return $.metadata?$.extend({},options,$(ele).metadata()):options},$.fn.tipsy.autoNS=function(){return $(this).offset().top>$(document).scrollTop()+$(window).height()/2?"s":"n"},$.fn.tipsy.autoWE=function(){return $(this).offset().left>$(document).scrollLeft()+$(window).width()/2?"e":"w"},$.fn.tipsy.autoBounds=function(margin,prefer){return function(){var dir={ns:prefer[0],ew:prefer.length>1?prefer[1]:!1},boundTop=$(document).scrollTop()+margin,boundLeft=$(document).scrollLeft()+margin,$this=$(this);return $this.offset().top<boundTop&&(dir.ns="n"),$this.offset().left<boundLeft&&(dir.ew="w"),$(window).width()+$(document).scrollLeft()-$this.offset().left<margin&&(dir.ew="e"),$(window).height()+$(document).scrollTop()-$this.offset().top<margin&&(dir.ns="s"),dir.ns+(dir.ew?dir.ew:"")}}}(jQuery),function($){var current=null;$.kmodal=function(el,options){$.kmodal.close();var remove,target;if(this.$body=$("body"),this.options=$.extend({},$.kmodal.defaults,options),this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10)),el.is("a"))if(target=el.attr("href"),/^#/.test(target)){if(this.$elm=$(target),1!==this.$elm.length)return null;this.open()}else this.$elm=$("<div>"),this.$body.append(this.$elm),remove=function(event,modal){modal.elm.remove()},this.showSpinner(),el.trigger($.kmodal.AJAX_SEND),$.get(target).done(function(html){current&&(el.trigger($.kmodal.AJAX_SUCCESS),current.$elm.empty().append(html).on($.kmodal.CLOSE,remove),current.hideSpinner(),current.open(),el.trigger($.kmodal.AJAX_COMPLETE))}).fail(function(){el.trigger($.kmodal.AJAX_FAIL),current.hideSpinner(),el.trigger($.kmodal.AJAX_COMPLETE)});else this.$elm=el,this.$body.append(this.$elm),this.open()},$.kmodal.prototype={constructor:$.kmodal,open:function(){var m=this;this.options.doFade?(this.block(),setTimeout(function(){m.show()},this.options.fadeDuration*this.options.fadeDelay)):(this.block(),this.show()),this.options.escapeClose&&$(document).on("keydown.modal",function(event){27==event.which&&$.kmodal.close()}),this.options.clickClose&&this.blocker.click($.kmodal.close)},close:function(){this.unblock(),this.hide(),$(document).off("keydown.modal")},block:function(){var initialOpacity=this.options.doFade?0:this.options.opacity;this.$elm.trigger($.kmodal.BEFORE_BLOCK,[this._ctx()]),this.blocker=$('<div class="jquery-modal blocker"></div>').css({top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",position:"fixed",zIndex:this.options.zIndex,background:this.options.overlay,opacity:initialOpacity}),this.$body.append(this.blocker),this.options.doFade&&this.blocker.animate({opacity:this.options.opacity},this.options.fadeDuration),this.$elm.trigger($.kmodal.BLOCK,[this._ctx()])},unblock:function(){this.options.doFade?this.blocker.fadeOut(this.options.fadeDuration,function(){$(this).remove()}):this.blocker.remove()},show:function(){this.$elm.trigger($.kmodal.BEFORE_OPEN,[this._ctx()]),this.options.showClose&&(this.closeButton=$('<a href="#close-modal" rel="modal:close" class="close-modal '+this.options.closeClass+'">'+this.options.closeText+"</a>"),this.$elm.append(this.closeButton)),this.$elm.addClass(this.options.modalClass+" current"),this.center(),this.options.doFade?this.$elm.fadeIn(this.options.fadeDuration):this.$elm.show(),this.$elm.trigger($.kmodal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger($.kmodal.BEFORE_CLOSE,[this._ctx()]),this.closeButton&&this.closeButton.remove(),this.$elm.removeClass("current"),this.options.doFade?this.$elm.fadeOut(this.options.fadeDuration):this.$elm.hide(),this.$elm.trigger($.kmodal.CLOSE,[this._ctx()])},showSpinner:function(){this.options.showSpinner&&(this.spinner=this.spinner||$('<div class="'+this.options.modalClass+'-spinner"></div>').append(this.options.spinnerHtml),this.$body.append(this.spinner),this.spinner.show())},hideSpinner:function(){this.spinner&&this.spinner.remove()},center:function(){this.$elm.css({position:"fixed",top:"50%",left:"50%",marginTop:-(this.$elm.outerHeight()/2),marginLeft:-(this.$elm.outerWidth()/2),zIndex:this.options.zIndex+1})},_ctx:function(){return{elm:this.$elm,blocker:this.blocker,options:this.options}}},$.kmodal.prototype.resize=$.kmodal.prototype.center,$.kmodal.close=function(event){if(current){event&&event.preventDefault(),current.close();var that=current.$elm;return current=null,that}},$.kmodal.resize=function(){current&¤t.resize()},$.kmodal.isActive=function(){return current?!0:!1},$.kmodal.defaults={overlay:"#000",opacity:.75,zIndex:1,escapeClose:!0,clickClose:!0,closeText:"Close",closeClass:"",modalClass:"kraken-modal",spinnerHtml:null,showSpinner:!0,showClose:!0,fadeDuration:null,fadeDelay:1},$.kmodal.BEFORE_BLOCK="modal:before-block",$.kmodal.BLOCK="modal:block",$.kmodal.BEFORE_OPEN="modal:before-open",$.kmodal.OPEN="modal:open",$.kmodal.BEFORE_CLOSE="modal:before-close",$.kmodal.CLOSE="modal:close",$.kmodal.AJAX_SEND="modal:ajax:send",$.kmodal.AJAX_SUCCESS="modal:ajax:success",$.kmodal.AJAX_FAIL="modal:ajax:fail",$.kmodal.AJAX_COMPLETE="modal:ajax:complete",$.fn.kmodal=function(options){return 1===this.length&&(current=new $.kmodal(this,options)),this},$(document).on("click.modal",'a[rel="modal:close"]',$.kmodal.close),$(document).on("click.modal",'a[rel="modal:open"]',function(event){event.preventDefault(),$(this).kmodal()})}(jQuery),jQuery(document).ready(function($){$(".krakenWhatsThis").tipsy({fade:!0,gravity:"w"});var data={action:"kraken_request"},errorTpl='<div class="krakenErrorWrap"><a class="krakenError">Failed! Hover here</a></div>',$btnApplyBulkAction=$("#doaction"),$btnApplyBulkAction2=$("#doaction2"),$topBulkActionDropdown=$(".tablenav.top .bulkactions select[name='action']"),$bottomBulkActionDropdown=$(".tablenav.bottom .bulkactions select[name='action2']"),requestSuccess=function(data,textStatus,jqXHR){var $button=$(this),$parent=$(this).parent(),$cell=$(this).closest("td");if(data.success&&"undefined"==typeof data.error){$button.text("Image optimized");var originalSize=(data.type,data.kraked_size,data.original_size),$originalSizeColumn=(data.savings_percent,$(this).parent().prev("td.original_size"));$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$(this).replaceWith(data.html),$originalSizeColumn.html(originalSize),$parent.remove()})}else if(data.error){var $error=$(errorTpl).attr("title",data.error);$parent.closest("td").find(".krakenErrorWrap").remove(),$parent.after($error),$error.tipsy({fade:!0,gravity:"e"}),$button.text("Retry request").removeAttr("disabled").css({opacity:1})}},requestFail=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled")},requestComplete=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled"),$(this).parent().find(".krakenSpinner").css("display","none")},opts='<option value="kraken-bulk-lossy">Krak \'em all</option>';$topBulkActionDropdown.find("option:last-child").before(opts),$bottomBulkActionDropdown.find("option:last-child").before(opts);var getBulkImageData=function(){var $rows=$("tr[id^='post-']"),$row=null,postId=0,$krakBtn=null,btnData={},originalSize="",rv=[];return $rows.each(function(){$row=$(this),postId=this.id.replace(/^\D+/g,""),$row.find("input[type='checkbox'][value='"+postId+"']:checked").length&&($krakBtn=$row.find(".kraken_req"),$krakBtn.length&&(btnData=$krakBtn.data(),originalSize=$.trim($row.find("td.original_size").text()),btnData.originalSize=originalSize,rv.push(btnData)))}),rv},renderBulkImageSummary=function(bulkImageData){var modalOptions={zIndex:4,escapeClose:!0,clickClose:!1,closeText:"close",showClose:!1},setting=kraken_settings.api_lossy,nImages=bulkImageData.length,header='<p class="krakenBulkHeader">Kraken Bulk Image Optimization</p>',krakEmAll='<button class="kraken_req_bulk">Krak \'em all</button>',typeRadios='<span class="radiosWrap"><span class="kraken-bulk-choose-type">Choose:</span><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/><label for="kraken-bulk-type-lossy">Lossy</label> <input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/><label for="kraken-bulk-type-lossless">Lossless</label></span>',$modal=$('<div id="kraken-bulk-modal" class="kraken-modal"></div>').html(header).append(typeRadios).append('<br /><small class="kraken-bulk-small">The following <strong>'+nImages+'</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">'+setting+"</strong> setting:</small><br />").appendTo("body").kmodal(modalOptions).bind($.kmodal.BEFORE_CLOSE,function(event,modal){}).bind($.kmodal.OPEN,function(event,modal){}).bind($.kmodal.CLOSE,function(event,modal){$("#kraken-bulk-modal").remove()}).css({top:"10px",marginTop:"40px"});"lossy"===setting?$("#kraken-bulk-type-lossy").attr("checked",!0):$("#kraken-bulk-type-lossless").attr("checked",!0),$bulkSettingSpan=$(".bulkSetting"),$("input[name='kraken-bulk-type']").change(function(){var text="kraken-bulk-type-lossy"===this.id?"lossy":"lossless";$bulkSettingSpan.text(text)}),$(".jquery-modal.blocker").click(function(e){return!1}),$("#menu-media ul.wp-submenu").css({"z-index":1});var $table=$('<table id="kraken-bulk"></table>'),$headerRow=$('<tr class="kraken-bulk-header"><td>File</td><td style="width:120px">Original Size</td><td style="width:120px">Kraked Size</td><td style="width:120px">Savings</td><td style="width:120px">% Savings</td></tr>');$table.append($headerRow),$.each(bulkImageData,function(index,element){$table.append('<tr class="kraken-item-row" data-krakenbulkid="'+element.id+'"><td class="kraken-filename">'+element.filename+'</td><td class="kraken-originalsize">'+element.originalSize+'</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td><td class="kraken-savings"></td><td class="kraken-savingsPercent"></td></tr>')}),$modal.append($table).append(krakEmAll).append('<span class="close-kraken-bulk">Close Window</span>'),$(".close-kraken-bulk").click(function(){$.kmodal.close()}),nImages||$(".kraken_req_bulk").attr("disabled",!0).css({opacity:.5})},bulkAction=function(bulkImageData){$bulkTable=$("#kraken-bulk");var jqxhr=null,q=async.queue(function(task,callback){var id=task.id,$row=(task.filename,$bulkTable.find("tr[data-krakenbulkid='"+id+"']")),$krakedSizeColumn=$row.find(".kraken-krakedsize"),$spinner=$krakedSizeColumn.find(".krakenBulkSpinner").css({display:"inline-block"}),$savingsPercentColumn=$row.find(".kraken-savingsPercent"),$savingsBytesColumn=$row.find(".kraken-savings");jqxhr=$.ajax({url:ajax_object.ajax_url,data:{action:"kraken_request",id:id,type:$("input[name='kraken-bulk-type']:checked").val().toLowerCase()},type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){if(data.success&&"undefined"==typeof data.error){var type=data.type,originalSize=data.original_size,krakedSize=data.kraked_size,savingsPercent=data.savings_percent,savingsBytes=data.saved_bytes;$krakedSizeColumn.text(krakedSize),$savingsPercentColumn.text(savingsPercent),$savingsBytesColumn.text(savingsBytes);var $button=$("button[id='krakenid-"+id+"']"),$parent=$button.parent(),$cell=$button.closest("td"),$originalSizeColumn=$button.parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),krakedData="<strong>"+krakedSize+"</strong><br /><small>Type: "+type+"</small><br /><small>Savings: "+savingsPercent+"</small>","undefined"!=typeof data.thumbs_data&&(krakedData+="<br /><small>"+data.thumbs_data.length+" thumbs optimized</small>"),$(this).replaceWith(krakedData),$originalSizeColumn.html(originalSize),$parent.remove()})}else data.error&&"This image can not be optimized any further"===data.error&&$krakedSizeColumn.text("No savings found.")}).fail(function(){}).always(function(){$spinner.css({display:"none"}),callback()})},kraken_settings.bulk_async_limit);q.drain=function(){$(".kraken_req_bulk").removeAttr("disabled").css({opacity:1}).text("Done").unbind("click").click(function(){$.kmodal.close()})},q.push(bulkImageData,function(err){})};$btnApplyBulkAction.add($btnApplyBulkAction2).click(function(e){if("kraken-bulk-lossy"===$(this).prev("select").val()){e.preventDefault();var bulkImageData=getBulkImageData();renderBulkImageSummary(bulkImageData),$(".kraken_req_bulk").click(function(e){e.preventDefault(),$(this).attr("disabled",!0).css({opacity:.5}),bulkAction(bulkImageData)})}}),$("body").on("click","small.krakenReset",function(e){e.preventDefault();var $resetButton=$(this),resetData={action:"kraken_reset"};resetData.id=$(this).data("id");var $spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){"undefined"!==data.success&&$resetButton.closest(".kraked_size.column-kraked_size").hide().html(data.html).fadeIn().prev(".original_size.column-original_size").html(data.original_size)})}),$("body").on("click",".kraken-reset-all",function(e){e.preventDefault();var reset=confirm("This will immediately remove all Kraken metadata associated with your images. \n\nAre you sure you want to do this?");if(reset){var $resetButton=$(this);$resetButton.text("Resetting images, pleaes wait...").attr("disabled",!0); 2 3 var resetData={action:"kraken_reset_all"},$spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);{$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){$spinner.remove(),$resetButton.text("Your images have been reset.").removeAttr("disabled").removeClass("enabled")})}}}),$(".krakenAdvancedSettings h3").on("click",function(){var $rows=$(".kraken-advanced-settings"),$plusMinus=$(".kraken-plus-minus");$rows.is(":visible")?($rows.hide(),$plusMinus.removeClass("dashicons-arrow-down").addClass("dashicons-arrow-right")):($rows.show(),$plusMinus.removeClass("dashicons-arrow-right").addClass("dashicons-arrow-down"))}),$("body").on("click",".kraken_req",function(e){e.preventDefault();var $button=$(this),$parent=$(this).parent();data.id=$(this).data("id"),$button.text("Optimizing image...").attr("disabled",!0).css({opacity:.5}),$parent.find(".krakenSpinner").css("display","inline");$.ajax({url:ajax_object.ajax_url,data:data,type:"post",dataType:"json",timeout:36e4,context:$button}).done(requestSuccess).fail(requestFail).always(requestComplete)})}); 1 !function(){function only_once(fn){var called=!1;return function(){if(called)throw new Error("Callback was already called.");called=!0,fn.apply(root,arguments)}}var root,previous_async,async={};root=this,null!=root&&(previous_async=root.async),async.noConflict=function(){return root.async=previous_async,async};var _each=function(arr,iterator){if(arr.forEach)return arr.forEach(iterator);for(var i=0;i<arr.length;i+=1)iterator(arr[i],i,arr)},_map=function(arr,iterator){if(arr.map)return arr.map(iterator);var results=[];return _each(arr,function(x,i,a){results.push(iterator(x,i,a))}),results},_reduce=function(arr,iterator,memo){return arr.reduce?arr.reduce(iterator,memo):(_each(arr,function(x,i,a){memo=iterator(memo,x,i,a)}),memo)},_keys=function(obj){if(Object.keys)return Object.keys(obj);var keys=[];for(var k in obj)obj.hasOwnProperty(k)&&keys.push(k);return keys};"undefined"!=typeof process&&process.nextTick?(async.nextTick=process.nextTick,"undefined"!=typeof setImmediate?async.setImmediate=function(fn){setImmediate(fn)}:async.setImmediate=async.nextTick):"function"==typeof setImmediate?(async.nextTick=function(fn){setImmediate(fn)},async.setImmediate=async.nextTick):(async.nextTick=function(fn){setTimeout(fn,0)},async.setImmediate=async.nextTick),async.each=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0;_each(arr,function(x){iterator(x,only_once(function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length&&callback(null))}))})},async.forEach=async.each,async.eachSeries=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0,iterate=function(){iterator(arr[completed],function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length?callback(null):iterate())})};iterate()},async.forEachSeries=async.eachSeries,async.eachLimit=function(arr,limit,iterator,callback){var fn=_eachLimit(limit);fn.apply(null,[arr,iterator,callback])},async.forEachLimit=async.eachLimit;var _eachLimit=function(limit){return function(arr,iterator,callback){if(callback=callback||function(){},!arr.length||0>=limit)return callback();var completed=0,started=0,running=0;!function replenish(){if(completed>=arr.length)return callback();for(;limit>running&&started<arr.length;)started+=1,running+=1,iterator(arr[started-1],function(err){err?(callback(err),callback=function(){}):(completed+=1,running-=1,completed>=arr.length?callback():replenish())})}()}},doParallel=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.each].concat(args))}},doParallelLimit=function(limit,fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[_eachLimit(limit)].concat(args))}},doSeries=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.eachSeries].concat(args))}},_asyncMap=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(err,v){results[x.index]=v,callback(err)})},function(err){callback(err,results)})};async.map=doParallel(_asyncMap),async.mapSeries=doSeries(_asyncMap),async.mapLimit=function(arr,limit,iterator,callback){return _mapLimit(limit)(arr,iterator,callback)};var _mapLimit=function(limit){return doParallelLimit(limit,_asyncMap)};async.reduce=function(arr,memo,iterator,callback){async.eachSeries(arr,function(x,callback){iterator(memo,x,function(err,v){memo=v,callback(err)})},function(err){callback(err,memo)})},async.inject=async.reduce,async.foldl=async.reduce,async.reduceRight=function(arr,memo,iterator,callback){var reversed=_map(arr,function(x){return x}).reverse();async.reduce(reversed,memo,iterator,callback)},async.foldr=async.reduceRight;var _filter=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v&&results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.filter=doParallel(_filter),async.filterSeries=doSeries(_filter),async.select=async.filter,async.selectSeries=async.filterSeries;var _reject=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v||results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.reject=doParallel(_reject),async.rejectSeries=doSeries(_reject);var _detect=function(eachfn,arr,iterator,main_callback){eachfn(arr,function(x,callback){iterator(x,function(result){result?(main_callback(x),main_callback=function(){}):callback()})},function(err){main_callback()})};async.detect=doParallel(_detect),async.detectSeries=doSeries(_detect),async.some=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v&&(main_callback(!0),main_callback=function(){}),callback()})},function(err){main_callback(!1)})},async.any=async.some,async.every=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v||(main_callback(!1),main_callback=function(){}),callback()})},function(err){main_callback(!0)})},async.all=async.every,async.sortBy=function(arr,iterator,callback){async.map(arr,function(x,callback){iterator(x,function(err,criteria){err?callback(err):callback(null,{value:x,criteria:criteria})})},function(err,results){if(err)return callback(err);var fn=function(left,right){var a=left.criteria,b=right.criteria;return b>a?-1:a>b?1:0};callback(null,_map(results.sort(fn),function(x){return x.value}))})},async.auto=function(tasks,callback){callback=callback||function(){};var keys=_keys(tasks);if(!keys.length)return callback(null);var results={},listeners=[],addListener=function(fn){listeners.unshift(fn)},removeListener=function(fn){for(var i=0;i<listeners.length;i+=1)if(listeners[i]===fn)return void listeners.splice(i,1)},taskComplete=function(){_each(listeners.slice(0),function(fn){fn()})};addListener(function(){_keys(results).length===keys.length&&(callback(null,results),callback=function(){})}),_each(keys,function(k){var task=tasks[k]instanceof Function?[tasks[k]]:tasks[k],taskCallback=function(err){var args=Array.prototype.slice.call(arguments,1);if(args.length<=1&&(args=args[0]),err){var safeResults={};_each(_keys(results),function(rkey){safeResults[rkey]=results[rkey]}),safeResults[k]=args,callback(err,safeResults),callback=function(){}}else results[k]=args,async.setImmediate(taskComplete)},requires=task.slice(0,Math.abs(task.length-1))||[],ready=function(){return _reduce(requires,function(a,x){return a&&results.hasOwnProperty(x)},!0)&&!results.hasOwnProperty(k)};if(ready())task[task.length-1](taskCallback,results);else{var listener=function(){ready()&&(removeListener(listener),task[task.length-1](taskCallback,results))};addListener(listener)}})},async.waterfall=function(tasks,callback){if(callback=callback||function(){},tasks.constructor!==Array){var err=new Error("First argument to waterfall must be an array of functions");return callback(err)}if(!tasks.length)return callback();var wrapIterator=function(iterator){return function(err){if(err)callback.apply(null,arguments),callback=function(){};else{var args=Array.prototype.slice.call(arguments,1),next=iterator.next();args.push(next?wrapIterator(next):callback),async.setImmediate(function(){iterator.apply(null,args)})}}};wrapIterator(async.iterator(tasks))()};var _parallel=function(eachfn,tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)eachfn.map(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};eachfn.each(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}};async.parallel=function(tasks,callback){_parallel({map:async.map,each:async.each},tasks,callback)},async.parallelLimit=function(tasks,limit,callback){_parallel({map:_mapLimit(limit),each:_eachLimit(limit)},tasks,callback)},async.series=function(tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)async.mapSeries(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};async.eachSeries(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}},async.iterator=function(tasks){var makeCallback=function(index){var fn=function(){return tasks.length&&tasks[index].apply(null,arguments),fn.next()};return fn.next=function(){return index<tasks.length-1?makeCallback(index+1):null},fn};return makeCallback(0)},async.apply=function(fn){var args=Array.prototype.slice.call(arguments,1);return function(){return fn.apply(null,args.concat(Array.prototype.slice.call(arguments)))}};var _concat=function(eachfn,arr,fn,callback){var r=[];eachfn(arr,function(x,cb){fn(x,function(err,y){r=r.concat(y||[]),cb(err)})},function(err){callback(err,r)})};async.concat=doParallel(_concat),async.concatSeries=doSeries(_concat),async.whilst=function(test,iterator,callback){test()?iterator(function(err){return err?callback(err):void async.whilst(test,iterator,callback)}):callback()},async.doWhilst=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?async.doWhilst(iterator,test,callback):callback())})},async.until=function(test,iterator,callback){test()?callback():iterator(function(err){return err?callback(err):void async.until(test,iterator,callback)})},async.doUntil=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?callback():async.doUntil(iterator,test,callback))})},async.queue=function(worker,concurrency){function _insert(q,data,pos,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){var item={data:task,callback:"function"==typeof callback?callback:null};pos?q.tasks.unshift(item):q.tasks.push(item),q.saturated&&q.tasks.length===concurrency&&q.saturated(),async.setImmediate(q.process)})}void 0===concurrency&&(concurrency=1);var workers=0,q={tasks:[],concurrency:concurrency,saturated:null,empty:null,drain:null,push:function(data,callback){_insert(q,data,!1,callback)},unshift:function(data,callback){_insert(q,data,!0,callback)},process:function(){if(workers<q.concurrency&&q.tasks.length){var task=q.tasks.shift();q.empty&&0===q.tasks.length&&q.empty(),workers+=1;var next=function(){workers-=1,task.callback&&task.callback.apply(task,arguments),q.drain&&q.tasks.length+workers===0&&q.drain(),q.process()},cb=only_once(next);worker(task.data,cb)}},length:function(){return q.tasks.length},running:function(){return workers}};return q},async.cargo=function(worker,payload){var working=!1,tasks=[],cargo={tasks:tasks,payload:payload,saturated:null,empty:null,drain:null,push:function(data,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){tasks.push({data:task,callback:"function"==typeof callback?callback:null}),cargo.saturated&&tasks.length===payload&&cargo.saturated()}),async.setImmediate(cargo.process)},process:function process(){if(!working){if(0===tasks.length)return void(cargo.drain&&cargo.drain());var ts="number"==typeof payload?tasks.splice(0,payload):tasks.splice(0),ds=_map(ts,function(task){return task.data});cargo.empty&&cargo.empty(),working=!0,worker(ds,function(){working=!1;var args=arguments;_each(ts,function(data){data.callback&&data.callback.apply(null,args)}),process()})}},length:function(){return tasks.length},running:function(){return working}};return cargo};var _console_fn=function(name){return function(fn){var args=Array.prototype.slice.call(arguments,1);fn.apply(null,args.concat([function(err){var args=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(err?console.error&&console.error(err):console[name]&&_each(args,function(x){console[name](x)}))}]))}};async.log=_console_fn("log"),async.dir=_console_fn("dir"),async.memoize=function(fn,hasher){var memo={},queues={};hasher=hasher||function(x){return x};var memoized=function(){var args=Array.prototype.slice.call(arguments),callback=args.pop(),key=hasher.apply(null,args);key in memo?callback.apply(null,memo[key]):key in queues?queues[key].push(callback):(queues[key]=[callback],fn.apply(null,args.concat([function(){memo[key]=arguments;var q=queues[key];delete queues[key];for(var i=0,l=q.length;l>i;i++)q[i].apply(null,arguments)}])))};return memoized.memo=memo,memoized.unmemoized=fn,memoized},async.unmemoize=function(fn){return function(){return(fn.unmemoized||fn).apply(null,arguments)}},async.times=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.map(counter,iterator,callback)},async.timesSeries=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.mapSeries(counter,iterator,callback)},async.compose=function(){var fns=Array.prototype.reverse.call(arguments);return function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();async.reduce(fns,args,function(newargs,fn,cb){fn.apply(that,newargs.concat([function(){var err=arguments[0],nextargs=Array.prototype.slice.call(arguments,1);cb(err,nextargs)}]))},function(err,results){callback.apply(that,[err].concat(results))})}};var _applyEach=function(eachfn,fns){var go=function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();return eachfn(fns,function(fn,cb){fn.apply(that,args.concat([cb]))},callback)};if(arguments.length>2){var args=Array.prototype.slice.call(arguments,2);return go.apply(this,args)}return go};async.applyEach=doParallel(_applyEach),async.applyEachSeries=doSeries(_applyEach),async.forever=function(fn,callback){function next(err){if(err){if(callback)return callback(err);throw err}fn(next)}next()},"undefined"!=typeof define&&define.amd?define([],function(){return async}):"undefined"!=typeof module&&module.exports?module.exports=async:root.async=async}(),function($){function maybeCall(thing,ctx){return"function"==typeof thing?thing.call(ctx):thing}function isElementInDOM(ele){for(;ele=ele.parentNode;)if(ele==document)return!0;return!1}function Tipsy(element,options){this.$element=$(element),this.options=options,this.enabled=!0,this.fixTitle()}Tipsy.prototype={show:function(){var title=this.getTitle();if(title&&this.enabled){var $tip=this.tip();$tip.find(".tipsy-inner")[this.options.html?"html":"text"](title),$tip[0].className="tipsy",$tip.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var tp,pos=$.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight}),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,gravity=maybeCall(this.options.gravity,this.$element[0]);switch(gravity.charAt(0)){case"n":tp={top:pos.top+pos.height+this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"s":tp={top:pos.top-actualHeight-this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"e":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth-this.options.offset};break;case"w":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width+this.options.offset}}2==gravity.length&&("w"==gravity.charAt(1)?tp.left=pos.left+pos.width/2-15:tp.left=pos.left+pos.width/2-actualWidth+15),$tip.css(tp).addClass("tipsy-"+gravity),$tip.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+gravity.charAt(0),this.options.className&&$tip.addClass(maybeCall(this.options.className,this.$element[0])),this.options.fade?$tip.stop().css({opacity:0,display:"block",visibility:"visible"}).animate({opacity:this.options.opacity}):$tip.css({visibility:"visible",opacity:this.options.opacity})}},hide:function(){this.options.fade?this.tip().stop().fadeOut(function(){$(this).remove()}):this.tip().remove()},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("original-title"))&&$e.attr("original-title",$e.attr("title")||"").removeAttr("title")},getTitle:function(){var title,$e=this.$element,o=this.options;this.fixTitle();var title,o=this.options;return"string"==typeof o.title?title=$e.attr("title"==o.title?"original-title":o.title):"function"==typeof o.title&&(title=o.title.call($e[0])),title=(""+title).replace(/(^\s*|\s*$)/,""),title||o.fallback},tip:function(){return this.$tip||(this.$tip=$('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>'),this.$tip.data("tipsy-pointee",this.$element[0])),this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled}},$.fn.tipsy=function(options){function get(ele){var tipsy=$.data(ele,"tipsy");return tipsy||(tipsy=new Tipsy(ele,$.fn.tipsy.elementOptions(ele,options)),$.data(ele,"tipsy",tipsy)),tipsy}function enter(){var tipsy=get(this);tipsy.hoverState="in",0==options.delayIn?tipsy.show():(tipsy.fixTitle(),setTimeout(function(){"in"==tipsy.hoverState&&tipsy.show()},options.delayIn))}function leave(){var tipsy=get(this);tipsy.hoverState="out",0==options.delayOut?tipsy.hide():setTimeout(function(){"out"==tipsy.hoverState&&tipsy.hide()},options.delayOut)}if(options===!0)return this.data("tipsy");if("string"==typeof options){var tipsy=this.data("tipsy");return tipsy&&tipsy[options](),this}if(options=$.extend({},$.fn.tipsy.defaults,options),options.live||this.each(function(){get(this)}),"manual"!=options.trigger){var binder=options.live?"live":"bind",eventIn="hover"==options.trigger?"mouseenter":"focus",eventOut="hover"==options.trigger?"mouseleave":"blur";this[binder](eventIn,enter)[binder](eventOut,leave)}return this},$.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:.8,title:"title",trigger:"hover"},$.fn.tipsy.revalidate=function(){$(".tipsy").each(function(){var pointee=$.data(this,"tipsy-pointee");pointee&&isElementInDOM(pointee)||$(this).remove()})},$.fn.tipsy.elementOptions=function(ele,options){return $.metadata?$.extend({},options,$(ele).metadata()):options},$.fn.tipsy.autoNS=function(){return $(this).offset().top>$(document).scrollTop()+$(window).height()/2?"s":"n"},$.fn.tipsy.autoWE=function(){return $(this).offset().left>$(document).scrollLeft()+$(window).width()/2?"e":"w"},$.fn.tipsy.autoBounds=function(margin,prefer){return function(){var dir={ns:prefer[0],ew:prefer.length>1?prefer[1]:!1},boundTop=$(document).scrollTop()+margin,boundLeft=$(document).scrollLeft()+margin,$this=$(this);return $this.offset().top<boundTop&&(dir.ns="n"),$this.offset().left<boundLeft&&(dir.ew="w"),$(window).width()+$(document).scrollLeft()-$this.offset().left<margin&&(dir.ew="e"),$(window).height()+$(document).scrollTop()-$this.offset().top<margin&&(dir.ns="s"),dir.ns+(dir.ew?dir.ew:"")}}}(jQuery),function($){var current=null;$.kmodal=function(el,options){$.kmodal.close();var remove,target;if(this.$body=$("body"),this.options=$.extend({},$.kmodal.defaults,options),this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10)),el.is("a"))if(target=el.attr("href"),/^#/.test(target)){if(this.$elm=$(target),1!==this.$elm.length)return null;this.open()}else this.$elm=$("<div>"),this.$body.append(this.$elm),remove=function(event,modal){modal.elm.remove()},this.showSpinner(),el.trigger($.kmodal.AJAX_SEND),$.get(target).done(function(html){current&&(el.trigger($.kmodal.AJAX_SUCCESS),current.$elm.empty().append(html).on($.kmodal.CLOSE,remove),current.hideSpinner(),current.open(),el.trigger($.kmodal.AJAX_COMPLETE))}).fail(function(){el.trigger($.kmodal.AJAX_FAIL),current.hideSpinner(),el.trigger($.kmodal.AJAX_COMPLETE)});else this.$elm=el,this.$body.append(this.$elm),this.open()},$.kmodal.prototype={constructor:$.kmodal,open:function(){var m=this;this.options.doFade?(this.block(),setTimeout(function(){m.show()},this.options.fadeDuration*this.options.fadeDelay)):(this.block(),this.show()),this.options.escapeClose&&$(document).on("keydown.modal",function(event){27==event.which&&$.kmodal.close()}),this.options.clickClose&&this.blocker.click($.kmodal.close)},close:function(){this.unblock(),this.hide(),$(document).off("keydown.modal")},block:function(){var initialOpacity=this.options.doFade?0:this.options.opacity;this.$elm.trigger($.kmodal.BEFORE_BLOCK,[this._ctx()]),this.blocker=$('<div class="jquery-modal blocker"></div>').css({top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",position:"fixed",zIndex:this.options.zIndex,background:this.options.overlay,opacity:initialOpacity}),this.$body.append(this.blocker),this.options.doFade&&this.blocker.animate({opacity:this.options.opacity},this.options.fadeDuration),this.$elm.trigger($.kmodal.BLOCK,[this._ctx()])},unblock:function(){this.options.doFade?this.blocker.fadeOut(this.options.fadeDuration,function(){$(this).remove()}):this.blocker.remove()},show:function(){this.$elm.trigger($.kmodal.BEFORE_OPEN,[this._ctx()]),this.options.showClose&&(this.closeButton=$('<a href="#close-modal" rel="modal:close" class="close-modal '+this.options.closeClass+'">'+this.options.closeText+"</a>"),this.$elm.append(this.closeButton)),this.$elm.addClass(this.options.modalClass+" current"),this.center(),this.options.doFade?this.$elm.fadeIn(this.options.fadeDuration):this.$elm.show(),this.$elm.trigger($.kmodal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger($.kmodal.BEFORE_CLOSE,[this._ctx()]),this.closeButton&&this.closeButton.remove(),this.$elm.removeClass("current"),this.options.doFade?this.$elm.fadeOut(this.options.fadeDuration):this.$elm.hide(),this.$elm.trigger($.kmodal.CLOSE,[this._ctx()])},showSpinner:function(){this.options.showSpinner&&(this.spinner=this.spinner||$('<div class="'+this.options.modalClass+'-spinner"></div>').append(this.options.spinnerHtml),this.$body.append(this.spinner),this.spinner.show())},hideSpinner:function(){this.spinner&&this.spinner.remove()},center:function(){this.$elm.css({position:"fixed",top:"50%",left:"50%",marginTop:-(this.$elm.outerHeight()/2),marginLeft:-(this.$elm.outerWidth()/2),zIndex:this.options.zIndex+1})},_ctx:function(){return{elm:this.$elm,blocker:this.blocker,options:this.options}}},$.kmodal.prototype.resize=$.kmodal.prototype.center,$.kmodal.close=function(event){if(current){event&&event.preventDefault(),current.close();var that=current.$elm;return current=null,that}},$.kmodal.resize=function(){current&¤t.resize()},$.kmodal.isActive=function(){return current?!0:!1},$.kmodal.defaults={overlay:"#000",opacity:.75,zIndex:1,escapeClose:!0,clickClose:!0,closeText:"Close",closeClass:"",modalClass:"kraken-modal",spinnerHtml:null,showSpinner:!0,showClose:!0,fadeDuration:null,fadeDelay:1},$.kmodal.BEFORE_BLOCK="modal:before-block",$.kmodal.BLOCK="modal:block",$.kmodal.BEFORE_OPEN="modal:before-open",$.kmodal.OPEN="modal:open",$.kmodal.BEFORE_CLOSE="modal:before-close",$.kmodal.CLOSE="modal:close",$.kmodal.AJAX_SEND="modal:ajax:send",$.kmodal.AJAX_SUCCESS="modal:ajax:success",$.kmodal.AJAX_FAIL="modal:ajax:fail",$.kmodal.AJAX_COMPLETE="modal:ajax:complete",$.fn.kmodal=function(options){return 1===this.length&&(current=new $.kmodal(this,options)),this},$(document).on("click.modal",'a[rel="modal:close"]',$.kmodal.close),$(document).on("click.modal",'a[rel="modal:open"]',function(event){event.preventDefault(),$(this).kmodal()})}(jQuery),jQuery(document).ready(function($){var tipsySettings={gravity:"e",html:!0,trigger:"manual",className:function(){return"tipsy-"+$(this).data("id")},title:function(){return activeId=$(this).data("id"),$(this).attr("original-title")}};$(".krakenWhatsThis").tipsy({fade:!0,gravity:"w"}),$(".krakenError").tipsy({fade:!0,gravity:"e"});var data={action:"kraken_request"},errorTpl='<div class="krakenErrorWrap"><a class="krakenError">Failed! Hover here</a></div>',$btnApplyBulkAction=$("#doaction"),$btnApplyBulkAction2=$("#doaction2"),$topBulkActionDropdown=$(".tablenav.top .bulkactions select[name='action']"),$bottomBulkActionDropdown=$(".tablenav.bottom .bulkactions select[name='action2']"),requestSuccess=function(data,textStatus,jqXHR){var $button=$(this),$parent=$(this).closest(".kraken-wrap, .buttonWrap"),$cell=$(this).closest("td");if(data.html){$button.text("Image optimized");var originalSize=(data.type,data.original_size),$originalSizeColumn=$(this).parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$cell.html(data.html),$cell.find(".kraken-item-details").tipsy(tipsySettings),$originalSizeColumn.html(originalSize),$parent.remove()})}else if(data.error){var $error=$(errorTpl).attr("title",data.error);$parent.closest("td").find(".krakenErrorWrap").remove(),$parent.after($error),$error.tipsy({fade:!0,gravity:"e"}),$button.text("Retry request").removeAttr("disabled").css({opacity:1})}},requestFail=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled")},requestComplete=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled"),$(this).parent().find(".krakenSpinner").css("display","none")},opts='<option value="kraken-bulk-lossy">Krak \'em all</option>';$topBulkActionDropdown.find("option:last-child").before(opts),$bottomBulkActionDropdown.find("option:last-child").before(opts);var getBulkImageData=function(){var $rows=$("tr[id^='post-']"),$row=null,postId=0,$krakBtn=null,btnData={},originalSize="",rv=[];return $rows.each(function(){$row=$(this),postId=this.id.replace(/^\D+/g,""),$row.find("input[type='checkbox'][value='"+postId+"']:checked").length&&($krakBtn=$row.find(".kraken_req"),$krakBtn.length&&(btnData=$krakBtn.data(),originalSize=$.trim($row.find("td.original_size").text()),btnData.originalSize=originalSize,rv.push(btnData)))}),rv},bulkModalOptions={zIndex:4,escapeClose:!0,clickClose:!1,closeText:"close",showClose:!1},renderBulkImageSummary=function(bulkImageData){var setting=kraken_settings.api_lossy,nImages=bulkImageData.length,header='<p class="krakenBulkHeader">Kraken Bulk Image Optimization <span class="close-kraken-bulk">×</span></p>',krakEmAll='<button class="kraken_req_bulk">Krak \'em all</button>',typeRadios='<div class="radiosWrap"><p>Choose optimization mode:</p><label><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>Intelligent Lossy</label> <label><input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>Lossless</label></div>',$modal=$('<div id="kraken-bulk-modal" class="kraken-modal"></div>').html(header).append(typeRadios).append('<p class="the-following">The following <strong>'+nImages+'</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">'+setting+"</strong> setting:</p>").appendTo("body").kmodal(bulkModalOptions).bind($.kmodal.BEFORE_CLOSE,function(event,modal){}).bind($.kmodal.OPEN,function(event,modal){}).bind($.kmodal.CLOSE,function(event,modal){$("#kraken-bulk-modal").remove()}).css({top:"10px",marginTop:"40px"});"lossy"===setting?$("#kraken-bulk-type-lossy").attr("checked",!0):$("#kraken-bulk-type-lossless").attr("checked",!0),$bulkSettingSpan=$(".bulkSetting"),$("input[name='kraken-bulk-type']").change(function(){var text="kraken-bulk-type-lossy"===this.id?"lossy":"lossless";$bulkSettingSpan.text(text)}),$(".jquery-modal.blocker").click(function(e){return!1}),$("#menu-media ul.wp-submenu").css({"z-index":1});var $table=$('<table id="kraken-bulk"></table>'),$headerRow=$('<tr class="kraken-bulk-header"><td>File Name</td><td style="width:120px">Original Size</td><td style="width:120px">Kraken.io Stats</td></tr>');$table.append($headerRow),$.each(bulkImageData,function(index,element){$table.append('<tr class="kraken-item-row" data-krakenbulkid="'+element.id+'"><td class="kraken-bulk-filename">'+element.filename+'</td><td class="kraken-originalsize">'+element.originalSize+'</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td></tr>')}),$modal.append($table).append(krakEmAll),$(".close-kraken-bulk").click(function(){$.kmodal.close()}),nImages||$(".kraken_req_bulk").attr("disabled",!0).css({opacity:.5})},bulkAction=function(bulkImageData){$bulkTable=$("#kraken-bulk");var jqxhr=null,q=async.queue(function(task,callback){var id=task.id,$row=(task.filename,$bulkTable.find("tr[data-krakenbulkid='"+id+"']")),$krakedSizeColumn=$row.find(".kraken-krakedsize"),$spinner=$krakedSizeColumn.find(".krakenBulkSpinner").css({display:"inline-block"}),$savingsPercentColumn=$row.find(".kraken-savingsPercent"),$savingsBytesColumn=$row.find(".kraken-savings");jqxhr=$.ajax({url:ajax_object.ajax_url,data:{action:"kraken_request",id:id,type:$("input[name='kraken-bulk-type']:checked").val().toLowerCase(),origin:"bulk_optimizer"},type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){if(data.success&&"undefined"==typeof data.message){var originalSize=(data.type,data.original_size),savingsPercent=(data.html,data.savings_percent),savingsBytes=data.saved_bytes;$krakedSizeColumn.html(data.html),$krakedSizeColumn.find(".kraken-item-details").remove(),$savingsPercentColumn.text(savingsPercent),$savingsBytesColumn.text(savingsBytes);var $button=$("button[id='krakenid-"+id+"']"),$parent=$button.parent(),$cell=$button.closest("td"),$originalSizeColumn=$button.parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$cell.empty().html(data.html),$cell.find(".kraken-item-details").tipsy(tipsySettings),$originalSizeColumn.html(originalSize),$parent.remove()})}else data.error&&"This image can not be optimized any further"===data.error&&$krakedSizeColumn.text("No savings found.")}).fail(function(){}).always(function(){$spinner.css({display:"none"}),callback()})},kraken_settings.bulk_async_limit);q.drain=function(){$(".kraken_req_bulk").removeAttr("disabled").css({opacity:1}).text("Done").unbind("click").click(function(){$.kmodal.close()})},q.push(bulkImageData,function(err){})};$btnApplyBulkAction.add($btnApplyBulkAction2).click(function(e){if("kraken-bulk-lossy"===$(this).prev("select").val()){e.preventDefault();var bulkImageData=getBulkImageData();renderBulkImageSummary(bulkImageData),$(".kraken_req_bulk").click(function(e){e.preventDefault(),$(this).attr("disabled",!0).css({opacity:.5}),bulkAction(bulkImageData)})}});var activeId=null;$(".kraken-item-details").tipsy(tipsySettings);$("body").on("click",".kraken-item-details",function(e){var id=$(this).data("id");return $(".tipsy").remove(),id==activeId?(activeId=null,void $(this).text("Show details")):($(".kraken-item-details").text("Show details"),$(this).tipsy("show"),void $(this).text("Hide details"))}),$("body").on("click",function(e){var $t=$(e.target);$t.hasClass("tipsy")||$t.closest(".tipsy").length||$t.hasClass("kraken-item-details")||(activeId=null,$(".kraken-item-details").text("Show details"),$(".tipsy").remove())}),$("body").on("click","small.krakenReset",function(e){e.preventDefault();var $resetButton=$(this),resetData={action:"kraken_reset"};resetData.id=$(this).data("id"),$row=$("#post-"+resetData.id).find(".kraked_size");var $spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4 2 }).done(function(data,textStatus,jqXHR){"undefined"!==data.success&&($row.hide().html(data.html).fadeIn().prev(".original_size.column-original_size").html(data.original_size),$(".tipsy").remove())})}),$("body").on("click",".kraken-reset-all",function(e){e.preventDefault();var reset=confirm("This will immediately remove all Kraken metadata associated with your images. \n\nAre you sure you want to do this?");if(reset){var $resetButton=$(this);$resetButton.text("Resetting images, pleaes wait...").attr("disabled",!0);var resetData={action:"kraken_reset_all"},$spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);{$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){$spinner.remove(),$resetButton.text("Your images have been reset.").removeAttr("disabled").removeClass("enabled")})}}}),$(".krakenAdvancedSettings h3").on("click",function(){var $rows=$(".kraken-advanced-settings"),$plusMinus=$(".kraken-plus-minus");$rows.is(":visible")?($rows.hide(),$plusMinus.removeClass("dashicons-arrow-down").addClass("dashicons-arrow-right")):($rows.show(),$plusMinus.removeClass("dashicons-arrow-right").addClass("dashicons-arrow-down"))}),$("body").on("click",".kraken_req",function(e){e.preventDefault();var $button=$(this),$parent=$(this).parent();data.id=$(this).data("id"),$button.text("Optimizing image...").attr("disabled",!0).css({opacity:.5}),$parent.find(".krakenSpinner").css("display","inline");$.ajax({url:ajax_object.ajax_url,data:data,type:"post",dataType:"json",timeout:36e4,context:$button}).done(requestSuccess).fail(requestFail).always(requestComplete)})}); -
kraken-image-optimizer/trunk/kraken.php
r1144921 r1351884 22 22 * Description: This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization solution. 23 23 * Author: Karim Salman 24 * Version: 2. 0.025 * Stable Tag: 2. 0.024 * Version: 2.5.0 25 * Stable Tag: 2.5.0 26 26 * Author URI: https://kraken.io 27 27 * License GPL2 … … 42 42 private $optimization_type = 'lossy'; 43 43 44 public static $kraken_plugin_version = '2. 0.0';44 public static $kraken_plugin_version = '2.5.0'; 45 45 46 46 function __construct() { … … 51 51 add_action( 'admin_enqueue_scripts', array( &$this, 'my_enqueue' ) ); 52 52 add_action( 'wp_ajax_kraken_reset', array( &$this, 'kraken_media_library_reset' ) ); 53 add_action( 'wp_ajax_kraken_optimize', array( &$this, 'kraken_optimize' ) ); 53 54 add_action( 'wp_ajax_kraken_request', array( &$this, 'kraken_media_library_ajax_callback' ) ); 54 55 add_action( 'wp_ajax_kraken_reset_all', array( &$this, 'kraken_media_library_reset_all' ) ); … … 56 57 add_filter( 'manage_media_columns', array( &$this, 'add_media_columns') ); 57 58 add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array( &$this, 'add_settings_link' ) ); 59 58 60 if ( ( !empty( $this->kraken_settings ) && !empty( $this->kraken_settings['auto_optimize'] ) ) || !isset( $this->kraken_settings['auto_optimize'] ) ) { 59 add_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails') ); 60 add_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) ); 61 } 62 add_action( 'admin_menu', array( &$this, 'kraken_menu' ) ); 61 add_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) ); 62 add_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails' ) ); 63 } 64 add_action( 'admin_menu', array( &$this, 'kraken_menu' ) ); 65 } 66 67 function isApiActive() { 68 $settings = $this->kraken_settings; 69 $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : ''; 70 $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : ''; 71 if ( empty( $api_key ) || empty( $api_secret) ) { 72 return false; 73 } 74 return true; 63 75 } 64 76 … … 67 79 } 68 80 81 function blog_kraker() { 82 add_management_page( 'Blog Kraker', 'Blog Kraker', 'manage_options', 'blog-kraker', array( &$this, 'show_blog_kraker' ) ); 83 } 69 84 70 85 function add_settings_link ( $links ) { … … 75 90 } 76 91 77 78 function kraken_settings_page() { 79 92 function kraken_settings_page() { 93 80 94 if ( !empty( $_POST ) ) { 81 95 $options = $_POST['_kraken_options']; … … 87 101 $lossy = isset( $settings['api_lossy'] ) ? $settings['api_lossy'] : 'lossy'; 88 102 $auto_optimize = isset( $settings['auto_optimize'] ) ? $settings['auto_optimize'] : 1; 89 103 $optimize_main_image = isset( $settings['optimize_main_image'] ) ? $settings['optimize_main_image'] : 1; 90 104 $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : ''; 91 105 $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : ''; 92 93 106 $show_reset = isset( $settings['show_reset'] ) ? $settings['show_reset'] : 0; 94 107 $bulk_async_limit = isset( $settings['bulk_async_limit'] ) ? $settings['bulk_async_limit'] : 4; 108 $preserve_meta_date = isset( $settings['preserve_meta_date'] ) ? $settings['preserve_meta_date'] : 0; 109 $preserve_meta_copyright = isset( $settings['preserve_meta_copyright'] ) ? $settings['preserve_meta_copyright'] : 0; 110 $preserve_meta_geotag = isset( $settings['preserve_meta_geotag'] ) ? $settings['preserve_meta_geotag'] : 0; 111 $preserve_meta_orientation = isset( $settings['preserve_meta_orientation'] ) ? $settings['preserve_meta_orientation'] : 0; 112 $preserve_meta_profile = isset( $settings['preserve_meta_profile'] ) ? $settings['preserve_meta_profile'] : 0; 113 $auto_orient = isset( $settings['auto_orient'] ) ? $settings['auto_orient'] : 1; 114 $resize_width = isset( $settings['resize_width'] ) ? $settings['resize_width'] : 0; 115 $resize_height = isset( $settings['resize_height'] ) ? $settings['resize_height'] : 0; 116 $jpeg_quality = isset( $settings['jpeg_quality'] ) ? $settings['jpeg_quality'] : 0; 95 117 96 118 $status = $this->get_api_status( $api_key, $api_secret ); … … 139 161 </tr> 140 162 <tr> 141 <th scope="row">Optimization Type:</th> 163 <th scope="row">API status:</th> 164 <td> 165 <?php echo $status_html ?> 166 </td> 167 </tr> 168 <tr class="with-tip"> 169 <th scope="row">Optimization mode:</th> 142 170 <td> 143 171 <input type="radio" id="kraken_lossy" name="_kraken_options[api_lossy]" value="lossy" <?php checked( 'lossy', $lossy, true ); ?>/> 144 <label for="kraken_lossy"> Lossy</label>172 <label for="kraken_lossy">Intelligent Lossy</label> 145 173 <input style="margin-left:10px;" type="radio" id="kraken_lossless" name="_kraken_options[api_lossy]" value="lossless" <?php checked( 'lossless', $lossy, true ) ?>/> 146 174 <label for="kraken_lossless">Lossless</label> 147 175 </td> 148 176 </tr> 149 <tr> 177 <tr class="tip"> 178 <td colspan="2"> 179 <div> 180 The <strong>Intelligent Lossy</strong> mode will yield the greatest savings without perceivable reducing the quality of your images, and so we recommend this setting to users.<br /> 181 The <strong>Lossless</strong> mode will result in an unchanged image, however, will yield reduced savings as the image will not be recompressed. 182 </div> 183 </td> 184 </tr> 185 <tr class="with-tip"> 150 186 <th scope="row">Automatically optimize uploads:</th> 151 187 <td> 152 188 <input type="checkbox" id="auto_optimize" name="_kraken_options[auto_optimize]" value="1" <?php checked( 1, $auto_optimize, true ); ?>/> 153 189 </td> 154 </tr> 155 <tr> 156 <th scope="row">API status:</th> 190 </tr> 191 <tr class="tip"> 192 <td colspan="2"> 193 <div> 194 Enabled by default. This setting causes images uploaded through the Media Uploader to be optimized on-the-fly.<br /> 195 If you do not wish to do this, or wish to optimize images later, disable this setting by unchecking the box. 196 </div> 197 </td> 198 </tr> 199 <tr class="with-tip"> 200 <th scope="row">Optimize main image:</th> 157 201 <td> 158 < ?php echo $status_html ?>202 <input type="checkbox" id="optimize_main_image" name="_kraken_options[optimize_main_image]" value="1" <?php checked( 1, $optimize_main_image, true ); ?>/> 159 203 </td> 160 204 </tr> 161 <tr> 162 <td class="krakenAdvancedSettings"><h3><span class="kraken-advanced-settings-label" title="Click to toggle advanced settings">Advanced Settings</span><span class="kraken-plus-minus dashicons dashicons-arrow-right"></span></h3></td> 205 <tr class="tip"> 206 <td colspan="2"> 207 <div> 208 Enabled by default. This option causes the image uploaded by the user to get optimized, as well as all sizes generated by WordPress.<br /> 209 Disabling this option results in faster uploading, since the main image is not sent to our system for optimization.<br /> 210 Disable this option if you never use the "main" image upload in your posts, or speed of image uploading is an issue. 211 </div> 212 </td> 213 </tr> 214 <tr class="with-tip"> 215 <th scope="row">Resize main image:</th> 216 <td> 217 Max Width (px): <input type="text" id="kraken_maximum_width" name="_kraken_options[resize_width]" value="<?php echo esc_attr( $resize_width ); ?>" style="width:50px;" /> Max Height (px): <input type="text" id="kraken_maximum_height" name="_kraken_options[resize_height]" value="<?php echo esc_attr( $resize_height ); ?>" style="width:50px;" /> 218 </td> 219 </tr> 220 <tr class="tip"> 221 <td colspan="2"> 222 <div> 223 You can restrict the maximum dimensions of image uploads by width and/or height.<br /> 224 It is especially useful if you wish to prevent unnecessarily large photos with extremely high resolutions from being uploaded, for example, <br /> 225 photos shot with a recent-model iPhone. Note: you can restrict the dimenions by width, height, or both. A value of zero disables. 226 </div> 227 </td> 228 </tr> 229 <tr class="with-tip"> 230 <th scope="row">JPEG quality setting:</th> 231 <td> 232 <select name="_kraken_options[jpeg_quality]"> 233 <?php $i = 0 ?> 234 <?php foreach ( range(100, 25) as $number ) { ?> 235 <?php if ( $i === 0 ) { ?> 236 <?php echo '<option value="0">Intelligent lossy (recommended)</option>'; ?> 237 <?php } ?> 238 <?php if ($i > 0) { ?> 239 <option value="<?php echo $number ?>" <?php selected( $jpeg_quality, $number, true); ?>> 240 <?php echo $number; ?> 241 <?php } ?> 242 </option> 243 <?php $i++ ?> 244 <?php } ?> 245 </select> 246 </td> 247 </tr> 248 <tr class="tip"> 249 <td colspan="2"> 250 <div> 251 Advanced users can force the quality of JPEG images to a discrete "q" value between 25 and 100 using this setting <br /> 252 For example, forcing the quality to 60 or 70 might yield greater savings, but the resulting quality might be affected, depending on the image. <br /> 253 We therefore recommend keeping the <strong>Intelligent Lossy</strong> setting, which will not allow a resulting image of unacceptable quality.<br /> 254 This settings will be ignored when using the <strong>lossless</strong> optimization mode. 255 </div> 256 </td> 257 </tr> 258 <tr class="no-border"> 259 <td class="krakenAdvancedSettings"><h3><span class="kraken-advanced-settings-label" title="Click to toggle advanced settings">Advanced Settings</span></h3></td> 163 260 </tr> 164 261 <tr class="kraken-advanced-settings"> 165 262 <td colspan="2" class="krakenAdvancedSettingsDescription"><small>We recommend that you leave these settings at their default values</td> 166 263 </tr> 167 <tr class="kraken-advanced-settings"> 168 <th scope="row"> 169 Show metadata reset per image: 170 <small class="krakenWhatsThis" title="Checking this option will add a Reset button in the Kraked Size column for each optimized image. Resetting an image will remove the Kraken.io metadata associated with it, effectively making your blog forget that it had been optimized in the first place, allowing further optimization in some cases. If an image has been optimized using the lossless setting, lossless optimization will not yield any greater savings. If in doubt, please contact [email protected]">What's this?</small> 171 </th> 264 <tr class="kraken-advanced-settings"> 265 <th scope="row">Preserve EXIF Metadata:</th> 266 <td> 267 <label for="preserve_meta_date"><input type="checkbox" id="preserve_meta_date" name="_kraken_options[preserve_meta_date]" value="1" <?php checked( 1, $preserve_meta_date, true ); ?>/> Date</label> 268 <label for="preserve_meta_copyright"><input type="checkbox" id="preserve_meta_copyright" name="_kraken_options[preserve_meta_copyright]" value="1" <?php checked( 1, $preserve_meta_copyright, true ); ?>/> Copyright</label> 269 <label for="preserve_meta_geotag"><input type="checkbox" id="preserve_meta_geotag" name="_kraken_options[preserve_meta_geotag]" value="1" <?php checked( 1, $preserve_meta_geotag, true ); ?>/> Geotag</label> 270 <label for="preserve_meta_orientation"><input type="checkbox" id="preserve_meta_orientation" name="_kraken_options[preserve_meta_orientation]" value="1" <?php checked( 1, $preserve_meta_orientation, true ); ?>/> Orientation</label> 271 <label for="preserve_meta_profile"><input type="checkbox" id="preserve_meta_profile" name="_kraken_options[preserve_meta_profile]" value="1" <?php checked( 1, $preserve_meta_profile, true ); ?>/> Profile</label> 272 </td> 273 </tr> 274 <tr class="kraken-advanced-settings with-tip"> 275 <th scope="row">Automatically Orient Images:</th> 276 <td> 277 <input type="checkbox" id="auto_orient" name="_kraken_options[auto_orient]" value="1" <?php checked( 1, $auto_orient, true ); ?>/> 278 </td> 279 </tr> 280 <tr class="tip"> 281 <td colspan="2"> 282 <div> 283 This setting will rotate the JPEG image according to its <strong>Orientation</strong> EXIF metadata such that it will always be correctly displayed in Web Browsers.<br /> 284 Enable this setting if many of your image uploads come from smart phones or digital cameras which set the orientation based on how they are held at the time of shooting. 285 </div> 286 </td> 287 </tr> 288 <tr class="kraken-advanced-settings with-tip"> 289 <th scope="row">Show metadata reset per image:</th> 172 290 <td> 173 291 <input type="checkbox" id="kraken_show_reset" name="_kraken_options[show_reset]" value="1" <?php checked( 1, $show_reset, true ); ?>/> … … 175 293 </td> 176 294 </tr> 177 <tr class="kraken-advanced-settings"> 178 <th scope="row"> 179 Bulk Concurrency: 180 <small class="krakenWhatsThis" title="This settings defines how many images can be processed at the same time using the bulk optimizer. The recommended value is 4. For blogs on very small hosting plans, or with reduced connectivity, a lower number might be necessary to avoid hitting request limits.">what's this?</small> 181 </th> 295 <tr class="tip"> 296 <td colspan="2"> 297 <div> 298 Checking this option will add a Reset button in the "Show Details" popup in the Kraken Stats column for each optimized image.<br /> 299 Resetting an image will remove the Kraken.io metadata associated with it, effectively making your blog forget that it had been optimized in the first place, allowing further optimization in some cases.<br /> 300 If an image has been optimized using the lossless setting, lossless optimization will not yield any greater savings. If in doubt, please contact [email protected] 301 </div> 302 </td> 303 </tr> 304 <tr class="kraken-advanced-settings with-tip"> 305 <th scope="row">Bulk Concurrency:</th> 182 306 <td> 183 307 <select name="_kraken_options[bulk_async_limit]"> … … 189 313 </select> 190 314 </td> 191 </tr> 315 </tr> 316 <tr class="tip"> 317 <td colspan="2"> 318 <div> 319 This settings defines how many images can be processed at the same time using the bulk optimizer. The recommended (and default) value is 4. <br /> 320 For blogs on very small hosting plans, or with reduced connectivity, a lower number might be necessary to avoid hitting request limits. 321 </div> 322 </td> 323 </tr> 192 324 </tbody> 193 325 </table> … … 202 334 $valid['api_lossy'] = $input['api_lossy']; 203 335 $valid['auto_optimize'] = isset( $input['auto_optimize'] )? 1 : 0; 336 $valid['optimize_main_image'] = isset( $input['optimize_main_image'] ) ? 1 : 0; 337 $valid['preserve_meta_date'] = isset( $input['preserve_meta_date'] ) ? $input['preserve_meta_date'] : 0; 338 $valid['preserve_meta_copyright'] = isset( $input['preserve_meta_copyright'] ) ? $input['preserve_meta_copyright'] : 0; 339 $valid['preserve_meta_geotag'] = isset( $input['preserve_meta_geotag'] ) ? $input['preserve_meta_geotag'] : 0; 340 $valid['preserve_meta_orientation'] = isset( $input['preserve_meta_orientation'] ) ? $input['preserve_meta_orientation'] : 0; 341 $valid['preserve_meta_profile'] = isset( $input['preserve_meta_profile'] ) ? $input['preserve_meta_profile'] : 0; 342 $valid['auto_orient'] = isset( $input['auto_orient'] ) ? $input['auto_orient'] : 0; 204 343 $valid['show_reset'] = isset( $input['show_reset'] ) ? 1 : 0; 205 344 $valid['bulk_async_limit'] = isset( $input['bulk_async_limit'] ) ? $input['bulk_async_limit'] : 4; 345 $valid['resize_width'] = isset( $input['resize_width'] ) ? (int) $input['resize_width'] : 0; 346 $valid['resize_height'] = isset( $input['resize_height'] ) ? (int) $input['resize_height'] : 0; 347 $valid['jpeg_quality'] = isset( $input['jpeg_quality'] ) ? (int) $input['jpeg_quality'] : 0; 206 348 207 349 if ( $valid['show_reset'] ) { … … 241 383 242 384 function my_enqueue( $hook ) { 385 243 386 if ( $hook == 'options-media.php' || $hook == 'upload.php' || $hook == 'settings_page_wp-krakenio' ) { 244 387 wp_enqueue_script( 'jquery' ); … … 273 416 274 417 /** 418 * Converts an deserialized API result array into an array 419 * which this plugin will consume 420 */ 421 function get_result_arr( $result, $image_id ) { 422 $rv = array(); 423 $rv['original_size'] = $result['original_size']; 424 $rv['kraked_size'] = $result['kraked_size']; 425 $rv['saved_bytes'] = $result['saved_bytes']; 426 $savings_percentage = $result['saved_bytes'] / $result['original_size'] * 100; 427 $rv['savings_percent'] = round( $savings_percentage, 2 ) . '%'; 428 $rv['type'] = $result['type']; 429 if ( !empty( $result['kraked_width'] ) && !empty( $result['kraked_height'] ) ) { 430 $rv['kraked_width'] = $result['kraked_width']; 431 $rv['kraked_height'] = $result['kraked_height']; 432 } 433 $rv['success'] = $result['success']; 434 $rv['meta'] = wp_get_attachment_metadata( $image_id ); 435 return $rv; 436 } 437 438 439 /** 275 440 * Handles optimizing already-uploaded images in the Media Library 276 441 */ 277 442 function kraken_media_library_ajax_callback() { 278 443 279 444 $image_id = (int) $_POST['id']; 280 445 $type = false; 446 281 447 if ( isset( $_POST['type'] ) ) { 282 448 $type = $_POST['type']; 449 $this->optimization_type = $type; 283 450 } 284 451 … … 287 454 if ( wp_attachment_is_image( $image_id ) ) { 288 455 456 $settings = $this->kraken_settings; 457 289 458 $image_path = get_attached_file( $image_id ); 290 $ settings = $this->kraken_settings;459 $optimize_main_image = !empty( $settings['optimize_main_image'] ); 291 460 $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : ''; 292 461 $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : ''; 293 462 294 $ status = $this->get_api_status( $api_key, $api_secret);295 296 if ( $status === false) {297 $ kv['error'] = 'There is a problem with your credentials. Please check them in the Kraken.io settings section of Media Settings, and try again.';298 update_post_meta( $image_id, '_kraken_size', $ kv);299 echo json_encode( array( 'error' => $ kv['error'] ) );463 $data = array(); 464 465 if ( empty( $api_key ) && empty( $api_secret ) ) { 466 $data['error'] = 'There is a problem with your credentials. Please check them in the Kraken.io settings section of Media Settings, and try again.'; 467 update_post_meta( $image_id, '_kraken_size', $data ); 468 echo json_encode( array( 'error' => $data['error'] ) ); 300 469 exit; 301 470 } 302 471 303 if ( isset( $status['active'] ) && $status['active'] === true ) { 304 472 if ( $optimize_main_image ) { 473 474 // check if thumbs already optimized 475 $thumbs_optimized = false; 476 $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true ); 477 478 if ( !empty ( $kraked_thumbs_data ) ) { 479 $thumbs_optimized = true; 480 } 481 482 // get metadata for thumbnails 483 $image_data = wp_get_attachment_metadata( $image_id ); 484 485 if ( !$thumbs_optimized ) { 486 $this->optimize_thumbnails( $image_data ); 487 } else { 488 489 // re-optimize thumbs if mode has changed 490 $kraked_thumbs_mode = $kraked_thumbs_data[0]['type']; 491 if ( strcmp( $kraked_thumbs_mode, $this->optimization_type ) !== 0 ) { 492 wp_generate_attachment_metadata( $image_id, $image_path ); 493 $this->optimize_thumbnails( $image_data ); 494 } 495 } 496 497 $resize = false; 498 if ( !empty( $settings['resize_width'] ) || !empty( $settings['resize_height'] ) ) { 499 $resize = true; 500 } 501 502 $api_result = $this->optimize_image( $image_path, $type, $resize ); 503 504 if ( !empty( $api_result ) && !empty( $api_result['success'] ) ) { 505 $data = $this->get_result_arr( $api_result, $image_id ); 506 if ( $this->replace_image( $image_path, $api_result['kraked_url'] ) ) { 507 508 if ( !empty( $data['kraked_width'] ) && !empty( $data['kraked_height'] ) ) { 509 $image_data = wp_get_attachment_metadata( $image_id ); 510 $image_data['width'] = $data['kraked_width']; 511 $image_data['height'] = $data['kraked_height']; 512 wp_update_attachment_metadata( $image_id, $image_data ); 513 } 514 515 // store kraked info to DB 516 update_post_meta( $image_id, '_kraken_size', $data ); 517 518 // krak thumbnails, store that data too. This can be unset when there are no thumbs 519 $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true ); 520 if ( !empty( $kraked_thumbs_data ) ) { 521 $data['thumbs_data'] = $kraked_thumbs_data; 522 $data['success'] = true; 523 } 524 525 $data['html'] = $this->generate_stats_summary( $image_id ); 526 echo json_encode( $data ); 527 528 } else { 529 echo json_encode( array( 'error' => 'Could not overwrite original file. Please ensure that your files are writable by plugins.' ) ); 530 exit; 531 } 532 533 } else { 534 // error or no optimization 535 if ( file_exists( $image_path ) ) { 536 update_post_meta( $image_id, '_kraken_size', $data ); 537 } else { 538 // file not found 539 } 540 echo json_encode( array( 'error' => $api_result['message'], '' ) ); 541 } 305 542 } else { 306 echo json_encode( array( 'error' => 'Your API is inactive. Please visit your account settings' ) ); 307 die(); 308 } 309 310 $result = $this->optimize_image( $image_path, $type ); 311 312 $kv = array(); 313 314 if ( $result['success'] == true && !isset( $result['error'] ) ) { 315 316 $kraked_url = $result['kraked_url']; 317 $savings_percentage = (int) $result['saved_bytes'] / (int) $result['original_size'] * 100; 318 $kv['original_size'] = self::pretty_kb( $result['original_size'] ); 319 $kv['kraked_size'] = self::pretty_kb( $result['kraked_size'] ); 320 $kv['saved_bytes'] = self::pretty_kb( $result['saved_bytes'] ); 321 $kv['savings_percent'] = round( $savings_percentage, 2 ) . '%'; 322 $kv['type'] = $result['type']; 323 $kv['success'] = true; 324 $kv['meta'] = wp_get_attachment_metadata( $image_id ); 325 $saved_bytes = (int) $kv['saved_bytes']; 326 327 if ( $this->replace_image( $image_path, $result['kraked_url'] ) ) { 328 329 // get metadata for thumbnails 330 $image_data = wp_get_attachment_metadata( $image_id ); 331 $this->optimize_thumbnails( $image_data ); 332 333 // store kraked info to DB 334 update_post_meta( $image_id, '_kraken_size', $kv ); 335 336 // krak thumbnails, store that data too. This can be unset when there are no thumbs 337 $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true ); 338 if ( !empty( $kraked_thumbs_data ) ) { 339 $kv['thumbs_data'] = $kraked_thumbs_data; 340 } 341 $kv['html'] = $this->results_html( $image_id ); 342 echo json_encode( $kv ); 343 } else { 344 echo json_encode( array( 'error' => 'Could not overwrite original file. Please ensure that your files are writable by plugins.' ) ); 345 exit; 346 } 347 348 } else { 349 350 // error or no optimization 351 if ( file_exists( $image_path ) ) { 352 353 $kv['original_size'] = self::pretty_kb( filesize( $image_path ) ); 354 $kv['error'] = $result['error']; 355 $kv['type'] = $result['type']; 356 357 if ( $kv['error'] == 'This image can not be optimized any further' ) { 358 $kv['kraked_size'] = 'No savings found'; 359 $kv['no_savings'] = true; 360 } 361 362 update_post_meta( $image_id, '_kraken_size', $kv ); 363 364 } else { 365 // file not found 543 // get metadata for thumbnails 544 $image_data = wp_get_attachment_metadata( $image_id ); 545 $this->optimize_thumbnails( $image_data ); 546 547 // krak thumbnails, store that data too. This can be unset when there are no thumbs 548 $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true ); 549 550 if ( !empty( $kraked_thumbs_data ) ) { 551 $data['thumbs_data'] = $kraked_thumbs_data; 552 $data['success'] = true; 366 553 } 367 echo json_encode($result); 368 } 369 } 370 die(); 371 } 554 $data['html'] = $this->generate_stats_summary( $image_id ); 555 556 echo json_encode( $data ); 557 } 558 } 559 wp_die(); 560 } 561 562 563 function is_successful( $response ) {} 372 564 373 565 /** … … 375 567 */ 376 568 function kraken_media_uploader_callback( $image_id ) { 569 377 570 $this->id = $image_id; 378 571 572 if ( !$this->kraken_settings['optimize_main_image'] ) { 573 return; 574 } 575 576 $settings = $this->kraken_settings; 577 $type = $settings['api_lossy']; 578 579 if ( !$this->isApiActive() ) { 580 remove_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails') ); 581 remove_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) ); 582 return; 583 } 584 379 585 if ( wp_attachment_is_image( $image_id ) ) { 380 586 381 $settings = $this->kraken_settings;382 $type = $settings['api_lossy'];383 587 $image_path = get_attached_file( $image_id ); 384 $result = $this->optimize_image( $image_path, $type ); 385 386 if ( $result['success'] == true && !isset( $result['error'] ) ) { 387 388 $kraked_url = $result['kraked_url']; 389 $savings_percentage = (int) $result['saved_bytes'] / (int) $result['original_size'] * 100; 390 $kv['original_size'] = self::pretty_kb( $result['original_size'] ); 391 $kv['kraked_size'] = self::pretty_kb( $result['kraked_size'] ); 392 $kv['saved_bytes'] = self::pretty_kb( $result['saved_bytes'] ); 393 $kv['savings_percent'] = round( $savings_percentage, 2 ) . '%'; 394 $kv['type'] = $result['type']; 395 $kv['success'] = true; 396 $kv['meta'] = wp_get_attachment_metadata( $image_id ); 397 $saved_bytes = (int) $kv['saved_bytes']; 398 399 if ( $this->replace_image( $image_path, $kraked_url ) ) { 400 update_post_meta( $image_id, '_kraken_size', $kv ); 588 $image_backup_path = $image_path . '_kraken_' . md5( $image_path ); 589 $backup_created = false; 590 591 if ( copy( $image_path, $image_backup_path ) ) { 592 $backup_created = true; 593 } 594 595 $resize = false; 596 if ( !empty( $settings['resize_width'] ) || !empty( $settings['resize_height'] ) ) { 597 $resize = true; 598 } 599 600 // optimize backup image 601 if ( $backup_created ) { 602 $api_result = $this->optimize_image( $image_backup_path, $type, $resize ); 603 } else { 604 $api_result = $this->optimize_image( $image_path, $type, $resize ); 605 } 606 607 $data = array(); 608 609 if ( !empty( $api_result ) && !empty( $api_result['success'] ) ) { 610 $data = $this->get_result_arr( $api_result, $image_id ); 611 612 if ( $backup_created ) { 613 $data['optimized_backup_file'] = $image_backup_path; 614 if ( $data['saved_bytes'] > 0 ) { 615 if ( $this->replace_image( $image_backup_path, $api_result['kraked_url'] ) ) { 616 } else { 617 error_log('Kraken.io: Could not replace local image with optimized image.'); 618 } 619 } 401 620 } else { 402 // writing image failed 621 if ( $data['saved_bytes'] > 0 ) { 622 if ( $this->replace_image( $image_path, $api_result['kraked_url'] ) ) { 623 } else { 624 error_log('Kraken.io: Could not replace local image with optimized image.'); 625 } 626 } 403 627 } 628 update_post_meta( $image_id, '_kraken_size', $data ); 404 629 405 630 } else { 406 407 631 // error or no optimization 408 632 if ( file_exists( $image_path ) ) { 409 633 410 $kv['original_size'] = self::pretty_kb( filesize( $image_path ) ); 411 $kv['error'] = $result['error']; 412 $kv['type'] = $result['type']; 413 414 if ( $kv['error'] == 'This image can not be optimized any further' ) { 415 $kv['kraked_size'] = 'No savings found'; 416 $kv['no_savings'] = true; 417 } 418 419 update_post_meta( $image_id, '_kraken_size', $kv ); 634 $data['original_size'] = filesize( $image_path ); 635 $data['error'] = $api_result['message']; 636 $data['type'] = $api_result['type']; 637 update_post_meta( $image_id, '_kraken_size', $data ); 420 638 421 639 } else { … … 429 647 $image_id = (int) $_POST['id']; 430 648 $image_meta = get_post_meta( $image_id, '_kraken_size', true ); 431 $original_size = $image_meta['kraked_size'];649 $original_size = self::formatBytes( filesize( get_attached_file( $image_id ) ) ); 432 650 delete_post_meta( $image_id, '_kraken_size' ); 433 651 delete_post_meta( $image_id, '_kraked_thumbs' ); 434 652 echo json_encode( array( 'success' => true, 'original_size' => $original_size, 'html' => $this->optimize_button_html( $image_id ) ) ); 435 die();653 wp_die(); 436 654 } 437 655 … … 442 660 $result = json_encode( array( 'success' => true ) ); 443 661 echo $result; 444 die();662 wp_die(); 445 663 } 446 664 … … 554 772 } 555 773 556 557 774 function add_media_columns( $columns ) { 558 775 $columns['original_size'] = 'Original Size'; 559 $columns['kraked_size'] = 'Krake d Size';776 $columns['kraked_size'] = 'Kraken.io Stats'; 560 777 return $columns; 561 778 } 562 779 563 function results_html( $id ) { 780 781 static function KBStringToBytes( $str ) { 782 $temp = floatVal( $str ); 783 $rv = false; 784 if ( 0 == $temp ) { 785 $rv = '0 bytes'; 786 } else { 787 $rv = self::formatBytes( ceil( floatval( $str) * 1024 ) ); 788 } 789 return $rv; 790 } 791 792 793 static function calculate_savings( $meta ) { 794 795 if ( isset( $meta['original_size'] ) ) { 796 797 $saved_bytes = isset( $meta['saved_bytes'] ) ? $meta['saved_bytes'] : ''; 798 $savings_percentage = $meta['savings_percent']; 799 800 // convert old data format, where applicable 801 if ( stripos( $saved_bytes, 'kb' ) !== false ) { 802 $saved_bytes = self::KBStringToBytes( $saved_bytes ); 803 } else { 804 if ( !$saved_bytes ) { 805 $saved_bytes = '0 bytes'; 806 } else { 807 $saved_bytes = self::formatBytes( $saved_bytes ); 808 } 809 } 810 811 return array( 812 'saved_bytes' => $saved_bytes, 813 'savings_percentage' => $savings_percentage 814 ); 815 816 } else if ( !empty( $meta ) ) { 817 $thumbs_count = count( $meta ); 818 $total_thumb_byte_savings = 0; 819 $total_thumb_size = 0; 820 $thumbs_savings_percentage = ''; 821 $total_thumbs_savings = ''; 822 823 foreach ( $meta as $k => $v ) { 824 $total_thumb_size += $v['original_size']; 825 $thumb_byte_savings = $v['original_size'] - $v['kraked_size']; 826 $total_thumb_byte_savings += $thumb_byte_savings; 827 } 828 829 $thumbs_savings_percentage = round( ( $total_thumb_byte_savings / $total_thumb_size * 100 ), 2 ) . '%'; 830 if ( $total_thumb_byte_savings ) { 831 $total_thumbs_savings = self::formatBytes( $total_thumb_byte_savings ); 832 } else { 833 $total_thumbs_savings = '0 bytes'; 834 } 835 return array( 836 'savings_percentage' => $thumbs_savings_percentage, 837 'total_savings' => $total_thumbs_savings 838 ); 839 } 840 } 841 842 function generate_stats_summary( $id ) { 564 843 $image_meta = get_post_meta( $id, '_kraken_size', true ); 565 844 $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true ); 566 $kraked_size = $image_meta['kraked_size']; 567 $type = $image_meta['type']; 568 $thumbs_count = count( $thumbs_meta ); 569 $savings_percentage = $image_meta['savings_percent']; 570 845 846 $total_original_size = 0; 847 $total_kraked_size = 0; 848 $total_saved_bytes = 0; 849 850 $total_savings_percentage = 0; 851 852 // crap for backward compat 853 if ( isset( $image_meta['original_size'] ) ) { 854 855 $original_size = $image_meta['original_size']; 856 857 if ( stripos( $original_size, 'kb' ) !== false ) { 858 $total_original_size = ceil( floatval( $original_size ) * 1024 ); 859 } else { 860 $total_original_size = (int) $original_size; 861 } 862 863 if ( isset( $image_meta['saved_bytes'] ) ) { 864 $saved_bytes = $image_meta['saved_bytes']; 865 if ( is_string( $saved_bytes ) ) { 866 $total_saved_bytes = (int) ceil( floatval( $saved_bytes ) * 1024 ); 867 } else { 868 $total_saved_bytes = $saved_bytes; 869 } 870 } 871 872 $total_kraked_size = $total_original_size - $total_saved_bytes; 873 } 874 875 if ( !empty( $thumbs_meta ) ) { 876 $thumb_saved_bytes = 0; 877 $total_thumb_byte_savings = 0; 878 $total_thumb_size = 0; 879 880 foreach ( $thumbs_meta as $k => $v ) { 881 $total_original_size += $v['original_size']; 882 $thumb_saved_bytes = $v['original_size'] - $v['kraked_size']; 883 $total_saved_bytes += $thumb_saved_bytes; 884 } 885 886 } 887 $total_savings_percentage = round( ( $total_saved_bytes / $total_original_size * 100 ), 2 ) . '%'; 888 $summary_string = ''; 889 if ( !$total_saved_bytes ) { 890 $summary_string = 'No savings'; 891 } else { 892 $total_savings = self::formatBytes( $total_saved_bytes ); 893 $detailed_results_html = $this->results_html( $id ); 894 $summary_string = '<div class="kraken-result-wrap">' . "Saved $total_savings_percentage ($total_savings)"; 895 $summary_string .= '<br /><small class="kraken-item-details" data-id="' . $id . '" original-title="' . htmlspecialchars($detailed_results_html) .'">Show details</small></div>'; 896 } 897 return $summary_string; 898 } 899 900 function results_html( $id ) { 901 902 $settings = $this->kraken_settings; 903 $optimize_main_image = !empty( $settings['optimize_main_image'] ); 904 905 // get meta data for main post and thumbs 906 $image_meta = get_post_meta( $id, '_kraken_size', true ); 907 $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true ); 908 $main_image_optimized = !empty( $image_meta ) && isset( $image_meta['type'] ); 909 $thumbs_optimized = !empty( $thumbs_meta ) && count( $thumbs_meta ) && isset( $thumbs_meta[0]['type'] ); 910 911 $type = ''; 912 $kraked_size = ''; 913 $savings_percentage = ''; 914 915 if ( $main_image_optimized ) { 916 $type = $image_meta['type']; 917 $kraked_size = isset( $image_meta['kraked_size'] ) ? $image_meta['kraked_size'] : ''; 918 $savings_percentage = $image_meta['savings_percent']; 919 $main_image_kraked_stats = self::calculate_savings( $image_meta ); 920 } 921 922 if ( $thumbs_optimized ) { 923 $type = $thumbs_meta[0]['type']; 924 $thumbs_kraked_stats = self::calculate_savings( $thumbs_meta ); 925 $thumbs_count = count( $thumbs_meta ); 926 } 927 571 928 ob_start(); 572 929 ?> 573 <strong><?php echo $kraked_size; ?></strong> 930 <?php if ( $main_image_optimized ) { ?> 931 <div class="kraken_detailed_results_wrap"> 932 <span class=""><strong>Main image savings:</strong></span> 574 933 <br /> 575 <small>Type: <?php echo $type; ?></small> 934 <span style="display:inline-block;margin-bottom:5px"><?php echo $main_image_kraked_stats['saved_bytes']; ?> (<?php echo $main_image_kraked_stats['savings_percentage']; ?> saved)</span> 935 <?php } ?> 936 <?php if ( $main_image_optimized && $thumbs_optimized ) { ?> 576 937 <br /> 577 <small>Savings: <?php echo $savings_percentage; ?></small> 578 <?php if ( !empty( $thumbs_meta ) ) { ?> 938 <?php } ?> 939 <?php if ( $thumbs_optimized ) { ?> 940 <span><strong>Savings on <?php echo $thumbs_count; ?> thumbnails:</strong></span> 579 941 <br /> 580 <s mall><?php echo $thumbs_count; ?> thumbs optimized</small>942 <span style="display:inline-block;margin-bottom:5px"><?php echo $thumbs_kraked_stats['total_savings']; ?> (<?php echo $thumbs_kraked_stats['savings_percentage']; ?> saved)</span> 581 943 <?php } ?> 944 <br /> 945 <span><strong>Optimization mode:</strong></span> 946 <br /> 947 <span><?php echo ucfirst($type); ?></span> 582 948 <?php if ( !empty( $this->kraken_settings['show_reset'] ) ) { ?> 583 949 <br /> 584 <small 950 <small 585 951 class="krakenReset" data-id="<?php echo $id; ?>" 586 952 title="Removes Kraken metadata associated with this image"> … … 588 954 </small> 589 955 <span class="krakenSpinner"></span> 956 </div> 590 957 <?php } ?> 591 958 <?php … … 596 963 function fill_media_columns( $column_name, $id ) { 597 964 598 $original_size = filesize( get_attached_file( $id ) ); 599 $original_size = self::pretty_kb( $original_size ); 600 601 $options = get_option( '_kraken_options' ); 602 $type = isset( $options['api_lossy'] ) ? $options['api_lossy'] : 'lossy'; 603 965 $settings = $this->kraken_settings; 966 $optimize_main_image = !empty( $settings['optimize_main_image'] ); 967 968 $file = get_attached_file( $id ); 969 $original_size = filesize( $file ); 970 971 // handle the case where file does not exist 972 if ( $original_size === 0 || $original_size === false ) { 973 echo '0 bytes'; 974 return; 975 } else { 976 $original_size = self::formatBytes( $original_size ); 977 } 978 979 $type = isset( $settings['api_lossy'] ) ? $settings['api_lossy'] : 'lossy'; 604 980 605 981 if ( strcmp( $column_name, 'original_size' ) === 0 ) { … … 609 985 610 986 if ( isset( $meta['original_size'] ) ) { 611 echo $meta['original_size']; 987 988 if ( stripos( $meta['original_size'], 'kb' ) !== false ) { 989 echo self::formatBytes( ceil( floatval( $meta['original_size']) * 1024 ) ); 990 } else { 991 echo self::formatBytes( $meta['original_size'] ); 992 } 993 612 994 } else { 613 995 echo $original_size; … … 617 999 } 618 1000 } else if ( strcmp( $column_name, 'kraked_size' ) === 0 ) { 619 1001 echo '<div class="kraken-wrap">'; 1002 $image_url = wp_get_attachment_url( $id ); 1003 $filename = basename( $image_url ); 620 1004 if ( wp_attachment_is_image( $id ) ) { 621 1005 622 $meta = get_post_meta($id, '_kraken_size', true); 1006 $meta = get_post_meta( $id, '_kraken_size', true ); 1007 $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true ); 623 1008 624 1009 // Is it optimized? Show some stats 625 if ( isset( $meta['kraked_size'] ) && empty( $meta['no_savings'] ) ) { 626 echo $this->results_html( $id ); 1010 if ( ( isset( $meta['kraked_size'] ) && empty( $meta['no_savings'] ) ) || !empty( $thumbs_meta ) ) { 1011 if ( !isset( $meta['kraked_size'] ) && $optimize_main_image ) { 1012 echo '<div class="buttonWrap"><button data-setting="' . $type . '" type="button" class="kraken_req" data-id="' . $id . '" id="krakenid-' . $id .'" data-filename="' . $filename . '" data-url="' . $image_url . '">Optimize Main Image</button><span class="krakenSpinner"></span></div>'; 1013 } 1014 echo $this->generate_stats_summary( $id ); 627 1015 628 1016 // Were there no savings, or was there an error? 629 1017 } else { 630 $image_url = wp_get_attachment_url( $id );631 $filename = basename( $image_url );632 1018 echo '<div class="buttonWrap"><button data-setting="' . $type . '" type="button" class="kraken_req" data-id="' . $id . '" id="krakenid-' . $id .'" data-filename="' . $filename . '" data-url="' . $image_url . '">Optimize This Image</button><span class="krakenSpinner"></span></div>'; 633 1019 if ( !empty( $meta['no_savings'] ) ) { … … 641 1027 echo 'n/a'; 642 1028 } 1029 echo '</div>'; 643 1030 } 644 1031 } … … 647 1034 $rv = false; 648 1035 $ch = curl_init( $kraked_url ); 649 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true);1036 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); 650 1037 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 ); 651 curl_setopt( $ch, CURLOPT_USERAGENT, 'WordPress/' . get_bloginfo('version') . ' KrakenPlugin/' . self::$kraken_plugin_version ); 1038 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 ); 1039 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 0 ); 1040 curl_setopt( $ch, CURLOPT_TIMEOUT, 120 ); 1041 curl_setopt( $ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36' ); 652 1042 $result = curl_exec( $ch ); 653 $rv = file_put_contents( $image_path, $result ); 1043 1044 if ( $result ) { 1045 $rv = file_put_contents( $image_path, $result ); 1046 } 654 1047 return $rv !== false; 655 1048 } 656 1049 657 function optimize_image( $image_path, $type ) {1050 function optimize_image( $image_path, $type, $resize = false ) { 658 1051 $settings = $this->kraken_settings; 659 1052 $kraken = new Kraken( $settings['api_key'], $settings['api_secret'] ); … … 662 1055 $lossy = $type === 'lossy'; 663 1056 } else { 664 $lossy = $settings['api_lossy'] === "lossy";1057 $lossy = $settings['api_lossy'] === 'lossy'; 665 1058 } 666 1059 667 1060 $params = array( 668 "file"=> $image_path,669 "wait"=> true,670 "lossy"=> $lossy,671 "origin" => "wp"1061 'file' => $image_path, 1062 'wait' => true, 1063 'lossy' => $lossy, 1064 'origin' => 'wp' 672 1065 ); 673 1066 674 try { 675 $data = $kraken->upload( $params ); 676 } catch (Exception $e) { 677 } 678 1067 $preserve_meta_arr = []; 1068 if ( $settings['preserve_meta_date'] ) { 1069 $preserve_meta_arr[] = 'date'; 1070 } 1071 if ( $settings['preserve_meta_copyright'] ) { 1072 $preserve_meta_arr[] = 'copyright'; 1073 } 1074 if ( $settings['preserve_meta_geotag'] ) { 1075 $preserve_meta_arr[] = 'geotag'; 1076 } 1077 if ( $settings['preserve_meta_orientation'] ) { 1078 $preserve_meta_arr[] = 'orientation'; 1079 } 1080 if ( $settings['preserve_meta_profile'] ) { 1081 $preserve_meta_arr[] = 'profile'; 1082 } 1083 1084 if ( count( $preserve_meta_arr ) ) { 1085 $params['preserve_meta'] = $preserve_meta_arr; 1086 } 1087 1088 if ( $settings['auto_orient'] ) { 1089 $params['auto_orient'] = true; 1090 } 1091 1092 if ( $resize ) { 1093 $width = (int) $settings['resize_width']; 1094 $height = (int) $settings['resize_height']; 1095 if ( $width && $height ) { 1096 $params['resize'] = array('strategy' => 'auto', 'width' => $width, 'height' => $height, 'enhance' => true ); 1097 } elseif ( $width && !$height ) { 1098 $params['resize'] = array('strategy' => 'landscape', 'width' => $width, 'enhance' => true ); 1099 } elseif ( $height && !$width ) { 1100 $params['resize'] = array('strategy' => 'portrait', 'height' => $height, 'enhance' => true ); 1101 } 1102 } 1103 1104 if ( isset( $settings['jpeg_quality'] ) && $settings['jpeg_quality'] > 0 ) { 1105 $params['quality'] = (int) $settings['jpeg_quality']; 1106 } 1107 1108 set_time_limit(400); 1109 $data = $kraken->upload( $params ); 679 1110 $data['type'] = !empty( $type ) ? $type : $settings['api_lossy']; 680 681 1111 return $data; 682 1112 } 683 1113 684 1114 function optimize_thumbnails( $image_data ) { 685 1115 686 1116 $image_id = $this->id; 687 1117 if ( empty( $image_id ) ) { … … 709 1139 710 1140 if ( !empty( $sizes ) ) { 711 712 1141 $thumb_path = ''; 713 714 1142 $thumbs_optimized_store = array(); 715 1143 $this_thumb = array(); … … 718 1146 719 1147 $thumb_path = $upload_full_path . '/' . $size['file']; 720 1148 721 1149 if ( file_exists( $thumb_path ) !== false ) { 722 723 1150 $result = $this->optimize_image( $thumb_path, $this->optimization_type ); 724 725 if ( !empty($result) && isset($result['success']) && isset( $result['kraked_url'] ) ) { 726 $kraked_url = $result["kraked_url"]; 727 if ( $this->replace_image( $thumb_path, $kraked_url ) ) { 728 $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['kraked_size'], 'type' => $this->optimization_type ); 729 $thumbs_optimized_store [] = $this_thumb; 1151 if ( !empty( $result ) && isset( $result['success'] ) && isset( $result['kraked_url'] ) ) { 1152 $kraked_url = $result['kraked_url']; 1153 if ( (int) $result['saved_bytes'] !== 0 ) { 1154 if ( $this->replace_image( $thumb_path, $kraked_url ) ) { 1155 $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['kraked_size'], 'type' => $this->optimization_type ); 1156 $thumbs_optimized_store [] = $this_thumb; 1157 } 1158 } else { 1159 $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['original_size'], 'type' => $this->optimization_type ); 1160 $thumbs_optimized_store [] = $this_thumb; 730 1161 } 1162 } else { 1163 return $image_data; 731 1164 } 732 1165 } 733 1166 } 734 1167 } 1168 1169 $kraken_meta = get_post_meta( $image_id, '_kraken_size', true ); 1170 $image_backup_path = isset( $kraken_meta['optimized_backup_file'] ) ? $kraken_meta['optimized_backup_file'] : ''; 1171 1172 if ( $image_backup_path ) { 1173 $original_image_path = get_attached_file( $image_id ); 1174 if ( copy( $image_backup_path, $original_image_path ) ) { 1175 unlink( $image_backup_path ); 1176 unset( $kraken_meta['optimized_backup_file'] ); 1177 update_post_meta( $image_id, '_kraken_size', $kraken_meta ); 1178 } 1179 } 1180 1181 // when resizing has taken place via API, update the post metadata accordingly 1182 if ( !empty( $kraken_meta['kraked_width'] ) && !empty( $kraken_meta['kraked_height'] ) ) { 1183 $image_data['width'] = $kraken_meta['kraked_width']; 1184 $image_data['height'] = $kraken_meta['kraked_height']; 1185 } 1186 735 1187 if ( !empty( $thumbs_optimized_store ) ) { 736 1188 update_post_meta( $image_id, '_kraked_thumbs', $thumbs_optimized_store, false ); … … 739 1191 } 740 1192 741 742 static function pretty_kb( $bytes ) { 743 return round( ( $bytes / 1024 ), 2 ) . ' kB'; 1193 static function formatBytes( $size, $precision = 2 ) { 1194 $base = log( $size, 1024 ); 1195 $suffixes = array( ' bytes', 'KB', 'MB', 'GB', 'TB' ); 1196 return round( pow( 1024, $base - floor( $base ) ), $precision ) . $suffixes[floor( $base )]; 744 1197 } 745 1198 } -
kraken-image-optimizer/trunk/lib/Kraken.php
r1144921 r1351884 1 1 <?php 2 2 3 class Kraken 4 { 3 class Kraken { 4 protected $auth = array(); 5 public static $kraken_plugin_version = '2.5.0'; 5 6 6 protected $auth = array(); 7 public static $kraken_plugin_version = '2.0.0'; 8 9 public function __construct($key = '', $secret = '') 10 { 7 public function __construct($key = '', $secret = '') { 11 8 $this->auth = array( 12 9 "auth" => array( … … 17 14 } 18 15 19 public function url($opts = array()) 20 { 16 public function url($opts = array()) { 21 17 $data = json_encode(array_merge($this->auth, $opts)); 22 $response = self::request($data, "https://api.kraken.io/v1/url");18 $response = self::request($data, 'https://api.kraken.io/v1/url', 'url'); 23 19 24 20 return $response; 25 21 } 26 22 27 public function upload($opts = array()) 28 { 29 if (!isset($opts['file'])) 30 { 23 public function upload($opts = array()) { 24 if (!isset($opts['file'])) { 31 25 return array( 32 26 "success" => false, … … 35 29 } 36 30 37 if (preg_match("/\/\//i", $opts['file'])) 38 { 31 if (preg_match("/\/\//i", $opts['file'])) { 39 32 $opts['url'] = $opts['file']; 40 33 unset($opts['file']); 34 41 35 return $this->url($opts); 42 36 } 43 37 44 if (!file_exists($opts['file'])) 45 { 38 if (!file_exists($opts['file'])) { 46 39 return array( 47 40 "success" => false, 48 "error" => "File `" . $opts['file'] . "` does not exist"41 "error" => 'File `' . $opts['file'] . '` does not exist' 49 42 ); 50 43 } 51 44 52 if ( function_exists('curl_file_create')) {53 $file = curl_file_create($opts['file'], 'image/jpeg',$opts['file']);45 if (class_exists('CURLFile')) { 46 $file = new CURLFile($opts['file']); 54 47 } else { 55 $file = sprintf('@%s', $opts['file']);48 $file = '@' . $opts['file']; 56 49 } 57 50 … … 60 53 $data = array_merge(array( 61 54 "file" => $file, 62 "data" => json_encode(array_merge( 63 $this->auth, $opts 64 )) 55 "data" => json_encode(array_merge($this->auth, $opts)) 65 56 )); 66 67 $response = self::request($data, "https://api.kraken.io/v1/upload"); 57 $response = self::request($data, 'https://api.kraken.io/v1/upload', 'upload'); 68 58 69 59 return $response; 70 60 } 71 61 72 public function status() 73 { 62 public function status() { 74 63 $data = array('auth' => array( 75 64 'api_key' => $this->auth['auth']['api_key'], 76 65 'api_secret' => $this->auth['auth']['api_secret'] 77 66 )); 78 $response = self::request(json_encode($data), "https://api.kraken.io/user_status"); 79 67 $response = self::request(json_encode($data), 'https://api.kraken.io/user_status', 'url'); 80 68 return $response; 81 69 } 82 70 83 private function request($data, $url) 84 { 85 $curl = curl_init(); 86 87 curl_setopt($curl, CURLOPT_URL, $url); 71 private function request($data, $url, $type) { 72 $curl = curl_init($url); 73 74 if ($type === 'url') { 75 curl_setopt($curl, CURLOPT_HTTPHEADER, array( 76 'Content-Type: application/json' 77 )); 78 } 79 80 // Force continue-100 from server 81 curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36'); 82 curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:')); 88 83 curl_setopt($curl, CURLOPT_POST, 1); 89 84 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); … … 92 87 curl_setopt($curl, CURLOPT_TIMEOUT, 400); 93 88 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); 94 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); 95 curl_setopt($curl, CURLOPT_USERAGENT, 'WordPress/' . get_bloginfo('version') . ' KrakenPlugin/' . self::$kraken_plugin_version); 96 curl_setopt($curl, CURLOPT_FAILONERROR, 1); 89 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); 97 90 98 91 $response = json_decode(curl_exec($curl), true); 99 92 $error = curl_errno($curl); 100 93 94 if ($response === null) { 95 $error_code = (int) curl_error($curl); 96 $response = array ( 97 "success" => false, 98 "error" => 'cURL Error: ' . $error_code, 99 "code" => $error_code 100 ); 101 } 101 102 curl_close($curl); 102 103 if ($error > 0) {104 throw new RuntimeException(sprintf('cURL returned with the following error code: "%s"', $error));105 }106 107 103 return $response; 108 104 } 109 110 105 } -
kraken-image-optimizer/trunk/readme.txt
r1144921 r1351884 1 1 === Kraken Image Optimizer === 2 2 Contributors: karim79 3 Tags: Image Optimizer, Image Optimiser, Optimize, Optimise, Images, Media, Performance, SEO, faster loading times, smushit, smush.it, compress, kraken-image-optimizer, tinypng, tinyjpeg, pngquant, jpegmini, ewww, pagespeed, pagespeed insights, sitespeed, optimize gif, optimize jpeg, optimize png, optimize animated gif, svg, improve pagerank, gtmetrix speed test 3 Tags: Image Optimizer, Image Optimiser, Optimize, Optimise, Images, Media, Performance, SEO, faster loading times, smushit, smush.it, compress, kraken-image-optimizer, tinypng, tinyjpeg, pngquant, jpegmini, ewww, pagespeed, pagespeed insights, sitespeed, optimize gif, optimize jpeg, optimize png, optimize animated gif, svg, improve pagerank, gtmetrix speed test, EXIF, image resize 4 4 Requires at least: 3.0.1 5 Tested up to: 4. 25 Tested up to: 4.4.2 6 6 Donate link: https://kraken.io 7 Stable tag: 2. 0.07 Stable tag: 2.5.0 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 10 10 11 11 12 This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization solution.12 This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization and resizing API. 13 13 14 14 == Description == 15 15 16 This plugin allows you to optimize new and existing Wordpress image uploads through [Kraken Image Optimizer's](https://kraken.io "Kraken Image Optimizer") API. Both lossless and intelligent lossy optimization modes are supported. Supported filetypes are JPEG, PNG and GIF. Maximum filesize limit is 16 MB. For more details, including detailed documentation and plans and pricing, please visit [Kraken.io](https://kraken.io "Kraken Image Optimizer").16 This plugin allows you to optimize and resize new and existing Wordpress image uploads through [Kraken Image Optimizer's](https://kraken.io "Kraken Image Optimizer") API. Both lossless and intelligent lossy optimization modes are supported. Supported filetypes are JPEG, PNG and GIF (including animated). Maximum filesize limit is 32 MB. For more details, including detailed documentation and plans and pricing, please visit [Kraken.io](https://kraken.io "Kraken Image Optimizer"). Even when using Kraken.io's lossy optimization, our system goes the extra mile to ensure that the results are of high quality, every time. You can just install the plugin and stop worrying. 17 17 18 18 > **Get your FREE account with us** … … 31 31 * You can use your Kraken API key and secret on as many sites/blogs as you like. We have no per-site license. 32 32 * All images uploaded throught the media uploader are optimized on-the-fly. All generated thumbnails are optimized too. 33 * The main image upload can be optionally resized - this is useful for preventing user uploads with unnecessarily large dimensions. You can specify the maximum width and/or height in Kraken.io->Settings. 34 * When restricting the maximum dimensions of the main image using the resizing feature, the resulting image is **enhanced** using various advanced techniques, to help prevent downsample artifacts and "haloing" and produce a sharper result. 35 * You can optionally preserve one or more of the Date, Copyright, Geotag, Orientation, Profile EXIF metadata tags. 36 * Images can be automatically oriented according to their EXIF Orientation value - no need to manually rotate images. 33 37 * All images already present in the media library can be optimized individually, or using the Bulk Action menu "Krak 'em all" feature. 34 38 * This plugin does not require any root or command-line access. No compilation and installation of any binaries is necessary. … … 53 57 For advanced users, there is a third party WordPress Command Line Interface (CLI) tool to allow image optimization from the command line, or by using cron. For details, visit: https://github.com/tillkruss/wp-cli-kraken 54 58 55 = Features on the way =56 * Optimize images directly to Amazon S3.57 * Optimize entire media library in one click.58 * Optimize your currently active theme.59 * WordPress Multisite support.60 61 59 Please send bug reports, problems, feature requests and so on to support (at) Kraken dot io, or directly to the author of this plugin. 62 60 … … 66 64 * [Google+](https://plus.google.com/107209047753760492207/ "Google+") 67 65 * [Facebook](https://www.facebook.com/krakenio "Kraken Image Optimizer") 66 * [Github](https://github.com/kraken-io "Kraken.io on Github") 68 67 69 68 == Installation == … … 103 102 You will need to switch the Media Library from the Thumbnail view to the List view. In the "Kraked Size" column, you will then see the "Optimize This Image" button for unoptimized images, or the results of the optimization where the image has already been optimized by our plugin. 104 103 105 106 104 == Changelog == 105 106 = 2.5.0 = 107 * Ability to disable optimization of main image, allowing faster uploads from Media Library. You can optimize the main image later from within your Media Library. 108 * Ability to restrict the maximum dimensions of image uploads (resizing), by width and/or height. 109 * When using resize feature, resized images are enhanced for sharper results using various advanced techniques. 110 * Ability to force JPEG quality to a discrete "quality" value, for greater savings if you know what you're doing. 111 * Ability to preserve certain EXIF metadata tags, including Date, Copyright, Orientation, Geotag and Profile. 112 * Ability to automatically orient images according to their Orientation EXIF metadata. 113 * Improvements and simplifications to interface elements and Kraken.io Settings page. 107 114 108 115 = 2.0.0 =
Note: See TracChangeset
for help on using the changeset viewer.