diff --git a/dist/picturefill.js b/dist/picturefill.js index 579ca377..75eb12c8 100644 --- a/dist/picturefill.js +++ b/dist/picturefill.js @@ -1,4 +1,4 @@ -/*! Picturefill - v2.0.0 - 2014-04-15 +/*! Picturefill - v2.0.0 - 2014-04-17 * http://scottjehl.github.io/picturefill * Copyright (c) 2014 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ @@ -161,11 +161,23 @@ window.matchMedia || (window.matchMedia = function() { } }; + /** + * Parses an individual `size` and returns the length, and optional media query + */ + pf.parseSize = function( sourceSizeStr ) { + var match = /(\([^)]+\))?\s*(.+)/g.exec( sourceSizeStr ); + return { + media: match && match[1], + length: match && match[2] + }; + }; + /** * Takes a string of sizes and returns the width in pixels as an int */ pf.findWidthFromSourceSize = function( sourceSizeListStr ) { // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33% + // or (min-width:30em) calc(30% - 15px) var sourceSizeList = pf.trim( sourceSizeListStr ).split( /\s*,\s*/ ); var winningLength; for ( var i=0, len=sourceSizeList.length; i < len; i++ ) { @@ -173,18 +185,17 @@ window.matchMedia || (window.matchMedia = function() { var sourceSize = sourceSizeList[ i ]; // Split "( min-width: 50em ) 100%" into separate strings - var match = /(\([^)]+\))?\s*([^\s]+)/g.exec( sourceSize ); - if ( !match ) { + var parsedSize = pf.parseSize( sourceSize ); + var length = parsedSize.length; + var media = parsedSize.media; + + if ( !length ) { continue; } - var length = match[ 2 ]; - var media; - if ( !match[ 1 ] ) { + if ( !media ) { // if there is no media query, choose this as our winning length winningLength = length; break; - } else { - media = match[ 1 ]; } if ( pf.matchesMedia( media ) ) { @@ -236,7 +247,7 @@ window.matchMedia || (window.matchMedia = function() { resolution = parseFloat( ( parseInt( sizeDescriptor, 10 ) / widthInCssPixels ).toFixed( 2 ) ); } else { // get the dpr by grabbing the value of Nx - resolution = sizeDescriptor ? parseFloat( sizeDescriptor, 10 ) : pf.getDpr(); + resolution = sizeDescriptor ? parseFloat( sizeDescriptor, 10 ) : 1; } var formattedCandidate = { @@ -281,26 +292,31 @@ window.matchMedia || (window.matchMedia = function() { }; pf.applyBestCandidate = function( candidates, picImg ) { - candidates.sort( pf.descendingSort ); - var candidate, bestCandidate = candidates[0]; - for ( var l=1; l < candidates.length; l++ ) { + var candidate, length, bestCandidate; + + candidates.sort( pf.ascendingSort ); + + length = candidates.length; + bestCandidate = candidates[ length - 1 ]; + + for ( var l=0; l < length; l++ ) { candidate = candidates[ l ]; - if ( candidate.resolution >= pf.getDpr() && candidate.resolution <= bestCandidate.resolution) { + if ( candidate.resolution >= pf.getDpr() ) { bestCandidate = candidate; - } else { break; } } + if ( !pf.endsWith( picImg.src, bestCandidate.url ) ) { picImg.src = bestCandidate.url; // currentSrc attribute and property to match // http://picture.responsiveimages.org/#the-img-element - picImg.currentSrc = bestCandidate.url; + picImg.currentSrc = picImg.src; } }; - pf.descendingSort = function( a, b ) { - return b.resolution - a.resolution; + pf.ascendingSort = function( a, b ) { + return a.resolution - b.resolution; }; /* @@ -325,27 +341,29 @@ window.matchMedia || (window.matchMedia = function() { /* * Find all picture elements and, - * in browsers that don't natively support srcset, find all img elements with srcset attrs that don't have picture parents + * in browsers that don't natively support srcset, find all img elements + * with srcset attrs that don't have picture parents */ - pf.getAllElements = function(){ + pf.getAllElements = function() { var pictures = doc.getElementsByTagName( "picture" ), elems = [], imgs = doc.getElementsByTagName( "img" ); - for ( var h = 0, len = pictures.length + imgs.length; h < len; h++ ){ - if( h < pictures.length ){ - elems[ h ] = pictures[ h ]; - } - else { - var currImg = imgs[ h - pictures.length ]; - if(currImg.parentNode.nodeName !== "PICTURE" && - ((pf.srcsetSupported && currImg.getAttribute( "sizes" )) - || currImg.getAttribute( "srcset" ) !== null)) { - elems.push( currImg ); - } + for ( var h = 0, len = pictures.length + imgs.length; h < len; h++ ) { + if ( h < pictures.length ){ + elems[ h ] = pictures[ h ]; + } + else { + var currImg = imgs[ h - pictures.length ]; + + if ( currImg.parentNode.nodeName !== "PICTURE" && + ( ( pf.srcsetSupported && currImg.getAttribute( "sizes" ) ) || + currImg.getAttribute( "srcset" ) !== null ) ) { + elems.push( currImg ); } } - return elems; + } + return elems; }; pf.getMatch = function( picture ) { @@ -353,7 +371,6 @@ window.matchMedia || (window.matchMedia = function() { var match; // Go through each child, and if they have media queries, evaluate them - // and add them to matches for ( var j=0, slen = sources.length; j < slen; j++ ) { var source = sources[ j ]; var media = source.getAttribute( "media" ); @@ -380,15 +397,23 @@ window.matchMedia || (window.matchMedia = function() { }; function picturefill( options ) { - var elements; + var elements, + element, + elemType, + firstMatch, + candidates, + picImg; options = options || {}; elements = options.elements || pf.getAllElements(); // Loop through all elements for ( var i=0, plen = elements.length; i < plen; i++ ) { - var element = elements[ i ]; - var elemType = element.nodeName; + element = elements[ i ]; + elemType = element.nodeName; + firstMatch = undefined; + candidates = undefined; + picImg = undefined; // expando for caching data on the img if( !element[ pf.ns ] ){ @@ -396,16 +421,12 @@ window.matchMedia || (window.matchMedia = function() { } // if the element has already been evaluated, skip it - // unless `options.reevaluate` is set to true ( this, for example, + // unless `options.force` is set to true ( this, for example, // is set to true when running `picturefill` on `resize` ). if ( !options.reevaluate && element[ pf.ns ].evaluated ) { continue; } - var firstMatch, - candidates, - picImg; - // if element is a picture element if( elemType === "PICTURE" ){ @@ -414,6 +435,7 @@ window.matchMedia || (window.matchMedia = function() { // return the first match which might undefined // returns false if there is a pending source + // TODO the return type here is brutal, cleanup firstMatch = pf.getMatch( element ); // if any sources are pending in this picture due to async type test(s) @@ -427,6 +449,7 @@ window.matchMedia || (window.matchMedia = function() { picImg = element.getElementsByTagName( "img" )[ 0 ]; } else { // if it's an img element + firstMatch = undefined; picImg = element; } diff --git a/dist/picturefill.min.js b/dist/picturefill.min.js index 1bd67af7..c9e32a8c 100644 --- a/dist/picturefill.min.js +++ b/dist/picturefill.min.js @@ -1,4 +1,4 @@ -/*! Picturefill - v2.0.0 - 2014-04-15 +/*! Picturefill - v2.0.0 - 2014-04-17 * http://scottjehl.github.io/picturefill * Copyright (c) 2014 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ -window.matchMedia||(window.matchMedia=function(){"use strict";var a=window.styleMedia||window.media;if(!a){var b=document.createElement("style"),c=document.getElementsByTagName("script")[0],d=null;b.type="text/css",b.id="matchmediajs-test",c.parentNode.insertBefore(b,c),d="getComputedStyle"in window&&window.getComputedStyle(b,null)||b.currentStyle,a={matchMedium:function(a){var c="@media "+a+"{ #matchmediajs-test { width: 1px; } }";return b.styleSheet?b.styleSheet.cssText=c:b.textContent=c,"1px"===d.width}}}return function(b){return{matches:a.matchMedium(b||"all"),media:b||"all"}}}()),function(a,b){"use strict";function c(a){var b;a=a||{},b=a.elements||e.getAllElements();for(var c=0,d=b.length;d>c;c++){var f=b[c],g=f.nodeName;if(f[e.ns]||(f[e.ns]={}),a.reevaluate||!f[e.ns].evaluated){var h,i,j;if("PICTURE"===g){if(e.removeVideoShim(f),h=e.getMatch(f),h===!1)continue;j=f.getElementsByTagName("img")[0]}else j=f;j&&(j[e.ns]||(j[e.ns]={}),j.srcset&&e.dodgeSrcset(j),h?(i=e.processSourceSet(h),e.applyBestCandidate(i,j)):(i=e.processSourceSet(j),(void 0===j.srcset||j.hasAttribute("sizes"))&&e.applyBestCandidate(i,j)),f[e.ns].evaluated=!0)}}}function d(){c();var d=setInterval(function(){return a.picturefill(),/^loaded|^i|^c/.test(b.readyState)?void clearInterval(d):void 0},250);if(a.addEventListener){var e;a.addEventListener("resize",function(){a.clearTimeout(e),e=a.setTimeout(function(){c({reevaluate:!0})},60)},!1)}}if(!a.HTMLPictureElement){b.createElement("picture"),b.createElement("source");var e={};e.ns="picturefill",e.srcsetSupported=void 0!==(new a.Image).srcset,e.trim=function(a){return a.trim?a.trim():a.replace(/^\s+|\s+$/g,"")},e.endsWith=function(a,b){return a.endsWith?a.endsWith(b):-1!==a.indexOf(b,a.length-b.length)},e.matchesMedia=function(b){return a.matchMedia&&a.matchMedia(b).matches},e.getDpr=function(){return a.devicePixelRatio||1},e.getWidthFromLength=function(a){return e.lengthEl||(e.lengthEl=b.createElement("div"),b.documentElement.insertBefore(e.lengthEl,b.documentElement.firstChild)),e.lengthEl.style.cssText="width: "+a+";",e.lengthEl.offsetWidth},e.types={},e.types["image/svg+xml"]=b.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1"),e.types["image/webp"]=function(){var b=new a.Image,d="image/webp";b.onerror=function(){e.types[d]=!1,c()},b.onload=function(){e.types[d]=1===b.width,c()},b.src="data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA="},e.verifyTypeSupport=function(a){var b=a.getAttribute("type");return null===b||""===b?!0:"function"==typeof e.types[b]?(e.types[b](),"pending"):e.types[b]},e.findWidthFromSourceSize=function(a){for(var b,c=e.trim(a).split(/\s*,\s*/),d=0,f=c.length;f>d;d++){var g=c[d],h=/(\([^)]+\))?\s*([^\s]+)/g.exec(g);if(h){var i,j=h[2];if(!h[1]){b=j;break}if(i=h[1],e.matchesMedia(i)){b=j;break}}}if(!b)return 300;var k=e.getWidthFromLength(b);return k},e.getCandidatesFromSourceSet=function(a,b){var c,d=e.trim(a).split(/\s*,\s*/),f=[];b&&(c=e.findWidthFromSourceSize(b));for(var g=0,h=d.length;h>g;g++){var i,j=d[g],k=j.split(/\s+/),l=k[1];!l||"w"!==l.slice(-1)&&"x"!==l.slice(-1)||(l=l.slice(0,-1)),i=b?parseFloat((parseInt(l,10)/c).toFixed(2)):l?parseFloat(l,10):e.getDpr();var m={url:k[0],resolution:i};f.push(m)}return f},e.dodgeSrcset=function(a){a.srcset&&(a[e.ns].srcset=a.srcset,a.removeAttribute("srcset"))},e.processSourceSet=function(a){var b=a.getAttribute("srcset"),c=a.getAttribute("sizes"),d=[];return"IMG"===a.nodeName&&a[e.ns]&&a[e.ns].srcset&&(b=a[e.ns].srcset),b&&(d=e.getCandidatesFromSourceSet(b,c)),d},e.applyBestCandidate=function(a,b){for(var c,d=a.sort(e.ascendingSort),f=0;f=e.getDpr()){e.endsWith(b.src,c.url)||(b.src=c.url,b.currentSrc=c.url);break}},e.ascendingSort=function(a,b){return a.resolution>b.resolution},e.removeVideoShim=function(a){var b=a.getElementsByTagName("video");if(b.length){for(var c=b[0],d=c.getElementsByTagName("source");d.length;)a.insertBefore(d[0],c);c.parentNode.removeChild(c)}},e.getAllElements=function(){var a=b.getElementsByTagName("picture");if(e.srcsetSupported)return a;for(var c=[],d=b.getElementsByTagName("img"),f=0,g=a.length+d.length;g>f;f++)if(fd;d++){var g=c[d],h=g.getAttribute("media");if(g.hasAttribute("srcset")&&(!h||e.matchesMedia(h))){var i=e.verifyTypeSupport(g);if(i===!0){b=g;break}if("pending"===i)return!1}}return b},d(),c._=e,"object"==typeof module&&"object"==typeof module.exports?module.exports=c:"object"==typeof define&&define.amd?define(function(){return c}):"object"==typeof a&&(a.picturefill=c)}}(this,this.document); \ No newline at end of file +window.matchMedia||(window.matchMedia=function(){"use strict";var a=window.styleMedia||window.media;if(!a){var b=document.createElement("style"),c=document.getElementsByTagName("script")[0],d=null;b.type="text/css",b.id="matchmediajs-test",c.parentNode.insertBefore(b,c),d="getComputedStyle"in window&&window.getComputedStyle(b,null)||b.currentStyle,a={matchMedium:function(a){var c="@media "+a+"{ #matchmediajs-test { width: 1px; } }";return b.styleSheet?b.styleSheet.cssText=c:b.textContent=c,"1px"===d.width}}}return function(b){return{matches:a.matchMedium(b||"all"),media:b||"all"}}}()),function(a,b){"use strict";function c(a){var b,c,d,f,g,h;a=a||{},b=a.elements||e.getAllElements();for(var i=0,j=b.length;j>i;i++)if(c=b[i],d=c.nodeName,f=void 0,g=void 0,h=void 0,c[e.ns]||(c[e.ns]={}),a.reevaluate||!c[e.ns].evaluated){if("PICTURE"===d){if(e.removeVideoShim(c),f=e.getMatch(c),f===!1)continue;h=c.getElementsByTagName("img")[0]}else f=void 0,h=c;h&&(h[e.ns]||(h[e.ns]={}),h.srcset&&e.dodgeSrcset(h),f?(g=e.processSourceSet(f),e.applyBestCandidate(g,h)):(g=e.processSourceSet(h),(void 0===h.srcset||h.hasAttribute("sizes"))&&e.applyBestCandidate(g,h)),c[e.ns].evaluated=!0)}}function d(){c();var d=setInterval(function(){return a.picturefill(),/^loaded|^i|^c/.test(b.readyState)?void clearInterval(d):void 0},250);if(a.addEventListener){var e;a.addEventListener("resize",function(){a.clearTimeout(e),e=a.setTimeout(function(){c({reevaluate:!0})},60)},!1)}}if(!a.HTMLPictureElement){b.createElement("picture"),b.createElement("source");var e={};e.ns="picturefill",e.srcsetSupported=void 0!==(new a.Image).srcset,e.trim=function(a){return a.trim?a.trim():a.replace(/^\s+|\s+$/g,"")},e.endsWith=function(a,b){return a.endsWith?a.endsWith(b):-1!==a.indexOf(b,a.length-b.length)},e.matchesMedia=function(b){return a.matchMedia&&a.matchMedia(b).matches},e.getDpr=function(){return a.devicePixelRatio||1},e.getWidthFromLength=function(a){return e.lengthEl||(e.lengthEl=b.createElement("div"),b.documentElement.insertBefore(e.lengthEl,b.documentElement.firstChild)),e.lengthEl.style.cssText="width: "+a+";",e.lengthEl.offsetWidth},e.types={},e.types["image/svg+xml"]=b.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1"),e.types["image/webp"]=function(){var b=new a.Image,d="image/webp";b.onerror=function(){e.types[d]=!1,c()},b.onload=function(){e.types[d]=1===b.width,c()},b.src="data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA="},e.verifyTypeSupport=function(a){var b=a.getAttribute("type");return null===b||""===b?!0:"function"==typeof e.types[b]?(e.types[b](),"pending"):e.types[b]},e.parseSize=function(a){var b=/(\([^)]+\))?\s*(.+)/g.exec(a);return{media:b&&b[1],length:b&&b[2]}},e.findWidthFromSourceSize=function(a){for(var b,c=e.trim(a).split(/\s*,\s*/),d=0,f=c.length;f>d;d++){var g=c[d],h=e.parseSize(g),i=h.length,j=h.media;if(i){if(!j){b=i;break}if(e.matchesMedia(j)){b=i;break}}}if(!b)return 300;var k=e.getWidthFromLength(b);return k},e.getCandidatesFromSourceSet=function(a,b){var c,d=e.trim(a).split(/\s*,\s*/),f=[];b&&(c=e.findWidthFromSourceSize(b));for(var g=0,h=d.length;h>g;g++){var i,j=d[g],k=j.split(/\s+/),l=k[1];!l||"w"!==l.slice(-1)&&"x"!==l.slice(-1)||(l=l.slice(0,-1)),i=b?parseFloat((parseInt(l,10)/c).toFixed(2)):l?parseFloat(l,10):1;var m={url:k[0],resolution:i};f.push(m)}return f},e.dodgeSrcset=function(a){a.srcset&&(a[e.ns].srcset=a.srcset,a.removeAttribute("srcset"))},e.processSourceSet=function(a){var b=a.getAttribute("srcset"),c=a.getAttribute("sizes"),d=[];return"IMG"===a.nodeName&&a[e.ns]&&a[e.ns].srcset&&(b=a[e.ns].srcset),b&&(d=e.getCandidatesFromSourceSet(b,c)),d},e.applyBestCandidate=function(a,b){var c,d,f;a.sort(e.ascendingSort),d=a.length,f=a[d-1];for(var g=0;d>g;g++)if(c=a[g],c.resolution>=e.getDpr()){f=c;break}e.endsWith(b.src,f.url)||(b.src=f.url,b.currentSrc=b.src)},e.ascendingSort=function(a,b){return a.resolution-b.resolution},e.removeVideoShim=function(a){var b=a.getElementsByTagName("video");if(b.length){for(var c=b[0],d=c.getElementsByTagName("source");d.length;)a.insertBefore(d[0],c);c.parentNode.removeChild(c)}},e.getAllElements=function(){for(var a=b.getElementsByTagName("picture"),c=[],d=b.getElementsByTagName("img"),f=0,g=a.length+d.length;g>f;f++)if(fd;d++){var g=c[d],h=g.getAttribute("media");if(g.hasAttribute("srcset")&&(!h||e.matchesMedia(h))){var i=e.verifyTypeSupport(g);if(i===!0){b=g;break}if("pending"===i)return!1}}return b},d(),c._=e,"object"==typeof module&&"object"==typeof module.exports?module.exports=c:"object"==typeof define&&define.amd?define(function(){return c}):"object"==typeof a&&(a.picturefill=c)}}(this,this.document); \ No newline at end of file