imgix-optimizer 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }