1
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
4
window.matchMedia = window.matchMedia || (function( doc, undefined ) {
9
docElem = doc.documentElement,
10
refNode = docElem.firstElementChild || docElem.firstChild,
11
// fakeBody required for <FF4 when executed in <head>
12
fakeBody = doc.createElement( "body" ),
13
div = doc.createElement( "div" );
16
div.style.cssText = "position:absolute;top:-100em";
17
fakeBody.style.background = "none";
18
fakeBody.appendChild(div);
22
div.innerHTML = "­<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
24
docElem.insertBefore( fakeBody, refNode );
25
bool = div.offsetWidth === 42;
26
docElem.removeChild( fakeBody );
41
/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
48
win.respond = respond;
50
//define update even in native-mq-supporting browsers, to avoid errors
51
respond.update = function(){};
53
//expose media query support flag for external use
54
respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
56
//if media queries are supported, exit here
57
if( respond.mediaQueriesSupported ){
62
var doc = win.document,
63
docElem = doc.documentElement,
69
head = doc.getElementsByTagName( "head" )[0] || docElem,
70
base = doc.getElementsByTagName( "base" )[0],
71
links = head.getElementsByTagName( "link" ),
74
//loop stylesheets, send text content to translate
77
for( var i = 0; i < links.length; i++ ){
78
var sheet = links[ i ],
81
isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
83
//only links plz and prevent re-parsing
84
if( !!href && isCSS && !parsedSheets[ href ] ){
85
// selectivizr exposes css through the rawCssText expando
86
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
87
translate( sheet.styleSheet.rawCssText, href, media );
88
parsedSheets[ href ] = true;
90
if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
91
href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
103
//recurse through request queue, get css text
104
makeRequests = function(){
105
if( requestQueue.length ){
106
var thisRequest = requestQueue.shift();
108
ajax( thisRequest.href, function( styles ){
109
translate( styles, thisRequest.href, thisRequest.media );
110
parsedSheets[ thisRequest.href ] = true;
112
// by wrapping recursive function call in setTimeout
113
// we prevent "Stack overflow" error in IE7
114
win.setTimeout(function(){ makeRequests(); },0);
119
//find media blocks in css text, convert to style blocks
120
translate = function( styles, href, media ){
121
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
122
ql = qs && qs.length || 0;
124
//try to get CSS path
125
href = href.substring( 0, href.lastIndexOf( "/" ) );
127
var repUrls = function( css ){
128
return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
130
useMedia = !ql && media;
132
//if path exists, tack on trailing slash
133
if( href.length ){ href += "/"; }
135
//if no internal queries exist, but media attr does, use that
136
//note: this currently lacks support for situations where a media attr is specified on a link AND
137
//its associated stylesheet has internal CSS media queries.
138
//In those cases, the media attribute will currently be ignored.
143
for( var i = 0; i < ql; i++ ){
144
var fullq, thisq, eachq, eql;
149
rules.push( repUrls( styles ) );
153
fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
154
rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
157
eachq = fullq.split( "," );
160
for( var j = 0; j < eql; j++ ){
163
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
164
rules : rules.length - 1,
165
hasquery : thisq.indexOf("(") > -1,
166
minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
167
maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
179
// returns the value of 1em in pixels
180
getEmValue = function() {
182
div = doc.createElement('div'),
186
div.style.cssText = "position:absolute;font-size:1em;width:1em";
189
body = fakeUsed = doc.createElement( "body" );
190
body.style.background = "none";
193
body.appendChild( div );
195
docElem.insertBefore( body, docElem.firstChild );
197
ret = div.offsetWidth;
200
docElem.removeChild( body );
203
body.removeChild( div );
206
//also update eminpx before returning
207
ret = eminpx = parseFloat(ret);
212
//cached container for 1em value, populated the first time it's needed
215
//enable/disable styles
216
applyMedia = function( fromResize ){
217
var name = "clientWidth",
218
docElemProp = docElem[ name ],
219
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
221
lastLink = links[ links.length-1 ],
222
now = (new Date()).getTime();
224
//throttle resize calls
225
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
226
win.clearTimeout( resizeDefer );
227
resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
234
for( var i in mediastyles ){
235
if( mediastyles.hasOwnProperty( i ) ){
236
var thisstyle = mediastyles[ i ],
237
min = thisstyle.minw,
238
max = thisstyle.maxw,
239
minnull = min === null,
240
maxnull = max === null,
244
min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
247
max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
250
// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
251
if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
252
if( !styleBlocks[ thisstyle.media ] ){
253
styleBlocks[ thisstyle.media ] = [];
255
styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
260
//remove any existing respond style element(s)
261
for( var j in appendedEls ){
262
if( appendedEls.hasOwnProperty( j ) ){
263
if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
264
head.removeChild( appendedEls[ j ] );
269
//inject active styles, grouped by media type
270
for( var k in styleBlocks ){
271
if( styleBlocks.hasOwnProperty( k ) ){
272
var ss = doc.createElement( "style" ),
273
css = styleBlocks[ k ].join( "\n" );
275
ss.type = "text/css";
278
//originally, ss was appended to a documentFragment and sheets were appended in bulk.
279
//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
280
head.insertBefore( ss, lastLink.nextSibling );
282
if ( ss.styleSheet ){
283
ss.styleSheet.cssText = css;
286
ss.appendChild( doc.createTextNode( css ) );
289
//push to appendedEls to track for later removal
290
appendedEls.push( ss );
294
//tweaked Ajax functions from Quirksmode
295
ajax = function( url, callback ) {
300
req.open( "GET", url, true );
301
req.onreadystatechange = function () {
302
if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
305
callback( req.responseText );
307
if ( req.readyState === 4 ){
313
xmlHttp = (function() {
314
var xmlhttpmethod = false;
316
xmlhttpmethod = new win.XMLHttpRequest();
319
xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" );
322
return xmlhttpmethod;
329
//expose update for re-running respond later on
330
respond.update = ripCSS;
333
function callMedia(){
336
if( win.addEventListener ){
337
win.addEventListener( "resize", callMedia, false );
339
else if( win.attachEvent ){
340
win.attachEvent( "onresize", callMedia );