diff options
Diffstat (limited to 'resources/src/jquery/jquery.hidpi.js')
-rw-r--r-- | resources/src/jquery/jquery.hidpi.js | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/resources/src/jquery/jquery.hidpi.js b/resources/src/jquery/jquery.hidpi.js new file mode 100644 index 00000000..4ecfeb88 --- /dev/null +++ b/resources/src/jquery/jquery.hidpi.js @@ -0,0 +1,129 @@ +/** + * Responsive images based on `srcset` and `window.devicePixelRatio` emulation where needed. + * + * Call `.hidpi()` on a document or part of a document to proces image srcsets within that section. + * + * `$.devicePixelRatio()` can be used as a substitute for `window.devicePixelRatio`. + * It provides a familiar interface to retrieve the pixel ratio for browsers that don't + * implement `window.devicePixelRatio` but do have a different way of getting it. + * + * @class jQuery.plugin.hidpi + */ +( function ( $ ) { + +/** + * Get reported or approximate device pixel ratio. + * + * - 1.0 means 1 CSS pixel is 1 hardware pixel + * - 2.0 means 1 CSS pixel is 2 hardware pixels + * - etc. + * + * Uses `window.devicePixelRatio` if available, or CSS media queries on IE. + * + * @static + * @inheritable + * @return {number} Device pixel ratio + */ +$.devicePixelRatio = function () { + if ( window.devicePixelRatio !== undefined ) { + // Most web browsers: + // * WebKit (Safari, Chrome, Android browser, etc) + // * Opera + // * Firefox 18+ + return window.devicePixelRatio; + } else if ( window.msMatchMedia !== undefined ) { + // Windows 8 desktops / tablets, probably Windows Phone 8 + // + // IE 10 doesn't report pixel ratio directly, but we can get the + // screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for + // simplicity, but you may get different values depending on zoom + // factor, size of screen and orientation in Metro IE. + if ( window.msMatchMedia( '(min-resolution: 192dpi)' ).matches ) { + return 2; + } else if ( window.msMatchMedia( '(min-resolution: 144dpi)' ).matches ) { + return 1.5; + } else { + return 1; + } + } else { + // Legacy browsers... + // Assume 1 if unknown. + return 1; + } +}; + +/** + * Implement responsive images based on srcset attributes, if browser has no + * native srcset support. + * + * @return {jQuery} This selection + * @chainable + */ +$.fn.hidpi = function () { + var $target = this, + // @todo add support for dpi media query checks on Firefox, IE + devicePixelRatio = $.devicePixelRatio(), + testImage = new Image(); + + if ( devicePixelRatio > 1 && testImage.srcset === undefined ) { + // No native srcset support. + $target.find( 'img' ).each( function () { + var $img = $( this ), + srcset = $img.attr( 'srcset' ), + match; + if ( typeof srcset === 'string' && srcset !== '' ) { + match = $.matchSrcSet( devicePixelRatio, srcset ); + if (match !== null ) { + $img.attr( 'src', match ); + } + } + }); + } + + return $target; +}; + +/** + * Match a srcset entry for the given device pixel ratio + * + * Exposed for testing. + * + * @private + * @static + * @param {number} devicePixelRatio + * @param {string} srcset + * @return {Mixed} null or the matching src string + */ +$.matchSrcSet = function ( devicePixelRatio, srcset ) { + var candidates, + candidate, + bits, + src, + i, + ratioStr, + ratio, + selectedRatio = 1, + selectedSrc = null; + candidates = srcset.split( / *, */ ); + for ( i = 0; i < candidates.length; i++ ) { + candidate = candidates[i]; + bits = candidate.split( / +/ ); + src = bits[0]; + if ( bits.length > 1 && bits[1].charAt( bits[1].length - 1 ) === 'x' ) { + ratioStr = bits[1].slice( 0, -1 ); + ratio = parseFloat( ratioStr ); + if ( ratio <= devicePixelRatio && ratio > selectedRatio ) { + selectedRatio = ratio; + selectedSrc = src; + } + } + } + return selectedSrc; +}; + +/** + * @class jQuery + * @mixins jQuery.plugin.hidpi + */ + +}( jQuery ) ); |