imgix-optimizer 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6630b32252b9019d7cdcb4b0652f7d2dcf2dd09176f624cbbdfa64f041b3dcbb
4
- data.tar.gz: 9715b46c1e2520797153afdbbb1a679646417a8ea1876504cce8959009011455
3
+ metadata.gz: 003e3c834f09df27d2057b68bc0c63dd599503d513b8e18944596ca7d700e033
4
+ data.tar.gz: 56d0c88dc28b460a13c362bdcc773f125f1aad805ca9e2301e90adc6560377dc
5
5
  SHA512:
6
- metadata.gz: 6c8152c7c744eb1e66a8a136330044e6a96ea75842622421904aa4709d9a5bdfc4e66c397e3a80e7f1cefb96b1ac052664d81e7fba875345e937c7e82b5cc624
7
- data.tar.gz: 94fcbdfb69bc9c3fd5934bcd9a969982d9e3e0d7b6d2c3d43363c8d95c2d779b7b8b641a9793b71fc9d92f4064924f33422026d8462a6ad34bd094899af50b93
6
+ metadata.gz: df9b55aaad2f6c893ce732d78d2bead5370c713469ea61d494e29797a819174783318e1b473c60f28b5a419ee8fcaf01791171b9b020ea51c87b34a1f2fcdcdf
7
+ data.tar.gz: 4c920564345f22588833ad4eaf2c75714397b59e5c19f004f5567e726fced26d8a4fe6413d87163a0f2583bd8e7d6db86f022d2ee31362bfb2515beae7d57c83
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- imgix-optimizer (0.0.6)
4
+ imgix-optimizer (0.0.7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -0,0 +1 @@
1
+ !function(){"use strict";var i=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},t=function(){function n(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(t,e,i){return e&&n(t.prototype,e),i&&n(t,i),t}}(),n=function(){function e(t){i(this,e),this.timeToFade=500,this.processingAttr="data-imgix-img-processed",this.placeholderImg=$(t),0<this.placeholderImg.height()?this.init():this.placeholderImg.on("load",$.proxy(this.init,this))}return t(e,[{key:"init",value:function(){this.initPlaceholder(),this.initOptimization()}},{key:"initOptimization",value:function(){$("<img>").on("load",$.proxy(this.listenForIntersection,this)).attr("src",this.placeholderImg.attr("src"))}},{key:"listenForIntersection",value:function(){new IntersectionObserver($.proxy(this.onIntersection,this)).observe(this.placeholderImg[0])}},{key:"onIntersection",value:function(t,e){var i=$(t[0].target);t[0].isIntersecting&&!$(i).attr(this.processingAttr)&&(i.attr(this.processingAttr,!0),this.renderFullSizeImg())}},{key:"initPlaceholder",value:function(){this.wrapPlaceholder(),this.setPlaceholderCss()}},{key:"wrapPlaceholder",value:function(){this.tmpWrapper=$("<div>").css({position:"relative",height:this.placeholderImg[0].getBoundingClientRect().height,width:this.placeholderImg[0].getBoundingClientRect().width,margin:this.placeholderImg.css("margin")}),this.placeholderImg.wrap(this.tmpWrapper)}},{key:"setPlaceholderCss",value:function(){"absolute"!=this.placeholderImg.css("position")&&this.placeholderImg.css("position","relative"),this.placeholderImg.css({margin:0})}},{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:"100%",height:"100%"})}},{key:"getPlaceholderImgRect",value:function(){return{width:this.placeholderImg[0].getBoundingClientRect().width,height:this.placeholderImg[0].getBoundingClientRect().height}}},{key:"setFullSizeImgSrc",value:function(){var t=this.placeholderImg.attr("src").replace(/(\?|\&)(w=)(\d+)/i,"$1$2"+this.getPlaceholderImgRect().width).replace(/(\?|\&)(h=)(\d+)/i,"$1$2"+this.getPlaceholderImgRect().height);t.search(/(\?|\&)(h=)(\d+)/i)<0&&(t=t+"&h="+this.getPlaceholderImgRect().height+"&fit=crop"),this.fullSizeImg.attr("ix-src",t),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 t=this;this.fullSizeImg.on("load",function(){return t.transitionImg()}),imgix.init()}},{key:"transitionImg",value:function(){var t=this;if(!this.placeholderImg)return!0;this.fadeOutPlaceholder(),setTimeout(function(){t.removeFullSizeImgProperties(),t.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)}},{key:"unwrapImg",value:function(){this.fullSizeImg.css("margin",this.tmpWrapper.css("margin")).unwrap()}}]),e}(),o=function(){function e(t){i(this,e),this.timeToFade=500,this.processingAttr="data-imgix-bg-processed",this.dpr=window.devicePixelRatio||1,this.largestImageWidth=0,this.el=$(t),"none"!=this.el.css("background-image")&&(this.initEl(),this.initOptimization(),this.initEventListeners())}return t(e,[{key:"initOptimization",value:function(){$("<img>").on("load",$.proxy(this.listenForIntersection,this)).attr("src",this.placeholderImgUrl)}},{key:"listenForIntersection",value:function(){new IntersectionObserver($.proxy(this.onIntersection,this)).observe(this.el[0])}},{key:"onIntersection",value:function(t,e){var i=$(t[0].target);t[0].isIntersecting&&!$(i).attr(this.processingAttr)&&($(i).attr(this.processingAttr,!0),this.renderTmpPlaceholderEl())}},{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(){if(!(this.fullSizeImgUrl&&this.el.outerWidth()*this.dpr<=this.largestImageWidth)){this.largestImageWidth=this.el.outerWidth()*this.dpr;var t=this.placeholderImgUrl.split("?"),e=t[t.length-1].split("&"),i={};for(var n in e.map(function(t){return i[t.split("=")[0]]=t.split("=")[1]}),this.el.outerWidth()>=this.el.outerHeight()?(i.w=this.largestImageWidth,delete i.h):(i.h=this.el.outerHeight()*this.dpr,delete i.w),e=[],i)e.push(n+"="+i[n]);return this.fullSizeImgUrl=t[0]+"?"+e.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 t=this;this.fadeOutTmpPlaceholderEl(),setTimeout(function(){t.updateElImg(),t.replaceElTmpCss(),t.replaceContainerTmpCss(),t.removeTmpEls()},this.timeToFade)}},{key:"fadeOutTmpPlaceholderEl",value:function(){this.tmpPlaceholderEl.fadeTo(this.timeToFade,0)}},{key:"updateElImg",value:function(){var e=this;this.setFullSizeImgUrl(),$("<img>").on("load",function(t){return e.el.css("background-image","url('"+e.fullSizeImgUrl+"')")}).attr("src",this.placeholderImgUrl)}},{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 e=this;this.initResizeEnd(),$(window).on("resizeEnd",function(t){return e.updateElImg()})}},{key:"initResizeEnd",value:function(){$(window).resize(function(){this.resizeTo&&clearTimeout(this.resizeTo),this.resizeTo=setTimeout(function(){$(this).trigger("resizeEnd")},500)})}}]),e}();!function(d,f){function a(t){this.time=t.time,this.target=t.target,this.rootBounds=t.rootBounds,this.boundingClientRect=t.boundingClientRect,this.intersectionRect=t.intersectionRect||{top:0,bottom:0,left:0,right:0,width:0,height:0},this.isIntersecting=!!t.intersectionRect;var e=this.boundingClientRect,i=e.width*e.height,n=this.intersectionRect,o=n.width*n.height;this.intersectionRatio=i?Number((o/i).toFixed(4)):this.isIntersecting?1:0}function t(t,e){var i,n,o,r=e||{};if("function"!=typeof t)throw new Error("callback must be a function");if(r.root&&1!=r.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=(i=this._checkForIntersections.bind(this),n=this.THROTTLE_TIMEOUT,o=null,function(){o||(o=setTimeout(function(){i(),o=null},n))}),this._callback=t,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(r.rootMargin),this.thresholds=this._initThresholds(r.threshold),this.root=r.root||null,this.rootMargin=this._rootMarginValues.map(function(t){return t.value+t.unit}).join(" ")}function e(t,e,i,n){"function"==typeof t.addEventListener?t.addEventListener(e,i,n||!1):"function"==typeof t.attachEvent&&t.attachEvent("on"+e,i)}function i(t,e,i,n){"function"==typeof t.removeEventListener?t.removeEventListener(e,i,n||!1):"function"==typeof t.detatchEvent&&t.detatchEvent("on"+e,i)}function v(t){var e;try{e=t.getBoundingClientRect()}catch(t){}return e?(e.width&&e.height||(e={top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:e.right-e.left,height:e.bottom-e.top}),e):{top:0,bottom:0,left:0,right:0,width:0,height:0}}function n(t,e){for(var i=e;i;){if(i==t)return!0;i=I(i)}return!1}function I(t){var e=t.parentNode;return e&&11==e.nodeType&&e.host?e.host:e}"IntersectionObserver"in d&&"IntersectionObserverEntry"in d&&"intersectionRatio"in d.IntersectionObserverEntry.prototype?"isIntersecting"in d.IntersectionObserverEntry.prototype||Object.defineProperty(d.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return 0<this.intersectionRatio}}):(t.prototype.THROTTLE_TIMEOUT=100,t.prototype.POLL_INTERVAL=null,t.prototype.USE_MUTATION_OBSERVER=!0,t.prototype.observe=function(e){if(!this._observationTargets.some(function(t){return t.element==e})){if(!e||1!=e.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:e,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},t.prototype.unobserve=function(e){this._observationTargets=this._observationTargets.filter(function(t){return t.element!=e}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},t.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},t.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},t.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter(function(t,e,i){if("number"!=typeof t||isNaN(t)||t<0||1<t)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==i[e-1]})},t.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map(function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}});return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},t.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(e(d,"resize",this._checkForIntersections,!0),e(f,"scroll",this._checkForIntersections,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in d&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(f,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},t.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,i(d,"resize",this._checkForIntersections,!0),i(f,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},t.prototype._checkForIntersections=function(){var l=this._rootIsInDom(),h=l?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach(function(t){var e=t.element,i=v(e),n=this._rootContainsTarget(e),o=t.entry,r=l&&n&&this._computeTargetAndRootIntersection(e,h),s=t.entry=new a({time:d.performance&&performance.now&&performance.now(),target:e,boundingClientRect:i,rootBounds:h,intersectionRect:r});o?l&&n?this._hasCrossedThreshold(o,s)&&this._queuedEntries.push(s):o&&o.isIntersecting&&this._queuedEntries.push(s):this._queuedEntries.push(s)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},t.prototype._computeTargetAndRootIntersection=function(t,e){if("none"!=d.getComputedStyle(t).display){for(var i,n,o,r,s,l,h,a,c=v(t),u=I(t),p=!1;!p;){var m=null,g=1==u.nodeType?d.getComputedStyle(u):{};if("none"==g.display)return;if(u==this.root||u==f?(p=!0,m=e):u!=f.body&&u!=f.documentElement&&"visible"!=g.overflow&&(m=v(u)),m&&(i=m,n=c,void 0,o=Math.max(i.top,n.top),r=Math.min(i.bottom,n.bottom),s=Math.max(i.left,n.left),l=Math.min(i.right,n.right),a=r-o,!(c=0<=(h=l-s)&&0<=a&&{top:o,bottom:r,left:s,right:l,width:h,height:a})))break;u=I(u)}return c}},t.prototype._getRootRect=function(){var t;if(this.root)t=v(this.root);else{var e=f.documentElement,i=f.body;t={top:0,left:0,right:e.clientWidth||i.clientWidth,width:e.clientWidth||i.clientWidth,bottom:e.clientHeight||i.clientHeight,height:e.clientHeight||i.clientHeight}}return this._expandRectByRootMargin(t)},t.prototype._expandRectByRootMargin=function(i){var t=this._rootMarginValues.map(function(t,e){return"px"==t.unit?t.value:t.value*(e%2?i.width:i.height)/100}),e={top:i.top-t[0],right:i.right+t[1],bottom:i.bottom+t[2],left:i.left-t[3]};return e.width=e.right-e.left,e.height=e.bottom-e.top,e},t.prototype._hasCrossedThreshold=function(t,e){var i=t&&t.isIntersecting?t.intersectionRatio||0:-1,n=e.isIntersecting?e.intersectionRatio||0:-1;if(i!==n)for(var o=0;o<this.thresholds.length;o++){var r=this.thresholds[o];if(r==i||r==n||r<i!=r<n)return!0}},t.prototype._rootIsInDom=function(){return!this.root||n(f,this.root)},t.prototype._rootContainsTarget=function(t){return n(this.root||f,t)},t.prototype._registerInstance=function(){},t.prototype._unregisterInstance=function(){},d.IntersectionObserver=t,d.IntersectionObserverEntry=a)}(window,document),"function"!=typeof Object.assign&&Object.defineProperty(Object,"assign",{value:function(t,e){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var i=Object(t),n=1;n<arguments.length;n++){var o=arguments[n];if(null!=o)for(var r in o)Object.prototype.hasOwnProperty.call(o,r)&&(i[r]=o[r])}return i},writable:!0,configurable:!0});var e=function(){function e(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};i(this,e),this.initDependencies(),this.initOptions(t),this.optimizeImages(),this.optimizeBgImages()}return t(e,[{key:"initDependencies",value:function(){}},{key:"initOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.options=t;var e={parent:"body"};for(var i in e)e.hasOwnProperty(i)&&!this.options[i]&&(this.options[i]=e[i])}},{key:"optimizeImages",value:function(){$(this.options.parent+" img[data-optimize-img]").each(function(t,e){new n(e)})}},{key:"optimizeBgImages",value:function(){return $(this.options.parent+" [data-optimize-bg-img]").each(function(t,e){new o(e)}),!0}}]),e}();window.Imgix=window.Imgix||{},Imgix.Optimizer=e}();
@@ -35,25 +35,40 @@
35
35
  this.processingAttr = 'data-imgix-img-processed';
36
36
  // The main image (pixelated placeholder).
37
37
  this.placeholderImg = $(img);
38
- // Configure the main placeholder image.
39
- this.initPlaceholder();
40
- // Kick off the optimization process.
41
- this.initOptimization();
38
+ // Wait for the image to load prior to kicking off the optimization process.
39
+ if (this.placeholderImg.height() > 0) {
40
+ this.init();
41
+ } else {
42
+ this.placeholderImg.on('load', $.proxy(this.init, this));
43
+ }
42
44
  }
43
45
 
44
46
  /**
45
- * Load an image in memory (not within the DOM) with the same source as the
46
- * placeholder image. Once that has completed, we know we're safe to begin
47
- * listening for the image to intersect the viewport.
47
+ * Configure the main placeholder image and kick off the optimization process.
48
48
  */
49
49
 
50
50
 
51
51
  createClass(Image, [{
52
+ key: 'init',
53
+ value: function init() {
54
+ this.initPlaceholder();
55
+ this.initOptimization();
56
+ }
57
+
58
+ /**
59
+ * Load an image in memory (not within the DOM) with the same source as the
60
+ * placeholder image. Once that has completed, we know we're safe to begin
61
+ * listening for the image to intersect the viewport.
62
+ */
63
+
64
+ }, {
52
65
  key: 'initOptimization',
53
66
  value: function initOptimization() {
54
67
  $('<img>').on('load', $.proxy(this.listenForIntersection, this)).attr('src', this.placeholderImg.attr('src'));
55
68
  }
56
69
 
70
+ // ---------------------------------------- | Lazy Loading Control
71
+
57
72
  /**
58
73
  * When the placeholder image intersects the viewport, begin processing.
59
74
  * (IntersectionObserver and Object.assign() are not supported by IE, but the
@@ -91,14 +106,34 @@
91
106
  }, {
92
107
  key: 'initPlaceholder',
93
108
  value: function initPlaceholder() {
109
+ this.wrapPlaceholder();
94
110
  this.setPlaceholderCss();
95
- this.setPlaceholderParentTmpCss();
111
+ }
112
+
113
+ /**
114
+ * Wrap the placeholder image in a <div>. This enables better control over the
115
+ * wrapping element and provides a more fluid transition process.
116
+ */
117
+
118
+ }, {
119
+ key: 'wrapPlaceholder',
120
+ value: function wrapPlaceholder() {
121
+ this.tmpWrapper = $('<div>').css({
122
+ position: 'relative',
123
+ height: this.placeholderImg[0].getBoundingClientRect().height,
124
+ width: this.placeholderImg[0].getBoundingClientRect().width,
125
+ margin: this.placeholderImg.css('margin')
126
+ });
127
+ this.placeholderImg.wrap(this.tmpWrapper);
96
128
  }
97
129
 
98
130
  /**
99
131
  * The main image must have a position set for it to remain in front of the
100
132
  * full-size image. We assume that if the element is not explicitly positioned
101
133
  * absolutely, then it can safely be positioned relatively.
134
+ *
135
+ * And temporarily remove any margin from the image, as the box model gets
136
+ * delegated to the temporary wrapper during the transition period.
102
137
  */
103
138
 
104
139
  }, {
@@ -107,24 +142,7 @@
107
142
  if (this.placeholderImg.css('position') != 'absolute') {
108
143
  this.placeholderImg.css('position', 'relative');
109
144
  }
110
- }
111
-
112
- /**
113
- * The parent of the image container should be relatively positioned
114
- * (temporarily) so temp image can be absolutely positioned.
115
- */
116
-
117
- }, {
118
- key: 'setPlaceholderParentTmpCss',
119
- value: function setPlaceholderParentTmpCss() {
120
- this.parentStyles = {
121
- display: this.placeholderImg.parent().css('display'),
122
- position: this.placeholderImg.parent().css('position')
123
- };
124
- this.placeholderImg.parent().css({
125
- display: 'block',
126
- position: 'relative'
127
- });
145
+ this.placeholderImg.css({ margin: 0 });
128
146
  }
129
147
 
130
148
  // ---------------------------------------- | Full-Size Image
@@ -263,8 +281,9 @@
263
281
  this.fadeOutPlaceholder();
264
282
  setTimeout(function () {
265
283
  _this2.removeFullSizeImgProperties();
266
- _this2.replacePlaceholderParentTmpCss();
267
284
  _this2.removeImg();
285
+ // this.unwrapImg();
286
+ // 215 x 161.3 // 215 x 161 // 216.66 x 163
268
287
  }, this.timeToFade);
269
288
  }
270
289
 
@@ -291,19 +310,6 @@
291
310
  this.fullSizeImg.removeClass('imgix-optimizing');
292
311
  }
293
312
 
294
- /**
295
- * Reset the container's adjusted CSS properties.
296
- */
297
-
298
- }, {
299
- key: 'replacePlaceholderParentTmpCss',
300
- value: function replacePlaceholderParentTmpCss() {
301
- this.placeholderImg.parent().css({
302
- display: this.parentStyles.display,
303
- position: this.parentStyles.position
304
- });
305
- }
306
-
307
313
  /**
308
314
  * Remove the placeholder image from the DOM since we no longer need it.
309
315
  */
@@ -317,6 +323,16 @@
317
323
  this.placeholderImg.remove();
318
324
  this.placeholderImg = undefined;
319
325
  }
326
+
327
+ /**
328
+ * Remove the temporary wrapper and and give the margin back to the image.
329
+ */
330
+
331
+ }, {
332
+ key: 'unwrapImg',
333
+ value: function unwrapImg() {
334
+ this.fullSizeImg.css('margin', this.tmpWrapper.css('margin')).unwrap();
335
+ }
320
336
  }]);
321
337
  return Image;
322
338
  }();
@@ -0,0 +1,50 @@
1
+ <!DOCTYPE html>
2
+ <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3
+ <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
4
+ <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
5
+ <!--[if gt IE 8]><!-->
6
+ <html class="no-js">
7
+ <!--<![endif]-->
8
+ <head>
9
+ <meta charset="utf-8" />
10
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
11
+ <title>Inline Test</title>
12
+ <meta name="description" content="" />
13
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
14
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" />
15
+ <style>
16
+ .inline-img {
17
+ width: 250px;
18
+ margin: 30px;
19
+ }
20
+ </style>
21
+
22
+ <script
23
+ src="https://code.jquery.com/jquery-2.2.4.js"
24
+ integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
25
+ crossorigin="anonymous"
26
+ ></script>
27
+ <script src="https://rawgit.com/imgix/imgix.js/master/dist/imgix.min.js"></script>
28
+ <script src="imgix-optimizer.js"></script>
29
+ </head>
30
+ <body>
31
+ <div class="container">
32
+ <img
33
+ class="inline-img"
34
+ src="https://images.unsplash.com/photo-1513791222152-c347a9d6c3dd?auto=format,compress&w=12&h=9&fit=crop"
35
+ data-optimize-img
36
+ />
37
+ <img
38
+ class="inline-img"
39
+ src="https://images.unsplash.com/photo-1472457897821-70d3819a0e24?auto=format,compress&w=10&h=10&fit=crop"
40
+ data-optimize-img
41
+ />
42
+ </div>
43
+
44
+ <script>
45
+ (function() {
46
+ new Imgix.Optimizer();
47
+ })();
48
+ </script>
49
+ </body>
50
+ </html>
data/dist/main.css CHANGED
@@ -1,5 +1,4 @@
1
1
  img {
2
- /* position: relative; */
3
2
  width: 100%;
4
3
  }
5
4
 
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imgix-optimizer",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "devDependencies": {
5
5
  "babel-core": "^6.26.3",
6
6
  "babel-preset-es2015-rollup": "^3.0.0",
data/src/image.js CHANGED
@@ -6,9 +6,19 @@ export default class Image {
6
6
  this.processingAttr = 'data-imgix-img-processed';
7
7
  // The main image (pixelated placeholder).
8
8
  this.placeholderImg = $(img);
9
- // Configure the main placeholder image.
9
+ // Wait for the image to load prior to kicking off the optimization process.
10
+ if (this.placeholderImg.height() > 0) {
11
+ this.init();
12
+ } else {
13
+ this.placeholderImg.on('load', $.proxy(this.init, this));
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Configure the main placeholder image and kick off the optimization process.
19
+ */
20
+ init() {
10
21
  this.initPlaceholder();
11
- // Kick off the optimization process.
12
22
  this.initOptimization();
13
23
  }
14
24
 
@@ -23,6 +33,8 @@ export default class Image {
23
33
  .attr('src', this.placeholderImg.attr('src'));
24
34
  }
25
35
 
36
+ // ---------------------------------------- | Lazy Loading Control
37
+
26
38
  /**
27
39
  * When the placeholder image intersects the viewport, begin processing.
28
40
  * (IntersectionObserver and Object.assign() are not supported by IE, but the
@@ -51,34 +63,37 @@ export default class Image {
51
63
  * Make necessary CSS adjustments to main placeholder image.
52
64
  */
53
65
  initPlaceholder() {
66
+ this.wrapPlaceholder();
54
67
  this.setPlaceholderCss();
55
- this.setPlaceholderParentTmpCss();
68
+ }
69
+
70
+ /**
71
+ * Wrap the placeholder image in a <div>. This enables better control over the
72
+ * wrapping element and provides a more fluid transition process.
73
+ */
74
+ wrapPlaceholder() {
75
+ this.tmpWrapper = $('<div>').css({
76
+ position: 'relative',
77
+ height: this.placeholderImg[0].getBoundingClientRect().height,
78
+ width: this.placeholderImg[0].getBoundingClientRect().width,
79
+ margin: this.placeholderImg.css('margin')
80
+ });
81
+ this.placeholderImg.wrap(this.tmpWrapper);
56
82
  }
57
83
 
58
84
  /**
59
85
  * The main image must have a position set for it to remain in front of the
60
86
  * full-size image. We assume that if the element is not explicitly positioned
61
87
  * absolutely, then it can safely be positioned relatively.
88
+ *
89
+ * And temporarily remove any margin from the image, as the box model gets
90
+ * delegated to the temporary wrapper during the transition period.
62
91
  */
63
92
  setPlaceholderCss() {
64
93
  if (this.placeholderImg.css('position') != 'absolute') {
65
94
  this.placeholderImg.css('position', 'relative');
66
95
  }
67
- }
68
-
69
- /**
70
- * The parent of the image container should be relatively positioned
71
- * (temporarily) so temp image can be absolutely positioned.
72
- */
73
- setPlaceholderParentTmpCss() {
74
- this.parentStyles = {
75
- display: this.placeholderImg.parent().css('display'),
76
- position: this.placeholderImg.parent().css('position')
77
- };
78
- this.placeholderImg.parent().css({
79
- display: 'block',
80
- position: 'relative'
81
- });
96
+ this.placeholderImg.css({ margin: 0 });
82
97
  }
83
98
 
84
99
  // ---------------------------------------- | Full-Size Image
@@ -190,8 +205,9 @@ export default class Image {
190
205
  this.fadeOutPlaceholder();
191
206
  setTimeout(() => {
192
207
  this.removeFullSizeImgProperties();
193
- this.replacePlaceholderParentTmpCss();
194
208
  this.removeImg();
209
+ // this.unwrapImg();
210
+ // 215 x 161.3 // 215 x 161 // 216.66 x 163
195
211
  }, this.timeToFade);
196
212
  }
197
213
 
@@ -212,16 +228,6 @@ export default class Image {
212
228
  this.fullSizeImg.removeClass('imgix-optimizing');
213
229
  }
214
230
 
215
- /**
216
- * Reset the container's adjusted CSS properties.
217
- */
218
- replacePlaceholderParentTmpCss() {
219
- this.placeholderImg.parent().css({
220
- display: this.parentStyles.display,
221
- position: this.parentStyles.position
222
- });
223
- }
224
-
225
231
  /**
226
232
  * Remove the placeholder image from the DOM since we no longer need it.
227
233
  */
@@ -232,4 +238,11 @@ export default class Image {
232
238
  this.placeholderImg.remove();
233
239
  this.placeholderImg = undefined;
234
240
  }
241
+
242
+ /**
243
+ * Remove the temporary wrapper and and give the margin back to the image.
244
+ */
245
+ unwrapImg() {
246
+ this.fullSizeImg.css('margin', this.tmpWrapper.css('margin')).unwrap();
247
+ }
235
248
  }