Skip to content

Commit

Permalink
Managing both src and srcset in the img tag
Browse files Browse the repository at this point in the history
picturePolyfill now manages the case in which the `img` tag contains
both src and srcset, and it extracts both `srcset` and `src` from the
`source` tags, applying it to the internal `img` tag
  • Loading branch information
verlok committed Jul 22, 2014
1 parent d29a4d3 commit 02cad52
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' +
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "picturePolyfill",
"version": "4.0.0",
"version": "4.1.0",
"main": "picturePolyfill.js",
"ignore": [
".idea",
Expand Down
4 changes: 2 additions & 2 deletions dist/picturePolyfill.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ <h3>With HD (Retina) display support</h3>
<source media="(min-width: 1025px)" srcset="img/720x720.gif, img/720x720x2.gif 2x"/>
<source media="(min-width: 481px)" srcset="img/512x512.gif, img/512x512x2.gif 2x"/>
<source srcset="img/480x480.gif, img/480x480x2.gif 2x"/>
<img src="img/960x960.gif" alt="A beautiful responsive image"/>
<img src="img/720x720.gif" srcset="img/720x720.gif, img/720x720x2.gif 2x" alt="A beautiful responsive image"/>
</picture>
</div>
<div class="element">
Expand All @@ -104,11 +104,11 @@ <h3>Without HD (Retina) display support</h3>
<h2>Full width pre-scaled image, with HD (Retina) display support</h2>

<picture data-alt="A beautiful responsive image" data-default-src="img/1440x1440.gif">
<source srcset="img/1920x1920.gif, img/1920x1920x2.gif 2x" media="(min-width: 1441px)"/>
<source srcset="img/1440x1440.gif, img/1440x1440x2.gif 2x" media="(min-width: 1025px)"/>
<source srcset="img/1024x1024.gif, img/1024x1024x2.gif 2x" media="(min-width: 481px)"/>
<source srcset="img/480x480.gif, img/480x480x2.gif 2x"/>
<img src="img/1440x1440.gif" alt="A beautiful responsive image"/>
<source media="(min-width: 1441px)" srcset="img/1920x1920.gif, img/1920x1920x2.gif 2x"/>
<source media="(min-width: 1025px)" srcset="img/1440x1440.gif, img/1440x1440x2.gif 2x"/>
<source media="(min-width: 481px)" srcset="img/1024x1024.gif, img/1024x1024x2.gif 2x"/>
<source srcset="img/480x480.gif, img/480x480x2.gif 2x"/>
<img src="img/1440x1440.gif" srcset="img/1440x1440.gif, img/1440x1440x2.gif 2x" alt="A beautiful responsive image"/>
</picture>

</div>
Expand Down
76 changes: 42 additions & 34 deletions src/picturePolyfill.js
Original file line number Diff line number Diff line change
@@ -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) {

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);

},

Expand Down Expand Up @@ -297,6 +298,7 @@ var picturePolyfill = (function (w) {
pictureElement,
pictureElements,
srcAttribute,
srcsetAttribute,
mqSupport,
cacheIndex;

Expand All @@ -306,7 +308,7 @@ var picturePolyfill = (function (w) {
}

// Default readFromCache parameter value
if (readFromCache === null) {
if (typeof readFromCache === 'undefined') {
readFromCache = true;
}

Expand All @@ -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')
});
}
Expand Down
52 changes: 27 additions & 25 deletions test/picturePolyfill.qunit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*
* TODO: Add test on readFromCache parameter of parse()
*
* TODO: Test cases with <img src="..." srcset="..."> and sources matching or not matching
* */

module("picturePolyfill", {
setup: function () {
// Nothing here!
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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"}
]);


}
Expand Down Expand Up @@ -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 () {
Expand Down

0 comments on commit 02cad52

Please sign in to comment.