imgix-optimizer 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +2 -2
- data/dist/crds.html +57 -0
- data/dist/imgix-optimizer-0.0.6.min.js +1 -0
- data/dist/imgix-optimizer.js +1063 -191
- data/dist/index.html +209 -85
- data/package-lock.json +328 -332
- data/package.json +2 -1
- data/src/{imgix_bg_image.js → background_image.js} +55 -16
- data/src/{imgix_image.js → image.js} +80 -10
- data/src/main.js +0 -4
- data/src/optimizer.js +15 -7
- data/src/polyfills/object_assign.js +32 -0
- metadata +7 -6
- data/dist/imgix-optimizer-0.0.5.min.js +0 -1
- data/vendor/assets/javascripts/imgix-optimizer.js +0 -695
@@ -1 +0,0 @@
|
|
1
|
-
!function(){"use strict";var t=function(e,i){if(!(e instanceof i))throw new TypeError("Cannot call a class as a function")},e=function(){function l(e,i){for(var t=0;t<i.length;t++){var l=i[t];l.enumerable=l.enumerable||!1,l.configurable=!0,"value"in l&&(l.writable=!0),Object.defineProperty(e,l.key,l)}}return function(e,i,t){return i&&l(e.prototype,i),t&&l(e,t),e}}(),l=function(){function i(e){t(this,i),this.timeToFade=500,this.dpr=window.devicePixelRatio||1,this.el=$(e),"none"!=this.el.css("background-image")&&(this.initEl(),this.initOptimization(),this.initEventListeners())}return e(i,[{key:"initOptimization",value:function(){var e=this;$("<img>").on("load",function(){return e.renderTmpPlaceholderEl()}).attr("src",this.placeholderImgUrl)}},{key:"initEl",value:function(){this.setPlaceholderImgUrl(),this.setContainerTmpCss(),this.setElTmpCss()}},{key:"setPlaceholderImgUrl",value:function(){this.placeholderImgUrl=this.el.css("background-image").replace("url(","").replace(")","").replace(/\"/gi,"").replace(/\'/gi,"").split(", ")[0]}},{key:"setContainerTmpCss",value:function(){this.parentStyles={display:this.el.parent().css("display"),position:this.el.parent().css("position")},this.el.parent().css({display:"block",position:"relative"})}},{key:"setElTmpCss",value:function(){"absolute"!=this.el.css("position")&&this.el.css("position","relative")}},{key:"renderTmpPlaceholderEl",value:function(){this.initTmpPlaceholderEl(),this.setTmpPlaceholderElCss(),this.addTmpPlaceholderElToDom(),this.renderFullSizeImg()}},{key:"initTmpPlaceholderEl",value:function(){this.tmpPlaceholderEl=this.el.clone(),this.tmpPlaceholderEl.html("")}},{key:"setTmpPlaceholderElCss",value:function(){this.tmpPlaceholderEl.addClass("imgix-optimizing"),this.tmpPlaceholderEl.css({position:"absolute",top:this.el.position().top,left:this.el.position().left,width:this.el.outerWidth(),height:this.el.outerHeight(),backgroundColor:"transparent"})}},{key:"addTmpPlaceholderElToDom",value:function(){this.tmpPlaceholderEl.insertBefore(this.el)}},{key:"renderFullSizeImg",value:function(){this.removeElBgImg(),this.initTmpFullSizeEl(),this.setTmpFullSizeElImg(),this.addTmpFullSizeElToDom(),this.initTransition()}},{key:"removeElBgImg",value:function(){this.elBgColor=this.el.css("background-color"),this.el.css("background-color","transparent"),this.el.css("background-image","")}},{key:"initTmpFullSizeEl",value:function(){this.tmpFullSizeEl=this.tmpPlaceholderEl.clone()}},{key:"setFullSizeImgUrl",value:function(){var e=this.placeholderImgUrl.split("?"),i=e[e.length-1].split("&"),t={};for(var l in i.map(function(e){return t[e.split("=")[0]]=e.split("=")[1]}),this.el.outerWidth()>=this.el.outerHeight()?(t.w=this.el.outerWidth()*this.dpr,delete t.h):(t.h=this.el.outerHeight()*this.dpr,delete t.w),i=[],t)i.push(l+"="+t[l]);return this.fullSizeImgUrl=e[0]+"?"+i.join("&")}},{key:"setTmpFullSizeElImg",value:function(){this.setFullSizeImgUrl(),this.tmpFullSizeEl.css("background-image",'url("'+this.fullSizeImgUrl+'")')}},{key:"addTmpFullSizeElToDom",value:function(){this.tmpFullSizeEl.insertBefore(this.tmpPlaceholderEl)}},{key:"initTransition",value:function(){$("<img>").on("load",$.proxy(this.transitionImg,this)).attr("src",this.fullSizeImgUrl)}},{key:"transitionImg",value:function(){var e=this;this.fadeOutTmpPlaceholderEl(),setTimeout(function(){e.updateElImg(),e.replaceElTmpCss(),e.replaceContainerTmpCss(),e.removeTmpEls()},this.timeToFade)}},{key:"fadeOutTmpPlaceholderEl",value:function(){this.tmpPlaceholderEl.fadeTo(this.timeToFade,0)}},{key:"updateElImg",value:function(){this.setFullSizeImgUrl(),this.el.css("background-image","url('"+this.fullSizeImgUrl+"')")}},{key:"replaceElTmpCss",value:function(){this.el.css("background-color",this.elBgColor)}},{key:"replaceContainerTmpCss",value:function(){this.el.parent().css({display:this.parentStyles.display,position:this.parentStyles.position})}},{key:"removeTmpEls",value:function(){this.tmpPlaceholderEl.remove(),this.tmpFullSizeEl.remove(),this.tmpPlaceholderEl=void 0,this.tmpFullSizeEl=void 0}},{key:"initEventListeners",value:function(){var i=this;this.initResizeEnd(),$(window).on("resizeEnd",function(e){return i.updateElImg()})}},{key:"initResizeEnd",value:function(){$(window).resize(function(){this.resizeTo&&clearTimeout(this.resizeTo),this.resizeTo=setTimeout(function(){$(this).trigger("resizeEnd")},500)})}}]),i}(),s=function(){function i(e){t(this,i),this.timeToFade=500,this.placeholderImg=$(e),this.initPlaceholder(),this.initOptimization()}return e(i,[{key:"initOptimization",value:function(){$("<img>").on("load",$.proxy(this.renderFullSizeImg,this)).attr("src",this.placeholderImg.attr("src"))}},{key:"initPlaceholder",value:function(){this.setPlaceholderCss()}},{key:"setPlaceholderCss",value:function(){"absolute"!=this.placeholderImg.css("position")&&this.placeholderImg.css("position","relative")}},{key:"renderFullSizeImg",value:function(){this.initFullSizeImg(),this.setFullSizeImgTempCss(),this.setFullSizeImgSrc(),this.addFullSizeImgToDom(),this.initTransition()}},{key:"initFullSizeImg",value:function(){this.fullSizeImg=this.placeholderImg.clone()}},{key:"setFullSizeImgTempCss",value:function(){this.fullSizeImg.css({position:"absolute",top:this.placeholderImg.position().top,left:this.placeholderImg.position().left,width:this.placeholderImg.width(),height:this.placeholderImg.height()})}},{key:"setFullSizeImgSrc",value:function(){var e=this.placeholderImg.attr("src").replace(/(\?|\&)(w=)(\d+)/i,"$1$2"+this.placeholderImg.width()).replace(/(\?|\&)(h=)(\d+)/i,"$1$2"+this.placeholderImg.height());this.fullSizeImg.attr("ix-src",e),this.fullSizeImg.addClass("img-responsive imgix-optimizing"),this.fullSizeImg.removeAttr("data-optimize-img")}},{key:"addFullSizeImgToDom",value:function(){this.fullSizeImg.insertBefore(this.placeholderImg)}},{key:"initTransition",value:function(){var e=this;this.fullSizeImg.on("load",function(){return e.transitionImg()}),imgix.init()}},{key:"transitionImg",value:function(){var e=this;if(!this.placeholderImg)return!0;this.fadeOutPlaceholder(),setTimeout(function(){e.removeFullSizeImgProperties(),e.removeImg()},this.timeToFade)}},{key:"fadeOutPlaceholder",value:function(){this.placeholderImg.fadeTo(this.timeToFade,0)}},{key:"removeFullSizeImgProperties",value:function(){this.fullSizeImg.removeAttr("style"),this.fullSizeImg.removeClass("imgix-optimizing")}},{key:"removeImg",value:function(){this.placeholderImg&&(this.placeholderImg.remove(),this.placeholderImg=void 0)}}]),i}(),i=function(){function i(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};t(this,i),this.initOptions(e),this.optimizeImages(),this.optimizeBgImages()}return e(i,[{key:"initOptions",value:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.options=e;var i={parent:"body"};for(var t in i)i.hasOwnProperty(t)&&!this.options[t]&&(this.options[t]=i[t])}},{key:"optimizeImages",value:function(){$(this.options.parent+" img[data-optimize-img]").each(function(e,i){new s(i)})}},{key:"optimizeBgImages",value:function(){return $(this.options.parent+" [data-optimize-bg-img]").each(function(e,i){new l(i)}),!0}}]),i}();window.Imgix=window.Imgix||{},Imgix.ImgixBgImage=l,Imgix.ImgixImage=s,Imgix.Optimizer=i}();
|
@@ -1,695 +0,0 @@
|
|
1
|
-
(function () {
|
2
|
-
'use strict';
|
3
|
-
|
4
|
-
var classCallCheck = function (instance, Constructor) {
|
5
|
-
if (!(instance instanceof Constructor)) {
|
6
|
-
throw new TypeError("Cannot call a class as a function");
|
7
|
-
}
|
8
|
-
};
|
9
|
-
|
10
|
-
var createClass = function () {
|
11
|
-
function defineProperties(target, props) {
|
12
|
-
for (var i = 0; i < props.length; i++) {
|
13
|
-
var descriptor = props[i];
|
14
|
-
descriptor.enumerable = descriptor.enumerable || false;
|
15
|
-
descriptor.configurable = true;
|
16
|
-
if ("value" in descriptor) descriptor.writable = true;
|
17
|
-
Object.defineProperty(target, descriptor.key, descriptor);
|
18
|
-
}
|
19
|
-
}
|
20
|
-
|
21
|
-
return function (Constructor, protoProps, staticProps) {
|
22
|
-
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
23
|
-
if (staticProps) defineProperties(Constructor, staticProps);
|
24
|
-
return Constructor;
|
25
|
-
};
|
26
|
-
}();
|
27
|
-
|
28
|
-
var ImgixBgImage = function () {
|
29
|
-
function ImgixBgImage(el) {
|
30
|
-
classCallCheck(this, ImgixBgImage);
|
31
|
-
|
32
|
-
// Length of time to complete fade-in transition.
|
33
|
-
this.timeToFade = 500;
|
34
|
-
// Device pixel ratio assumes 1 if not set.
|
35
|
-
this.dpr = window['devicePixelRatio'] || 1;
|
36
|
-
// The primary element (i.e. the one with the background image).
|
37
|
-
this.el = $(el);
|
38
|
-
// Background image CSS property must be present.
|
39
|
-
if (this.el.css('background-image') == 'none') {
|
40
|
-
return;
|
41
|
-
}
|
42
|
-
// Prepare the element and its container for optimization.
|
43
|
-
this.initEl();
|
44
|
-
// Kick off the optimization process.
|
45
|
-
this.initOptimization();
|
46
|
-
// Listen for window resize events.
|
47
|
-
this.initEventListeners();
|
48
|
-
}
|
49
|
-
|
50
|
-
/**
|
51
|
-
* Load an image in memory (not within the DOM) with the same source as the
|
52
|
-
* placeholder image. Once that has completed, we know we're safe to begin
|
53
|
-
* processing.
|
54
|
-
*/
|
55
|
-
|
56
|
-
|
57
|
-
createClass(ImgixBgImage, [{
|
58
|
-
key: 'initOptimization',
|
59
|
-
value: function initOptimization() {
|
60
|
-
var _this = this;
|
61
|
-
|
62
|
-
$('<img>').on('load', function () {
|
63
|
-
return _this.renderTmpPlaceholderEl();
|
64
|
-
}).attr('src', this.placeholderImgUrl);
|
65
|
-
}
|
66
|
-
|
67
|
-
// ---------------------------------------- | Main Element
|
68
|
-
|
69
|
-
/**
|
70
|
-
* Prepare the main element and its container for optimization.
|
71
|
-
*/
|
72
|
-
|
73
|
-
}, {
|
74
|
-
key: 'initEl',
|
75
|
-
value: function initEl() {
|
76
|
-
this.setPlaceholderImgUrl();
|
77
|
-
this.setContainerTmpCss();
|
78
|
-
this.setElTmpCss();
|
79
|
-
}
|
80
|
-
|
81
|
-
/**
|
82
|
-
* Set reference to original image URL, which is expected to be a small
|
83
|
-
* placeholder.
|
84
|
-
*/
|
85
|
-
|
86
|
-
}, {
|
87
|
-
key: 'setPlaceholderImgUrl',
|
88
|
-
value: function setPlaceholderImgUrl() {
|
89
|
-
this.placeholderImgUrl = this.el.css('background-image').replace('url(', '').replace(')', '').replace(/\"/gi, "").replace(/\'/gi, "").split(', ')[0];
|
90
|
-
}
|
91
|
-
|
92
|
-
/**
|
93
|
-
* The parent of our jumbotron container should be relatively positioned
|
94
|
-
* (temporarily) so that we can absolutely position the temp image in the
|
95
|
-
* correct location.
|
96
|
-
*/
|
97
|
-
|
98
|
-
}, {
|
99
|
-
key: 'setContainerTmpCss',
|
100
|
-
value: function setContainerTmpCss() {
|
101
|
-
this.parentStyles = {
|
102
|
-
display: this.el.parent().css('display'),
|
103
|
-
position: this.el.parent().css('position')
|
104
|
-
};
|
105
|
-
this.el.parent().css({
|
106
|
-
display: 'block',
|
107
|
-
position: 'relative'
|
108
|
-
});
|
109
|
-
}
|
110
|
-
|
111
|
-
/**
|
112
|
-
* The main element must have a position set for it to be rendered on top of
|
113
|
-
* the temporary full-size image. We assume that if the element is not
|
114
|
-
* explicitly positioned absolutely, then it can safely be positioned
|
115
|
-
* relatively.
|
116
|
-
*/
|
117
|
-
|
118
|
-
}, {
|
119
|
-
key: 'setElTmpCss',
|
120
|
-
value: function setElTmpCss() {
|
121
|
-
if (this.el.css('position') != 'absolute') {
|
122
|
-
this.el.css('position', 'relative');
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
// ---------------------------------------- | Placeholder Image (Temp)
|
127
|
-
|
128
|
-
/**
|
129
|
-
* Render a clone of the element with the background image directly behind
|
130
|
-
* itself.
|
131
|
-
*/
|
132
|
-
|
133
|
-
}, {
|
134
|
-
key: 'renderTmpPlaceholderEl',
|
135
|
-
value: function renderTmpPlaceholderEl() {
|
136
|
-
this.initTmpPlaceholderEl();
|
137
|
-
this.setTmpPlaceholderElCss();
|
138
|
-
this.addTmpPlaceholderElToDom();
|
139
|
-
this.renderFullSizeImg();
|
140
|
-
}
|
141
|
-
|
142
|
-
/**
|
143
|
-
* Create a clone of the element with the background image. Remove content
|
144
|
-
* from the clone -- often elements with a background image contain content.
|
145
|
-
*/
|
146
|
-
|
147
|
-
}, {
|
148
|
-
key: 'initTmpPlaceholderEl',
|
149
|
-
value: function initTmpPlaceholderEl() {
|
150
|
-
this.tmpPlaceholderEl = this.el.clone();
|
151
|
-
this.tmpPlaceholderEl.html('');
|
152
|
-
}
|
153
|
-
|
154
|
-
/**
|
155
|
-
* Position the clone directly behind the main element
|
156
|
-
*/
|
157
|
-
|
158
|
-
}, {
|
159
|
-
key: 'setTmpPlaceholderElCss',
|
160
|
-
value: function setTmpPlaceholderElCss() {
|
161
|
-
this.tmpPlaceholderEl.addClass('imgix-optimizing');
|
162
|
-
this.tmpPlaceholderEl.css({
|
163
|
-
position: 'absolute',
|
164
|
-
top: this.el.position().top,
|
165
|
-
left: this.el.position().left,
|
166
|
-
width: this.el.outerWidth(),
|
167
|
-
height: this.el.outerHeight(),
|
168
|
-
backgroundColor: 'transparent'
|
169
|
-
});
|
170
|
-
}
|
171
|
-
|
172
|
-
/**
|
173
|
-
* Add temporary element to the DOM, directly before the main element
|
174
|
-
* containing the background image.
|
175
|
-
*/
|
176
|
-
|
177
|
-
}, {
|
178
|
-
key: 'addTmpPlaceholderElToDom',
|
179
|
-
value: function addTmpPlaceholderElToDom() {
|
180
|
-
this.tmpPlaceholderEl.insertBefore(this.el);
|
181
|
-
}
|
182
|
-
|
183
|
-
// ---------------------------------------- | Full-Size Image (Temp)
|
184
|
-
|
185
|
-
/**
|
186
|
-
* Create another clone, this time of the temporary placeholder image. This
|
187
|
-
* new element sits behind the other two and is responsible for loading the
|
188
|
-
* full-size image.
|
189
|
-
*/
|
190
|
-
|
191
|
-
}, {
|
192
|
-
key: 'renderFullSizeImg',
|
193
|
-
value: function renderFullSizeImg() {
|
194
|
-
this.removeElBgImg();
|
195
|
-
this.initTmpFullSizeEl();
|
196
|
-
this.setTmpFullSizeElImg();
|
197
|
-
this.addTmpFullSizeElToDom();
|
198
|
-
this.initTransition();
|
199
|
-
}
|
200
|
-
|
201
|
-
/**
|
202
|
-
* Remove the background color and image from the main element. The user won't
|
203
|
-
* notice this transition because the temp duplicate image is already set and
|
204
|
-
* is sitting behind the primary element.
|
205
|
-
*
|
206
|
-
* This also stores a reference to the original background color so we can put
|
207
|
-
* it back when the transition is complete.
|
208
|
-
*/
|
209
|
-
|
210
|
-
}, {
|
211
|
-
key: 'removeElBgImg',
|
212
|
-
value: function removeElBgImg() {
|
213
|
-
this.elBgColor = this.el.css('background-color');
|
214
|
-
this.el.css('background-color', 'transparent');
|
215
|
-
this.el.css('background-image', '');
|
216
|
-
}
|
217
|
-
|
218
|
-
/**
|
219
|
-
* The temporary full-size element is a clone of the temporary placeholder
|
220
|
-
* image element.
|
221
|
-
*/
|
222
|
-
|
223
|
-
}, {
|
224
|
-
key: 'initTmpFullSizeEl',
|
225
|
-
value: function initTmpFullSizeEl() {
|
226
|
-
this.tmpFullSizeEl = this.tmpPlaceholderEl.clone();
|
227
|
-
}
|
228
|
-
|
229
|
-
/**
|
230
|
-
* Sets a reference to the full-size image URL based on the current dimensions
|
231
|
-
* of the main element.
|
232
|
-
*/
|
233
|
-
|
234
|
-
}, {
|
235
|
-
key: 'setFullSizeImgUrl',
|
236
|
-
value: function setFullSizeImgUrl() {
|
237
|
-
// Work with the placeholdler image URL, which has been pulled from the
|
238
|
-
// background-image css property of the main elements.
|
239
|
-
var url = this.placeholderImgUrl.split('?');
|
240
|
-
// q is an array of querystring parameters as ["k=v", "k=v", ...].
|
241
|
-
var q = url[url.length - 1].split('&');
|
242
|
-
// Mapping q converts the array to an object of querystring parameters as
|
243
|
-
// { k: v, k: v, ... }.
|
244
|
-
var args = {};
|
245
|
-
q.map(function (x) {
|
246
|
-
return args[x.split('=')[0]] = x.split('=')[1];
|
247
|
-
});
|
248
|
-
// If the image's container is wider than it is tall, we only set width and
|
249
|
-
// unset height, and vice versa.
|
250
|
-
if (this.el.outerWidth() >= this.el.outerHeight()) {
|
251
|
-
args['w'] = this.el.outerWidth() * this.dpr;
|
252
|
-
delete args['h'];
|
253
|
-
} else {
|
254
|
-
args['h'] = this.el.outerHeight() * this.dpr;
|
255
|
-
delete args['w'];
|
256
|
-
}
|
257
|
-
// Redefine q and go the other direction -- take the args object and convert
|
258
|
-
// it back to an array of querystring parameters, as ["k=v", "k=v", ...].
|
259
|
-
q = [];
|
260
|
-
for (var k in args) {
|
261
|
-
q.push(k + '=' + args[k]);
|
262
|
-
}
|
263
|
-
// Store the result and return.
|
264
|
-
return this.fullSizeImgUrl = url[0] + '?' + q.join('&');
|
265
|
-
}
|
266
|
-
|
267
|
-
/**
|
268
|
-
* Change the URL of this temporary element's background image to be the
|
269
|
-
* full-size image.
|
270
|
-
*/
|
271
|
-
|
272
|
-
}, {
|
273
|
-
key: 'setTmpFullSizeElImg',
|
274
|
-
value: function setTmpFullSizeElImg() {
|
275
|
-
this.setFullSizeImgUrl();
|
276
|
-
this.tmpFullSizeEl.css('background-image', 'url("' + this.fullSizeImgUrl + '")');
|
277
|
-
}
|
278
|
-
|
279
|
-
/**
|
280
|
-
* Add the temporary full-size element direct before the temporary placeholder
|
281
|
-
* element.
|
282
|
-
*/
|
283
|
-
|
284
|
-
}, {
|
285
|
-
key: 'addTmpFullSizeElToDom',
|
286
|
-
value: function addTmpFullSizeElToDom() {
|
287
|
-
this.tmpFullSizeEl.insertBefore(this.tmpPlaceholderEl);
|
288
|
-
}
|
289
|
-
|
290
|
-
// ---------------------------------------- | Transition
|
291
|
-
|
292
|
-
/**
|
293
|
-
* Load full-size image in memory. When it has loaded we can confidentally
|
294
|
-
* fade out the placeholder, knowing the full-size image will be in its place.
|
295
|
-
*/
|
296
|
-
|
297
|
-
}, {
|
298
|
-
key: 'initTransition',
|
299
|
-
value: function initTransition() {
|
300
|
-
$('<img>').on('load', $.proxy(this.transitionImg, this)).attr('src', this.fullSizeImgUrl);
|
301
|
-
}
|
302
|
-
|
303
|
-
/**
|
304
|
-
* Fade out the temporary placeholder, set the background-image on the main
|
305
|
-
* element to the full-size URL, then remove the temporary elements behind the
|
306
|
-
* main element
|
307
|
-
*/
|
308
|
-
|
309
|
-
}, {
|
310
|
-
key: 'transitionImg',
|
311
|
-
value: function transitionImg() {
|
312
|
-
var _this2 = this;
|
313
|
-
|
314
|
-
this.fadeOutTmpPlaceholderEl();
|
315
|
-
setTimeout(function () {
|
316
|
-
_this2.updateElImg();
|
317
|
-
_this2.replaceElTmpCss();
|
318
|
-
_this2.replaceContainerTmpCss();
|
319
|
-
_this2.removeTmpEls();
|
320
|
-
}, this.timeToFade);
|
321
|
-
}
|
322
|
-
|
323
|
-
/**
|
324
|
-
* Fade out the placeholder element. This was the temporary clone of the main
|
325
|
-
* element that has a placeholder background image.
|
326
|
-
*
|
327
|
-
* Rememeber the main element's background image was unset and its color set
|
328
|
-
* to transparent. That is why fading out this temporary image will work
|
329
|
-
* properly.
|
330
|
-
*/
|
331
|
-
|
332
|
-
}, {
|
333
|
-
key: 'fadeOutTmpPlaceholderEl',
|
334
|
-
value: function fadeOutTmpPlaceholderEl() {
|
335
|
-
this.tmpPlaceholderEl.fadeTo(this.timeToFade, 0);
|
336
|
-
}
|
337
|
-
|
338
|
-
/**
|
339
|
-
* Reset the image URL (this helps if the size of the element has changed),
|
340
|
-
* then set the background image to the new source.
|
341
|
-
*/
|
342
|
-
|
343
|
-
}, {
|
344
|
-
key: 'updateElImg',
|
345
|
-
value: function updateElImg() {
|
346
|
-
this.setFullSizeImgUrl();
|
347
|
-
this.el.css('background-image', 'url(\'' + this.fullSizeImgUrl + '\')');
|
348
|
-
}
|
349
|
-
|
350
|
-
/**
|
351
|
-
* Set the background color back to what it was before the transition.
|
352
|
-
*/
|
353
|
-
|
354
|
-
}, {
|
355
|
-
key: 'replaceElTmpCss',
|
356
|
-
value: function replaceElTmpCss() {
|
357
|
-
this.el.css('background-color', this.elBgColor);
|
358
|
-
}
|
359
|
-
|
360
|
-
/**
|
361
|
-
* Reset the container's adjusted CSS properties.
|
362
|
-
*/
|
363
|
-
|
364
|
-
}, {
|
365
|
-
key: 'replaceContainerTmpCss',
|
366
|
-
value: function replaceContainerTmpCss() {
|
367
|
-
this.el.parent().css({
|
368
|
-
display: this.parentStyles.display,
|
369
|
-
position: this.parentStyles.position
|
370
|
-
});
|
371
|
-
}
|
372
|
-
|
373
|
-
/**
|
374
|
-
* Remove both temporary elements from the DOM.
|
375
|
-
*/
|
376
|
-
|
377
|
-
}, {
|
378
|
-
key: 'removeTmpEls',
|
379
|
-
value: function removeTmpEls() {
|
380
|
-
this.tmpPlaceholderEl.remove();
|
381
|
-
this.tmpFullSizeEl.remove();
|
382
|
-
this.tmpPlaceholderEl = undefined;
|
383
|
-
this.tmpFullSizeEl = undefined;
|
384
|
-
}
|
385
|
-
|
386
|
-
// ---------------------------------------- | Event Listeners
|
387
|
-
|
388
|
-
/**
|
389
|
-
* Listener for window resize events and update the image when the event ends.
|
390
|
-
*/
|
391
|
-
|
392
|
-
}, {
|
393
|
-
key: 'initEventListeners',
|
394
|
-
value: function initEventListeners() {
|
395
|
-
var _this3 = this;
|
396
|
-
|
397
|
-
this.initResizeEnd();
|
398
|
-
$(window).on('resizeEnd', function (event) {
|
399
|
-
return _this3.updateElImg();
|
400
|
-
});
|
401
|
-
}
|
402
|
-
|
403
|
-
/**
|
404
|
-
* Trigger "resizeEnd" event on the window object after resizing has ceased
|
405
|
-
* for at least 0.5 seconds.
|
406
|
-
*/
|
407
|
-
|
408
|
-
}, {
|
409
|
-
key: 'initResizeEnd',
|
410
|
-
value: function initResizeEnd() {
|
411
|
-
$(window).resize(function () {
|
412
|
-
if (this.resizeTo) {
|
413
|
-
clearTimeout(this.resizeTo);
|
414
|
-
}
|
415
|
-
this.resizeTo = setTimeout(function () {
|
416
|
-
$(this).trigger('resizeEnd');
|
417
|
-
}, 500);
|
418
|
-
});
|
419
|
-
}
|
420
|
-
}]);
|
421
|
-
return ImgixBgImage;
|
422
|
-
}();
|
423
|
-
|
424
|
-
var ImgixImage = function () {
|
425
|
-
function ImgixImage(img) {
|
426
|
-
classCallCheck(this, ImgixImage);
|
427
|
-
|
428
|
-
// Length of crossfade transition.
|
429
|
-
this.timeToFade = 500;
|
430
|
-
// The main image (pixelated placeholder).
|
431
|
-
this.placeholderImg = $(img);
|
432
|
-
// Configure the main placeholder image.
|
433
|
-
this.initPlaceholder();
|
434
|
-
// Kick off the optimization process.
|
435
|
-
this.initOptimization();
|
436
|
-
}
|
437
|
-
|
438
|
-
/**
|
439
|
-
* Load an image in memory (not within the DOM) with the same source as the
|
440
|
-
* placeholder image. Once that has completed, we know we're safe to begin
|
441
|
-
* processing.
|
442
|
-
*/
|
443
|
-
|
444
|
-
|
445
|
-
createClass(ImgixImage, [{
|
446
|
-
key: 'initOptimization',
|
447
|
-
value: function initOptimization() {
|
448
|
-
$('<img>').on('load', $.proxy(this.renderFullSizeImg, this)).attr('src', this.placeholderImg.attr('src'));
|
449
|
-
}
|
450
|
-
|
451
|
-
// ---------------------------------------- | Placeholder Image
|
452
|
-
|
453
|
-
/**
|
454
|
-
* Make necessary CSS adjustments to main placeholder image.
|
455
|
-
*/
|
456
|
-
|
457
|
-
}, {
|
458
|
-
key: 'initPlaceholder',
|
459
|
-
value: function initPlaceholder() {
|
460
|
-
this.setPlaceholderCss();
|
461
|
-
}
|
462
|
-
|
463
|
-
/**
|
464
|
-
* The main image must have a position set for it to remain in front of the
|
465
|
-
* full-size image. We assume that if the element is not explicitly positioned
|
466
|
-
* absolutely, then it can safely be positioned relatively.
|
467
|
-
*/
|
468
|
-
|
469
|
-
}, {
|
470
|
-
key: 'setPlaceholderCss',
|
471
|
-
value: function setPlaceholderCss() {
|
472
|
-
if (this.placeholderImg.css('position') != 'absolute') {
|
473
|
-
this.placeholderImg.css('position', 'relative');
|
474
|
-
}
|
475
|
-
}
|
476
|
-
|
477
|
-
// ---------------------------------------- | Full-Size Image
|
478
|
-
|
479
|
-
/**
|
480
|
-
* Render the full-size image behind the placeholder image.
|
481
|
-
*/
|
482
|
-
|
483
|
-
}, {
|
484
|
-
key: 'renderFullSizeImg',
|
485
|
-
value: function renderFullSizeImg() {
|
486
|
-
this.initFullSizeImg();
|
487
|
-
this.setFullSizeImgTempCss();
|
488
|
-
this.setFullSizeImgSrc();
|
489
|
-
this.addFullSizeImgToDom();
|
490
|
-
this.initTransition();
|
491
|
-
}
|
492
|
-
|
493
|
-
/**
|
494
|
-
* The full-size image is a clone of the placeholder image. This enables us to
|
495
|
-
* easily replace it without losing any necessary styles or attributes.
|
496
|
-
*/
|
497
|
-
|
498
|
-
}, {
|
499
|
-
key: 'initFullSizeImg',
|
500
|
-
value: function initFullSizeImg() {
|
501
|
-
this.fullSizeImg = this.placeholderImg.clone();
|
502
|
-
}
|
503
|
-
|
504
|
-
/**
|
505
|
-
* Give the full-size image a temporary set of CSS rules so that it can sit
|
506
|
-
* directly behind the placeholder image while loading.
|
507
|
-
*/
|
508
|
-
|
509
|
-
}, {
|
510
|
-
key: 'setFullSizeImgTempCss',
|
511
|
-
value: function setFullSizeImgTempCss() {
|
512
|
-
this.fullSizeImg.css({
|
513
|
-
position: 'absolute',
|
514
|
-
top: this.placeholderImg.position().top,
|
515
|
-
left: this.placeholderImg.position().left,
|
516
|
-
width: this.placeholderImg.width(),
|
517
|
-
height: this.placeholderImg.height()
|
518
|
-
});
|
519
|
-
}
|
520
|
-
|
521
|
-
/**
|
522
|
-
* Prep the full-size image with the attributes necessary to become its full
|
523
|
-
* size. Right now it is still just a replica of the placeholder, sitting
|
524
|
-
* right behind the placeholder.
|
525
|
-
*
|
526
|
-
* We set the src directly even though we're using imgix.js because older
|
527
|
-
* browsers don't support the srcset attribute which is what imgix.js relies
|
528
|
-
* upon.
|
529
|
-
*/
|
530
|
-
|
531
|
-
}, {
|
532
|
-
key: 'setFullSizeImgSrc',
|
533
|
-
value: function setFullSizeImgSrc() {
|
534
|
-
var newSrc = this.placeholderImg.attr('src').replace(/(\?|\&)(w=)(\d+)/i, '$1$2' + this.placeholderImg.width()).replace(/(\?|\&)(h=)(\d+)/i, '$1$2' + this.placeholderImg.height());
|
535
|
-
this.fullSizeImg.attr('ix-src', newSrc);
|
536
|
-
// TODO: Make this a configurable option or document it as a more semantic temporary class
|
537
|
-
this.fullSizeImg.addClass('img-responsive imgix-optimizing');
|
538
|
-
// TODO: This should respect the option from the Optimizer class for the select
|
539
|
-
this.fullSizeImg.removeAttr('data-optimize-img');
|
540
|
-
}
|
541
|
-
|
542
|
-
/**
|
543
|
-
* Render the full-size image in the DOM.
|
544
|
-
*/
|
545
|
-
|
546
|
-
}, {
|
547
|
-
key: 'addFullSizeImgToDom',
|
548
|
-
value: function addFullSizeImgToDom() {
|
549
|
-
this.fullSizeImg.insertBefore(this.placeholderImg);
|
550
|
-
}
|
551
|
-
|
552
|
-
// ---------------------------------------- | Image Transition
|
553
|
-
|
554
|
-
/**
|
555
|
-
* Once the full-size image is loaded, begin the transition. This is the
|
556
|
-
* critical piece of this process. Imgix.js uses the ix-src attribute to build
|
557
|
-
* out the srcset attribute. Then, based on the sizes attribute, the browser
|
558
|
-
* determines which source to render. Therefore we can't preload in memory
|
559
|
-
* because we need imgix to do its thing directly in the DOM.
|
560
|
-
*/
|
561
|
-
|
562
|
-
}, {
|
563
|
-
key: 'initTransition',
|
564
|
-
value: function initTransition() {
|
565
|
-
var _this = this;
|
566
|
-
|
567
|
-
this.fullSizeImg.on('load', function () {
|
568
|
-
return _this.transitionImg();
|
569
|
-
});
|
570
|
-
imgix.init();
|
571
|
-
}
|
572
|
-
|
573
|
-
/**
|
574
|
-
* Fade out the placeholder image, effectively showing the image behind it.
|
575
|
-
*
|
576
|
-
* Once the fade out transition has completed, remove any temporary properties
|
577
|
-
* from the full-size image (so it gets back to being a clone of the
|
578
|
-
* placeholder, with the full-size src).
|
579
|
-
*
|
580
|
-
* Finally, remove the placeholder image from the DOM since we don't need it
|
581
|
-
* any more.
|
582
|
-
*/
|
583
|
-
|
584
|
-
}, {
|
585
|
-
key: 'transitionImg',
|
586
|
-
value: function transitionImg() {
|
587
|
-
var _this2 = this;
|
588
|
-
|
589
|
-
if (!this.placeholderImg) return true;
|
590
|
-
this.fadeOutPlaceholder();
|
591
|
-
setTimeout(function () {
|
592
|
-
_this2.removeFullSizeImgProperties();
|
593
|
-
_this2.removeImg();
|
594
|
-
}, this.timeToFade);
|
595
|
-
}
|
596
|
-
|
597
|
-
/**
|
598
|
-
* Fade out the placeholder image.
|
599
|
-
*/
|
600
|
-
|
601
|
-
}, {
|
602
|
-
key: 'fadeOutPlaceholder',
|
603
|
-
value: function fadeOutPlaceholder() {
|
604
|
-
this.placeholderImg.fadeTo(this.timeToFade, 0);
|
605
|
-
}
|
606
|
-
|
607
|
-
/**
|
608
|
-
* Remove temporary styles and class from the full-size image, which
|
609
|
-
* effectively means it has replaced the placeholder image.
|
610
|
-
*/
|
611
|
-
|
612
|
-
}, {
|
613
|
-
key: 'removeFullSizeImgProperties',
|
614
|
-
value: function removeFullSizeImgProperties() {
|
615
|
-
this.fullSizeImg.removeAttr('style');
|
616
|
-
// TODO: Update this with how the class is handled above.
|
617
|
-
this.fullSizeImg.removeClass('imgix-optimizing');
|
618
|
-
}
|
619
|
-
|
620
|
-
/**
|
621
|
-
* Remove the placeholder image from the DOM since we no longer need it.
|
622
|
-
*/
|
623
|
-
|
624
|
-
}, {
|
625
|
-
key: 'removeImg',
|
626
|
-
value: function removeImg() {
|
627
|
-
if (!this.placeholderImg) {
|
628
|
-
return;
|
629
|
-
}
|
630
|
-
this.placeholderImg.remove();
|
631
|
-
this.placeholderImg = undefined;
|
632
|
-
}
|
633
|
-
}]);
|
634
|
-
return ImgixImage;
|
635
|
-
}();
|
636
|
-
|
637
|
-
var Optimizer = function () {
|
638
|
-
function Optimizer() {
|
639
|
-
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
640
|
-
classCallCheck(this, Optimizer);
|
641
|
-
|
642
|
-
this.initOptions(options);
|
643
|
-
this.optimizeImages();
|
644
|
-
this.optimizeBgImages();
|
645
|
-
}
|
646
|
-
|
647
|
-
// ---------------------------------------- | Options
|
648
|
-
|
649
|
-
createClass(Optimizer, [{
|
650
|
-
key: 'initOptions',
|
651
|
-
value: function initOptions() {
|
652
|
-
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
653
|
-
|
654
|
-
this.options = options;
|
655
|
-
var defaultOptions = {
|
656
|
-
parent: 'body'
|
657
|
-
};
|
658
|
-
for (var key in defaultOptions) {
|
659
|
-
if (defaultOptions.hasOwnProperty(key) && !this.options[key]) {
|
660
|
-
this.options[key] = defaultOptions[key];
|
661
|
-
}
|
662
|
-
}
|
663
|
-
}
|
664
|
-
|
665
|
-
// ---------------------------------------- | Inline Images
|
666
|
-
|
667
|
-
}, {
|
668
|
-
key: 'optimizeImages',
|
669
|
-
value: function optimizeImages() {
|
670
|
-
$(this.options.parent + ' img[data-optimize-img]').each(function (idx, img) {
|
671
|
-
new ImgixImage(img);
|
672
|
-
});
|
673
|
-
}
|
674
|
-
|
675
|
-
// ---------------------------------------- | Background Images
|
676
|
-
|
677
|
-
}, {
|
678
|
-
key: 'optimizeBgImages',
|
679
|
-
value: function optimizeBgImages() {
|
680
|
-
$(this.options.parent + ' [data-optimize-bg-img]').each(function (idx, img) {
|
681
|
-
new ImgixBgImage(img);
|
682
|
-
});
|
683
|
-
return true;
|
684
|
-
}
|
685
|
-
}]);
|
686
|
-
return Optimizer;
|
687
|
-
}();
|
688
|
-
|
689
|
-
window['Imgix'] = window['Imgix'] || {};
|
690
|
-
|
691
|
-
Imgix.ImgixBgImage = ImgixBgImage;
|
692
|
-
Imgix.ImgixImage = ImgixImage;
|
693
|
-
Imgix.Optimizer = Optimizer;
|
694
|
-
|
695
|
-
}());
|