buttons: Set min-width of button groups and icon buttons
[mediawiki.git] / resources / src / jquery / jquery.hidpi.js
blob4ecfeb884ea9b56752a0fdc6180c8aa2d5ec8f5e
1 /**
2  * Responsive images based on `srcset` and `window.devicePixelRatio` emulation where needed.
3  *
4  * Call `.hidpi()` on a document or part of a document to proces image srcsets within that section.
5  *
6  * `$.devicePixelRatio()` can be used as a substitute for `window.devicePixelRatio`.
7  * It provides a familiar interface to retrieve the pixel ratio for browsers that don't
8  * implement `window.devicePixelRatio` but do have a different way of getting it.
9  *
10  * @class jQuery.plugin.hidpi
11  */
12 ( function ( $ ) {
14 /**
15  * Get reported or approximate device pixel ratio.
16  *
17  * - 1.0 means 1 CSS pixel is 1 hardware pixel
18  * - 2.0 means 1 CSS pixel is 2 hardware pixels
19  * - etc.
20  *
21  * Uses `window.devicePixelRatio` if available, or CSS media queries on IE.
22  *
23  * @static
24  * @inheritable
25  * @return {number} Device pixel ratio
26  */
27 $.devicePixelRatio = function () {
28         if ( window.devicePixelRatio !== undefined ) {
29                 // Most web browsers:
30                 // * WebKit (Safari, Chrome, Android browser, etc)
31                 // * Opera
32                 // * Firefox 18+
33                 return window.devicePixelRatio;
34         } else if ( window.msMatchMedia !== undefined ) {
35                 // Windows 8 desktops / tablets, probably Windows Phone 8
36                 //
37                 // IE 10 doesn't report pixel ratio directly, but we can get the
38                 // screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for
39                 // simplicity, but you may get different values depending on zoom
40                 // factor, size of screen and orientation in Metro IE.
41                 if ( window.msMatchMedia( '(min-resolution: 192dpi)' ).matches ) {
42                         return 2;
43                 } else if ( window.msMatchMedia( '(min-resolution: 144dpi)' ).matches ) {
44                         return 1.5;
45                 } else {
46                         return 1;
47                 }
48         } else {
49                 // Legacy browsers...
50                 // Assume 1 if unknown.
51                 return 1;
52         }
55 /**
56  * Implement responsive images based on srcset attributes, if browser has no
57  * native srcset support.
58  *
59  * @return {jQuery} This selection
60  * @chainable
61  */
62 $.fn.hidpi = function () {
63         var $target = this,
64                 // @todo add support for dpi media query checks on Firefox, IE
65                 devicePixelRatio = $.devicePixelRatio(),
66                 testImage = new Image();
68         if ( devicePixelRatio > 1 && testImage.srcset === undefined ) {
69                 // No native srcset support.
70                 $target.find( 'img' ).each( function () {
71                         var $img = $( this ),
72                                 srcset = $img.attr( 'srcset' ),
73                                 match;
74                         if ( typeof srcset === 'string' && srcset !== '' ) {
75                                 match = $.matchSrcSet( devicePixelRatio, srcset );
76                                 if (match !== null ) {
77                                         $img.attr( 'src', match );
78                                 }
79                         }
80                 });
81         }
83         return $target;
86 /**
87  * Match a srcset entry for the given device pixel ratio
88  *
89  * Exposed for testing.
90  *
91  * @private
92  * @static
93  * @param {number} devicePixelRatio
94  * @param {string} srcset
95  * @return {Mixed} null or the matching src string
96  */
97 $.matchSrcSet = function ( devicePixelRatio, srcset ) {
98         var candidates,
99                 candidate,
100                 bits,
101                 src,
102                 i,
103                 ratioStr,
104                 ratio,
105                 selectedRatio = 1,
106                 selectedSrc = null;
107         candidates = srcset.split( / *, */ );
108         for ( i = 0; i < candidates.length; i++ ) {
109                 candidate = candidates[i];
110                 bits = candidate.split( / +/ );
111                 src = bits[0];
112                 if ( bits.length > 1 && bits[1].charAt( bits[1].length - 1 ) === 'x' ) {
113                         ratioStr = bits[1].slice( 0, -1 );
114                         ratio = parseFloat( ratioStr );
115                         if ( ratio <= devicePixelRatio && ratio > selectedRatio ) {
116                                 selectedRatio = ratio;
117                                 selectedSrc = src;
118                         }
119                 }
120         }
121         return selectedSrc;
125  * @class jQuery
126  * @mixins jQuery.plugin.hidpi
127  */
129 }( jQuery ) );