1/* MediaMatch v.2.0.2 - Testing css media queries in Javascript. Authors & copyright (c) 2013: WebLinc, David Knight. */ 2//https://github.com/weblinc/media-match 3 4window.matchMedia || (window.matchMedia = function (win) { 5 'use strict'; 6 7 // Internal globals 8 var _doc = win.document, 9 _viewport = _doc.documentElement, 10 _queries = [], 11 _queryID = 0, 12 _type = '', 13 _features = {}, 14 // only screen 15 // only screen and 16 // not screen 17 // not screen and 18 // screen 19 // screen and 20 _typeExpr = /\s*(only|not)?\s*(screen|print|[a-z\-]+)\s*(and)?\s*/i, 21 // (-vendor-min-width: 300px) 22 // (min-width: 300px) 23 // (width: 300px) 24 // (width) 25 // (orientation: portrait|landscape) 26 _mediaExpr = /^\s*\(\s*(-[a-z]+-)?(min-|max-)?([a-z\-]+)\s*(:?\s*([0-9]+(\.[0-9]+)?|portrait|landscape)(px|em|dppx|dpcm|rem|%|in|cm|mm|ex|pt|pc|\/([0-9]+(\.[0-9]+)?))?)?\s*\)\s*$/, 27 _timer = 0, 28 29 // Helper methods 30 31 /* 32 _matches 33 */ 34 _matches = function (media) { 35 // screen and (min-width: 400px), screen and (max-width: 500px) 36 var mql = (media.indexOf(',') !== -1 && media.split(',')) || [media], 37 mqIndex = mql.length - 1, 38 mqLength = mqIndex, 39 mq = null, 40 41 // not screen, screen 42 negateType = null, 43 negateTypeFound = '', 44 negateTypeIndex = 0, 45 negate = false, 46 type = '', 47 48 // (min-width: 400px), (min-width) 49 exprListStr = '', 50 exprList = null, 51 exprIndex = 0, 52 exprLength = 0, 53 expr = null, 54 55 prefix = '', 56 length = '', 57 unit = '', 58 value = '', 59 feature = '', 60 61 match = false; 62 63 if (media === '') { 64 return true; 65 } 66 67 do { 68 mq = mql[mqLength - mqIndex]; 69 negate = false; 70 negateType = mq.match(_typeExpr); 71 72 if (negateType) { 73 negateTypeFound = negateType[0]; 74 negateTypeIndex = negateType.index; 75 } 76 77 if (!negateType || ((mq.substring(0, negateTypeIndex).indexOf('(') === -1) && (negateTypeIndex || (!negateType[3] && negateTypeFound !== negateType.input)))) { 78 match = false; 79 continue; 80 } 81 82 exprListStr = mq; 83 84 negate = negateType[1] === 'not'; 85 86 if (!negateTypeIndex) { 87 type = negateType[2]; 88 exprListStr = mq.substring(negateTypeFound.length); 89 } 90 91 // Test media type 92 // Test type against this device or if 'all' or empty '' 93 match = type === _type || type === 'all' || type === ''; 94 95 exprList = (exprListStr.indexOf(' and ') !== -1 && exprListStr.split(' and ')) || [exprListStr]; 96 exprIndex = exprList.length - 1; 97 exprLength = exprIndex; 98 99 if (match && exprIndex >= 0 && exprListStr !== '') { 100 do { 101 expr = exprList[exprIndex].match(_mediaExpr); 102 103 if (!expr || !_features[expr[3]]) { 104 match = false; 105 break; 106 } 107 108 prefix = expr[2]; 109 length = expr[5]; 110 value = length; 111 unit = expr[7]; 112 feature = _features[expr[3]]; 113 114 // Convert unit types 115 if (unit) { 116 if (unit === 'px') { 117 // If unit is px 118 value = Number(length); 119 } else if (unit === 'em' || unit === 'rem') { 120 // Convert relative length unit to pixels 121 // Assumed base font size is 16px 122 value = 16 * length; 123 } else if (expr[8]) { 124 // Convert aspect ratio to decimal 125 value = (length / expr[8]).toFixed(2); 126 } else if (unit === 'dppx') { 127 // Convert resolution dppx unit to pixels 128 value = length * 96; 129 } else if (unit === 'dpcm') { 130 // Convert resolution dpcm unit to pixels 131 value = length * 0.3937; 132 } else { 133 // default 134 value = Number(length); 135 } 136 } 137 138 // Test for prefix min or max 139 // Test value against feature 140 if (prefix === 'min-' && value) { 141 match = feature >= value; 142 } else if (prefix === 'max-' && value) { 143 match = feature <= value; 144 } else if (value) { 145 match = feature === value; 146 } else { 147 match = !!feature; 148 } 149 150 // If 'match' is false, break loop 151 // Continue main loop through query list 152 if (!match) { 153 break; 154 } 155 } while (exprIndex--); 156 } 157 158 // If match is true, break loop 159 // Once matched, no need to check other queries 160 if (match) { 161 break; 162 } 163 } while (mqIndex--); 164 165 return negate ? !match : match; 166 }, 167 168 /* 169 _setFeature 170 */ 171 _setFeature = function () { 172 // Sets properties of '_features' that change on resize and/or orientation. 173 var w = win.innerWidth || _viewport.clientWidth, 174 h = win.innerHeight || _viewport.clientHeight, 175 dw = win.screen.width, 176 dh = win.screen.height, 177 c = win.screen.colorDepth, 178 x = win.devicePixelRatio; 179 180 _features.width = w; 181 _features.height = h; 182 _features['aspect-ratio'] = (w / h).toFixed(2); 183 _features['device-width'] = dw; 184 _features['device-height'] = dh; 185 _features['device-aspect-ratio'] = (dw / dh).toFixed(2); 186 _features.color = c; 187 _features['color-index'] = Math.pow(2, c); 188 _features.orientation = (h >= w ? 'portrait' : 'landscape'); 189 _features.resolution = (x && x * 96) || win.screen.deviceXDPI || 96; 190 _features['device-pixel-ratio'] = x || 1; 191 }, 192 193 /* 194 _watch 195 */ 196 _watch = function () { 197 clearTimeout(_timer); 198 199 _timer = setTimeout(function () { 200 var query = null, 201 qIndex = _queryID - 1, 202 qLength = qIndex, 203 match = false; 204 205 if (qIndex >= 0) { 206 _setFeature(); 207 208 do { 209 query = _queries[qLength - qIndex]; 210 211 if (query) { 212 match = _matches(query.mql.media); 213 214 if ((match && !query.mql.matches) || (!match && query.mql.matches)) { 215 query.mql.matches = match; 216 217 if (query.listeners) { 218 for (var i = 0, il = query.listeners.length; i < il; i++) { 219 if (query.listeners[i]) { 220 query.listeners[i].call(win, query.mql); 221 } 222 } 223 } 224 } 225 } 226 } while(qIndex--); 227 } 228 229 230 }, 10); 231 }, 232 233 /* 234 _init 235 */ 236 _init = function () { 237 var head = _doc.getElementsByTagName('head')[0], 238 style = _doc.createElement('style'), 239 info = null, 240 typeList = ['screen', 'print', 'speech', 'projection', 'handheld', 'tv', 'braille', 'embossed', 'tty'], 241 typeIndex = 0, 242 typeLength = typeList.length, 243 cssText = '#mediamatchjs { position: relative; z-index: 0; }', 244 eventPrefix = '', 245 addEvent = win.addEventListener || (eventPrefix = 'on') && win.attachEvent; 246 247 style.type = 'text/css'; 248 style.id = 'mediamatchjs'; 249 250 head.appendChild(style); 251 252 // Must be placed after style is inserted into the DOM for IE 253 info = (win.getComputedStyle && win.getComputedStyle(style)) || style.currentStyle; 254 255 // Create media blocks to test for media type 256 for ( ; typeIndex < typeLength; typeIndex++) { 257 cssText += '@media ' + typeList[typeIndex] + ' { #mediamatchjs { position: relative; z-index: ' + typeIndex + ' } }'; 258 } 259 260 // Add rules to style element 261 if (style.styleSheet) { 262 style.styleSheet.cssText = cssText; 263 } else { 264 style.textContent = cssText; 265 } 266 267 // Get media type 268 _type = typeList[(info.zIndex * 1) || 0]; 269 270 head.removeChild(style); 271 272 _setFeature(); 273 274 // Set up listeners 275 addEvent(eventPrefix + 'resize', _watch); 276 addEvent(eventPrefix + 'orientationchange', _watch); 277 }; 278 279 _init(); 280 281 /* 282 A list of parsed media queries, ex. screen and (max-width: 400px), screen and (max-width: 800px) 283 */ 284 return function (media) { 285 var id = _queryID, 286 mql = { 287 matches : false, 288 media : media, 289 addListener : function addListener(listener) { 290 _queries[id].listeners || (_queries[id].listeners = []); 291 listener && _queries[id].listeners.push(listener); 292 }, 293 removeListener : function removeListener(listener) { 294 var query = _queries[id], 295 i = 0, 296 il = 0; 297 298 if (!query) { 299 return; 300 } 301 302 il = query.listeners.length; 303 304 for ( ; i < il; i++) { 305 if (query.listeners[i] === listener) { 306 query.listeners.splice(i, 1); 307 } 308 } 309 } 310 }; 311 312 if (media === '') { 313 mql.matches = true; 314 return mql; 315 } 316 317 mql.matches = _matches(media); 318 319 _queryID = _queries.push({ 320 mql : mql, 321 listeners : null 322 }); 323 324 return mql; 325 }; 326}(window));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.