diff --git a/Gruntfile.js b/Gruntfile.js
index 1fbf813..4fee459 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -5,7 +5,7 @@ module.exports = function(grunt) {
grunt.initConfig({
// Metadata.
meta: {
- version: '4.0.0'
+ version: '4.1.0'
},
banner: '/*! picturePolyfill - v<%= meta.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
diff --git a/bower.json b/bower.json
index afb0701..14c0cc8 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "picturePolyfill",
- "version": "4.0.0",
+ "version": "4.1.0",
"main": "picturePolyfill.js",
"ignore": [
".idea",
diff --git a/dist/picturePolyfill.min.js b/dist/picturePolyfill.min.js
index a0c7631..cd64c3d 100644
--- a/dist/picturePolyfill.min.js
+++ b/dist/picturePolyfill.min.js
@@ -1,4 +1,4 @@
-/*! picturePolyfill - v4.0.0 - 2014-07-22
+/*! picturePolyfill - v4.1.0 - 2014-07-22
* https://github.com/verlok/picturePolyfill/
* Copyright (c) 2014 Andrea "verlok" Verlicchi; Licensed MIT */
-var picturePolyfill=function(a){"use strict";var b,c,d,e=100,f=!1;return{_getAttrs:function(a,b){for(var c,d,e={},f=0,g=b.length;g>f;f+=1)c=b[f],d=a.getAttribute(c),d&&(e[c]=d);return e},_getAttrsList:function(a){for(var b=[],c=0,d=a.attributes,e=d.length;e>c;c++)b.push(d.item(c).nodeName);return b},_getSrcsetArray:function(a){for(var b,c,d,e=[],f=a.split(","),g=0,h=f.length;h>g;g+=1)b=f[g].trim().split(" "),d=1===b.length?1:parseFloat(b[b.length-1],10),c=b[0],e.push({pxr:d,src:c});return e.sort(function(a,b){var c=a.pxr,d=b.pxr;return d>c?-1:c>d?1:0})},_getSrcFromArray:function(a,b){var c=0,d=a.length,e=-1;if(!d)return null;do(a[c].pxr>=b||c===d-1)&&(e=c),c+=1;while(!(e>-1||c>=d));return a[e].src},_getSrcFromData:function(b){for(var c,d,e,f=0,g=b.length;g>f;f+=1)if(c=b[f],d=c.media,e=c.srcset,!d||a.matchMedia(d).matches)return e?this._getSrcFromArray(e,this._pxRatio):c.src;return null},_setImgSrc:function(a,b){var c,d,e,f,g,h,i=a.getElementsByTagName("img");return 0===i.length?!1:(c=i[0],d=c.getAttribute("data-original-src"),e=c.getAttribute("data-original-srcset"),f=b.src,d||(c.setAttribute("data-original-src",c.getAttribute("src")),c.setAttribute("data-original-srcset",c.getAttribute("srcset"))),f?(g=f,h=b.srcset):(g=d,h=e),c.getAttribute("src")!==g&&c.setAttribute("src",g),void(h&&c.getAttribute("srcset")!==h&&c.setAttribute("srcset",h)))},_getSourcesData:function(a){for(var b,c,d=[],e=a.getElementsByTagName("source"),f=0,g=e.length;g>f;f+=1)b=e[f],c=this._getAttrs(b,this._getAttrsList(b)),c.srcset&&(c.srcset=this._getSrcsetArray(c.srcset)),d.push(c);return d},_addListeners:function(){function b(){picturePolyfill.parse(document)}function c(){clearTimeout(d),d=setTimeout(b,e)}return!this.isUseful||f?!1:(a.addEventListener?(a.addEventListener("resize",c),a.addEventListener("DOMContentLoaded",function(){b(),a.removeEventListener("load",b)}),a.addEventListener("load",b)):a.attachEvent&&(a.attachEvent("onload",b),a.attachEvent("onresize",c)),void(f=!0))},initialize:function(){this._pxRatio=a.devicePixelRatio||1,this._mqSupport=!!a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,this.isUseful=!a.HTMLPictureElement,b=[],c=0,this._addListeners()},parse:function(a,d){var e,f,g,h,i,j;if(!this.isUseful)return 0;null===d&&(d=!0),g=(a||document).getElementsByTagName("picture"),i=this._mqSupport;for(var k=0,l=g.length;l>k;k+=1)e=null,f=g[k],d&&(j=f.getAttribute("data-cache-index"),null!==j&&(e=b[j])),e||(e=this._getSourcesData(f),b[c]=e,f.setAttribute("data-cache-index",c),c+=1),h=0!==e.length&&i?this._getSrcFromData(e):f.getAttribute("data-default-src"),this._setImgSrc(f,{src:h,alt:f.getAttribute("data-alt")});return k}}}(window);picturePolyfill.initialize(),picturePolyfill.parse();
\ No newline at end of file
+var picturePolyfill=function(a){"use strict";var b,c,d,e=100,f=!1;return{_getAttrs:function(a,b){for(var c,d,e={},f=0,g=b.length;g>f;f+=1)c=b[f],d=a.getAttribute(c),d&&(e[c]=d);return e},_getAttrsList:function(a){for(var b=[],c=0,d=a.attributes,e=d.length;e>c;c++)b.push(d.item(c).nodeName);return b},_getSrcsetArray:function(a){for(var b,c,d,e=[],f=a.split(","),g=0,h=f.length;h>g;g+=1)b=f[g].trim().split(" "),d=1===b.length?1:parseFloat(b[b.length-1],10),c=b[0],e.push({pxr:d,src:c});return e.sort(function(a,b){var c=a.pxr,d=b.pxr;return d>c?-1:c>d?1:0})},_getSrcFromArray:function(a,b){var c=0,d=a.length,e=-1;if(!d)return null;do(a[c].pxr>=b||c===d-1)&&(e=c),c+=1;while(!(e>-1||c>=d));return a[e].src},_getSrcsetFromData:function(b){for(var c,d,e,f=0,g=b.length;g>f;f+=1)if(c=b[f],d=c.media,e=c.srcset,!d||a.matchMedia(d).matches)return e?e:[{pxr:1,src:c.src}];return null},_setImgAttributes:function(a,b){function c(a,b,c){a.getAttribute(b)!==c&&a.setAttribute(b,c)}var d,e,f,g,h,i,j,k=a.getElementsByTagName("img");return 0===k.length?!1:(d=k[0],e=d.getAttribute("data-original-src"),f=d.getAttribute("data-original-srcset"),g=b.src,h=b.src,e||(c(d,"data-original-src",d.getAttribute("src")),c(d,"data-original-srcset",d.getAttribute("srcset"))),g||h?(i=g,j=h):(i=e,j=f),c(d,"src",i),void c(d,"srcset",j))},_getSourcesData:function(a){for(var b,c,d=[],e=a.getElementsByTagName("source"),f=0,g=e.length;g>f;f+=1)b=e[f],c=this._getAttrs(b,this._getAttrsList(b)),c.srcset&&(c.srcset=this._getSrcsetArray(c.srcset)),d.push(c);return d},_addListeners:function(){function b(){picturePolyfill.parse(document)}function c(){clearTimeout(d),d=setTimeout(b,e)}return!this.isUseful||f?!1:(a.addEventListener?(a.addEventListener("resize",c),a.addEventListener("DOMContentLoaded",function(){b(),a.removeEventListener("load",b)}),a.addEventListener("load",b)):a.attachEvent&&(a.attachEvent("onload",b),a.attachEvent("onresize",c)),void(f=!0))},initialize:function(){this._pxRatio=a.devicePixelRatio||1,this._mqSupport=!!a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,this.isUseful=!a.HTMLPictureElement,b=[],c=0,this._addListeners()},parse:function(a,d){var e,f,g,h,i,j,k;if(!this.isUseful)return 0;"undefined"==typeof d&&(d=!0),g=(a||document).getElementsByTagName("picture"),j=this._mqSupport;for(var l=0,m=g.length;m>l;l+=1)e=null,f=g[l],d&&(k=f.getAttribute("data-cache-index"),null!==k&&(e=b[k])),e||(e=this._getSourcesData(f),b[c]=e,f.setAttribute("data-cache-index",c),c+=1),0!==e.length&&j?(i=this._getSrcsetFromData(e),h=this._getSrcFromArray(i,this._pxRatio)):(h=f.getAttribute("data-default-src"),i=f.getAttribute("data-default-srcset")),this._setImgAttributes(f,{src:h,srcset:i,alt:f.getAttribute("data-alt")});return l}}}(window);picturePolyfill.initialize(),picturePolyfill.parse();
\ No newline at end of file
diff --git a/index.html b/index.html
index 15aa0fe..372dcb0 100644
--- a/index.html
+++ b/index.html
@@ -86,7 +86,7 @@
With HD (Retina) display support
-
+
@@ -104,11 +104,11 @@
Without HD (Retina) display support
Full width pre-scaled image, with HD (Retina) display support
diff --git a/src/picturePolyfill.js b/src/picturePolyfill.js
index 4b67164..59427a6 100644
--- a/src/picturePolyfill.js
+++ b/src/picturePolyfill.js
@@ -1,12 +1,10 @@
-/* PicturePolyfill - Responsive Images that work today. (and mimic the proposed Picture element with span elements). Author: Andrea Verlicchi | License: MIT/GPLv2 */
-
/*
- * TODO:
- * ALSO MANAGE SRCSET, IT MIGHT BE ALREADY SUPPORTED BY THE BROWSER
- * SO NO NEED TO SET SRC INDIVIDUALLY
- * 1. TEST SRCSET SUPPORT SOMEHOW
- * 2. IF SRCSET IS SUPPORTED, SET BOTH SRC AND SRCSET IN THE IMG TAG, ELSE SRC ONLY
- * */
+ PicturePolyfill
+ Responsive Images that work today (and mimic the proposed Picture element with span elements)
+ Author: Andrea Verlicchi
+ License: MIT/GPLv2
+ Please "/dist/picturePolyfill.min.js" for production purposes
+*/
var picturePolyfill = (function (w) {
@@ -117,12 +115,12 @@ var picturePolyfill = (function (w) {
/**
* Loop through every element of the sourcesData array, check if the media query applies and,
- * if so, get the src element from the srcSet property based depending on pixel ratio
+ * if so, get the matching srcset attribute, if any
* @param sourcesData
* @returns {string||undefined}
* @private
*/
- _getSrcFromData: function (sourcesData) {
+ _getSrcsetFromData: function (sourcesData) {
var sourceData,
media,
srcset;
@@ -132,7 +130,7 @@ var picturePolyfill = (function (w) {
media = sourceData.media;
srcset = sourceData.srcset;
if (!media || w.matchMedia(media).matches) {
- return (srcset) ? this._getSrcFromArray(srcset, this._pxRatio) : sourceData.src;
+ return (srcset) ? srcset : [{pxr: 1, src: sourceData.src}];
}
}
return null;
@@ -144,44 +142,47 @@ var picturePolyfill = (function (w) {
* @param pictureElement {Node}
* @param attributes
*/
- _setImgSrc: function (pictureElement, attributes) {
+ _setImgAttributes: function (pictureElement, attributes) {
var imageElements = pictureElement.getElementsByTagName('img'),
- imgEl, originalImgSrc, originalImgSrcset, givenSrcAttribute,
+ imgEl, originalImgSrc, originalImgSrcset,
+ givenSrcAttribute, givenSrcsetAttribute,
srcToSet, srcsetToSet;
+ function _setAttributeIfDifferent(element, attribute, value) {
+ if (element.getAttribute(attribute) !== value) {
+ element.setAttribute(attribute, value);
+ }
+ }
+
if (imageElements.length === 0) {
return false;
}
+ // Setting repeated usage variables
imgEl = imageElements[0];
originalImgSrc = imgEl.getAttribute('data-original-src');
originalImgSrcset = imgEl.getAttribute('data-original-srcset');
givenSrcAttribute = attributes.src;
+ givenSrcsetAttribute = attributes.src;
// Set original img tag's src and srcset in a data attribute
if (!originalImgSrc) {
- imgEl.setAttribute('data-original-src', imgEl.getAttribute('src'));
- imgEl.setAttribute('data-original-srcset', imgEl.getAttribute('srcset'));
+ _setAttributeIfDifferent(imgEl, 'data-original-src', imgEl.getAttribute('src'));
+ _setAttributeIfDifferent(imgEl, 'data-original-srcset', imgEl.getAttribute('srcset'));
}
- // Set srcToSet and srcsetToSet depending on the given src attribute
- // If the given src is empty, use the original img src and srcset
- if (!givenSrcAttribute) {
+ // Set srcToSet and srcsetToSet depending on the given src/srcset attributes
+ // If none are given, use original ones
+ // If both ore one are given, them (even if one is null)
+ if (!givenSrcAttribute && !givenSrcsetAttribute) {
srcToSet = originalImgSrc;
srcsetToSet = originalImgSrcset;
- }
- else {
+ } else {
srcToSet = givenSrcAttribute;
- srcsetToSet = attributes.srcset;
- }
-
- if (imgEl.getAttribute('src') !== srcToSet) {
- imgEl.setAttribute('src', srcToSet);
- }
- if (!!srcsetToSet && imgEl.getAttribute('srcset') !== srcsetToSet) {
- imgEl.setAttribute('srcset', srcsetToSet);
+ srcsetToSet = givenSrcsetAttribute;
}
-
+ _setAttributeIfDifferent(imgEl, 'src', srcToSet);
+ _setAttributeIfDifferent(imgEl, 'srcset', srcsetToSet);
},
@@ -297,6 +298,7 @@ var picturePolyfill = (function (w) {
pictureElement,
pictureElements,
srcAttribute,
+ srcsetAttribute,
mqSupport,
cacheIndex;
@@ -306,7 +308,7 @@ var picturePolyfill = (function (w) {
}
// Default readFromCache parameter value
- if (readFromCache === null) {
+ if (typeof readFromCache === 'undefined') {
readFromCache = true;
}
@@ -332,12 +334,18 @@ var picturePolyfill = (function (w) {
cacheLatestIndex += 1;
}
// If no sourcesData retrieved or media queries are not supported, read from the default src
- srcAttribute = (sourcesData.length === 0 || !mqSupport) ?
- pictureElement.getAttribute('data-default-src') :
- this._getSrcFromData(sourcesData);
+ if (sourcesData.length === 0 || !mqSupport) {
+ srcAttribute = pictureElement.getAttribute('data-default-src');
+ srcsetAttribute = pictureElement.getAttribute('data-default-srcset');
+ }
+ else {
+ srcsetAttribute = this._getSrcsetFromData(sourcesData);
+ srcAttribute = this._getSrcFromArray(srcsetAttribute, this._pxRatio);
+ }
// Set the img source
- this._setImgSrc(pictureElement, {
+ this._setImgAttributes(pictureElement, {
src: srcAttribute,
+ srcset: srcsetAttribute,
alt: pictureElement.getAttribute('data-alt')
});
}
diff --git a/test/picturePolyfill.qunit.js b/test/picturePolyfill.qunit.js
index 38c1fba..e85eed5 100644
--- a/test/picturePolyfill.qunit.js
+++ b/test/picturePolyfill.qunit.js
@@ -1,3 +1,9 @@
+/*
+* TODO: Add test on readFromCache parameter of parse()
+*
+* TODO: Test cases with and sources matching or not matching
+* */
+
module("picturePolyfill", {
setup: function () {
// Nothing here!
@@ -198,7 +204,7 @@ test("_getSrcsetArray correct behaviour, messy srcset format", function () {
}
});
-test("_getSrcFromData behaves correctly", function () {
+test("_getSrcsetFromData behaves correctly", function () {
if (!picturePolyfill._mqSupport) {
ok(true);
}
@@ -246,38 +252,34 @@ test("_getSrcFromData behaves correctly", function () {
matchMediaStub.withArgs("(min-width: 200px)").returns(negative);
matchMediaStub.withArgs("(min-width: 100px)").returns(negative);
matchMediaStub.withArgs(null).returns(positive);
-
- picturePolyfill._pxRatio = 1;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "50.gif");
- picturePolyfill._pxRatio = 2;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "100.gif");
+ deepEqual(picturePolyfill._getSrcsetFromData(sourcesData), [
+ {pxr: 1, src: "50.gif"},
+ {pxr: 2, src: "100.gif"}
+ ]);
// Testing width @ 100px
matchMediaStub.withArgs("(min-width: 100px)").returns(positive);
-
- picturePolyfill._pxRatio = 1;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "100.gif");
- picturePolyfill._pxRatio = 2;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "200.gif");
+ deepEqual(picturePolyfill._getSrcsetFromData(sourcesData), [
+ {pxr: 1, src: "100.gif"},
+ {pxr: 2, src: "200.gif"}
+ ]);
// Testing width @ 200px
matchMediaStub.withArgs("(min-width: 200px)").returns(positive);
-
- picturePolyfill._pxRatio = 1;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "200.gif");
- picturePolyfill._pxRatio = 2;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "400.gif");
+ deepEqual(picturePolyfill._getSrcsetFromData(sourcesData), [
+ {pxr: 1, src: "200.gif"},
+ {pxr: 2, src: "400.gif"}
+ ]);
// Testing width @ 300px
matchMediaStub.withArgs("(min-width: 300px)").returns(positive);
-
- picturePolyfill._pxRatio = 1;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "300.gif");
- picturePolyfill._pxRatio = 2;
- strictEqual(picturePolyfill._getSrcFromData(sourcesData), "600.gif");
+ deepEqual(picturePolyfill._getSrcsetFromData(sourcesData), [
+ {pxr: 1, src: "300.gif"},
+ {pxr: 2, src: "600.gif"}
+ ]);
}
@@ -433,17 +435,17 @@ test("parse() only parses passed element", function () {
// Setting spies
- this.spy(picturePolyfill, "_setImgSrc");
+ this.spy(picturePolyfill, "_setImgAttributes");
// Testing number of calls when calling parse() on the whole document or on a single element
picturePolyfill.parse();
- ok(picturePolyfill._setImgSrc.calledTwice);
+ ok(picturePolyfill._setImgAttributes.calledTwice);
- picturePolyfill._setImgSrc.reset();
+ picturePolyfill._setImgAttributes.reset();
picturePolyfill.parse(document.getElementById('innerA'));
- ok(picturePolyfill._setImgSrc.calledOnce);
+ ok(picturePolyfill._setImgAttributes.calledOnce);
});
test("parse() resulting image sources - with MQ support", function () {