1/*! 2 * Modernizr JavaScript library 1.5 3 * http://www.modernizr.com/ 4 * 5 * Copyright (c) 2009-2010 Faruk Ates - http://farukat.es/ 6 * Dual-licensed under the BSD and MIT licenses. 7 * http://www.modernizr.com/license/ 8 * 9 * Featuring major contributions by 10 * Paul Irish - http://paulirish.com 11 */ 12 13/* 14 * LicenseModernizr is available under the MIT and BSD licenses: 15 16 * MIT License 17 * Copyright (c) 20092010 Faruk Ate? 18 * Permission is hereby granted, free of charge, to any person obtaining a copy 19 * of this software and associated documentation files (the "Software"), to deal 20 * in the Software without restriction, including without limitation the rights 21 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 22 * copies of the Software, and to permit persons to whom the Software is 23 * furnished to do so, subject to the following conditions: 24 25 * The above copyright notice and this permission notice shall be included in 26 * all copies or substantial portions of the Software. 27 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 34 * THE SOFTWARE. 35 36 * BSD License 37 * Copyright (c) 2010, Faruk Ate? 38 * All rights reserved. 39 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions are met: 42 * * Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * * Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * * Neither the name of the Organization nor the 48 * names of its contributors may be used to endorse or promote products 49 * derived from this software without specific prior written permission. 50 51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 53 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 54 * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY 55 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 56 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 58 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61*/ 62 63/* 64 * Modernizr is a script that will detect native CSS3 and HTML5 features 65 * available in the current UA and provide an object containing all 66 * features with a true/false value, depending on whether the UA has 67 * native support for it or not. 68 * 69 * In addition to that, Modernizr will add classes to the <html> 70 * element of the page, one for each cutting-edge feature. If the UA 71 * supports it, a class like "cssgradients" will be added. If not, 72 * the class name will be "no-cssgradients". This allows for simple 73 * if-conditionals in CSS styling, making it easily to have fine 74 * control over the look and feel of your website. 75 * 76 * @author Faruk Ates 77 * @copyright (c) 2009-2010 Faruk Ates. 78 * 79 * @contributor Paul Irish 80 * @contributor Ben Alman 81 */ 82 83window.Modernizr = (function(window,doc,undefined){ 84 85 var version = '1.5', 86 87 ret = {}, 88 89 /** 90 * enableHTML5 is a private property for advanced use only. If enabled, 91 * it will make Modernizr.init() run through a brief while() loop in 92 * which it will create all HTML5 elements in the DOM to allow for 93 * styling them in Internet Explorer, which does not recognize any 94 * non-HTML4 elements unless created in the DOM this way. 95 * 96 * enableHTML5 is ON by default. 97 */ 98 enableHTML5 = true, 99 100 101 /** 102 * fontfaceCheckDelay is the ms delay before the @font-face test is 103 * checked a second time. This is neccessary because both Gecko and 104 * WebKit do not load data: URI font data synchronously. 105 * https://bugzilla.mozilla.org/show_bug.cgi?id=512566 106 * The check will be done again at fontfaceCheckDelay*2 and then 107 * a fourth time at window's load event. 108 * If you need to query for @font-face support, send a callback to: 109 * Modernizr._fontfaceready(fn); 110 * The callback is passed the boolean value of Modernizr.fontface 111 */ 112 fontfaceCheckDelay = 75, 113 114 115 docElement = doc.documentElement, 116 117 /** 118 * Create our "modernizr" element that we do most feature tests on. 119 */ 120 mod = 'modernizr', 121 m = doc.createElement( mod ), 122 m_style = m.style, 123 124 /** 125 * Create the input element for various Web Forms feature tests. 126 */ 127 f = doc.createElement( 'input' ), 128 129 // Reused strings, stored here to allow better minification 130 131 canvas = 'canvas', 132 canvastext = 'canvastext', 133 rgba = 'rgba', 134 hsla = 'hsla', 135 multiplebgs = 'multiplebgs', 136 backgroundsize = 'backgroundsize', 137 borderimage = 'borderimage',
138 borderradius = 'borderradius', 139 boxshadow = 'boxshadow', 140 opacity = 'opacity', 141 cssanimations = 'cssanimations', 142 csscolumns = 'csscolumns', 143 cssgradients = 'cssgradients', 144 cssreflections = 'cssreflections', 145 csstransforms = 'csstransforms', 146 csstransforms3d = 'csstransforms3d', 147 csstransitions = 'csstransitions', 148 fontface = 'fontface', 149 geolocation = 'geolocation', 150 video = 'video', 151 audio = 'audio', 152 input = 'input', 153 inputtypes = input + 'types', 154 // inputtypes is an object of its own containing individual tests for 155 // various new input types, such as search, range, datetime, etc. 156 157 svg = 'svg', 158 smil = 'smil', 159 svgclippaths = svg+'clippaths', 160 161 background = 'background', 162 backgroundColor = background + 'Color', 163 canPlayType = 'canPlayType', 164 165 // FF gets really angry if you name local variables as these, but camelCased. 166 localstorage = 'localStorage', 167 sessionstorage = 'sessionStorage', 168 applicationcache = 'applicationCache', 169 170 webWorkers = 'webworkers', 171 hashchange = 'hashchange', 172 crosswindowmessaging = 'crosswindowmessaging', 173 historymanagement = 'historymanagement', 174 draganddrop = 'draganddrop', 175 websqldatabase = 'websqldatabase', 176 indexedDB = 'indexedDB', 177 websockets = 'websockets', 178 smile = ':)', 179 180 // IE7 gets mad if you name a local variable `toString` 181 tostring = Object.prototype.toString, 182 183 // list of property values to set for css tests. see ticket #21 184 prefixes = ' -o- -moz- -ms- -webkit- -khtml- '.split(' '), 185 186 tests = {}, 187 inputs = {}, 188 attrs = {}, 189 190 classes = [], 191 192 /** 193 * isEventSupported determines if a given element supports the given event 194 * function from http://yura.thinkweb2.com/isEventSupported/ 195 */ 196 isEventSupported = (function(){ 197 198 var TAGNAMES = { 199 'select':'input','change':'input', 200 'submit':'form','reset':'form', 201 'error':'img','load':'img','abort':'img' 202 }, 203 cache = { }; 204 205 function isEventSupported(eventName, element) { 206 var canCache = (arguments.length == 1); 207 208 // only return cached result when no element is given 209 if (canCache && cache[eventName]) { 210 return cache[eventName]; 211 } 212 213 element = element || document.createElement(TAGNAMES[eventName] || 'div'); 214 eventName = 'on' + eventName; 215 216 // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize" 217 // `in` "catches" those 218 var isSupported = (eventName in element); 219 220 if (!isSupported && element.setAttribute) { 221 element.setAttribute(eventName, 'return;'); 222 isSupported = typeof element[eventName] == 'function'; 223 } 224 225 element = null; 226 return canCache ? (cache[eventName] = isSupported) : isSupported; 227 } 228 229 return isEventSupported; 230 })(); 231 232 233 var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; 234 if (typeof _hasOwnProperty !== 'undefined' && typeof _hasOwnProperty.call !== 'undefined') { 235 hasOwnProperty = function (object, property) { 236 return _hasOwnProperty.call(object, property); 237 }; 238 } 239 else { 240 hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ 241 return ((property in object) && typeof object.constructor.prototype[property] === 'undefined'); 242 }; 243 } 244 245 /** 246 * set_css applies given styles to the Modernizr DOM node. 247 */ 248 function set_css( str ) { 249 m_style.cssText = str; 250 } 251 252 /** 253 * set_css_all extrapolates all vendor-specific css strings. 254 */ 255 function set_css_all( str1, str2 ) { 256 return set_css(prefixes.join(str1 + ';') + ( str2 || '' )); 257 } 258 259 /** 260 * contains returns a boolean for if substr is found within str. 261 */ 262 function contains( str, substr ) { 263 return (''+str).indexOf( substr ) !== -1; 264 } 265 266 /** 267 * test_props is a generic CSS / DOM property test; if a browser supports 268 * a certain property, it won't return undefined for it. 269 * A supported CSS property returns empty string when its not yet set.
270 */ 271 function test_props( props, callback ) { 272 for ( var i in props ) { 273 if ( m_style[ props[i] ] !== undefined && ( !callback || callback( props[i], m ) ) ) { 274 return true; 275 } 276 } 277 } 278 279 /** 280 * test_props_all tests a list of DOM properties we want to check against. 281 * We specify literally ALL possible (known and/or likely) properties on 282 * the element including the non-vendor prefixed one, for forward- 283 * compatibility. 284 */ 285 function test_props_all( prop, callback ) { 286 var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), 287 288 // following spec is to expose vendor-specific style properties as: 289 // elem.style.WebkitBorderRadius 290 // and the following would be incorrect: 291 // elem.style.webkitBorderRadius 292 // Webkit and Mozilla are nice enough to ghost their properties in the lowercase 293 // version but Opera does not. 294 295 // see more here: http://github.com/Modernizr/Modernizr/issues/issue/21 296 props = [ 297 prop, 298 'Webkit' + uc_prop, 299 'Moz' + uc_prop, 300 'O' + uc_prop, 301 'ms' + uc_prop, 302 'Khtml' + uc_prop 303 ]; 304 305 return !!test_props( props, callback ); 306 } 307 308 309 /** 310 * Tests 311 */ 312 313 tests[canvas] = function() { 314 return !!doc.createElement( canvas ).getContext; 315 }; 316 317 tests[canvastext] = function() { 318 return !!(tests[canvas]() && typeof doc.createElement( canvas ).getContext('2d').fillText == 'function'); 319 }; 320 321 /** 322 * The Modernizr.touch test only indicates if the browser supports 323 * touch events, which does not necessarily reflect a touchscreen 324 * device, as evidenced by tablets running Windows 7 or, alas, 325 * the Palm Pre / WebOS (touch) phones. 326 * Additionally, chrome used to lie about its support on this, but that 327 * has since been recitifed: http://crbug.com/36415 328 * Because there is no way to reliably detect Chrome's false positive 329 * without UA sniffing we have removed this test from Modernizr. We 330 * hope to add it in after Chrome 5 has been sunsetted. 331 * See also http://github.com/Modernizr/Modernizr/issues#issue/84 332 333 tests[touch] = function() { 334 335 return !!('ontouchstart' in window); 336 337 }; 338 */ 339 340 /** 341 * geolocation tests for the new Geolocation API specification. 342 * This test is a standards compliant-only test; for more complete 343 * testing, including a Google Gears fallback, please see: 344 * http://code.google.com/p/geo-location-javascript/ 345 * or view a fallback solution using google's geo API: 346 * http://gist.github.com/366184 347 */ 348 tests[geolocation] = function() { 349 return !!navigator.geolocation; 350 }; 351 352 tests[crosswindowmessaging] = function() { 353 return !!window.postMessage; 354 }; 355 356 tests[websqldatabase] = function() { 357 var result = !!window.openDatabase; 358 if (result){ 359 try { 360 result = !!openDatabase("testdb", "1.0", "html5 test db", 200000); 361 } catch(err) { 362 result = false; 363 } 364 } 365 return result; 366 }; 367 368 tests[indexedDB] = function(){ 369 return !!window[indexedDB]; 370 }; 371 372 // documentMode logic from YUI to filter out IE8 Compat Mode 373 // which false positives. 374 tests[hashchange] = function() { 375 return isEventSupported(hashchange, window) && ( document.documentMode === undefined || document.documentMode > 7 ); 376 }; 377 378 tests[historymanagement] = function() { 379 return !!(window.history && history.pushState); 380 }; 381 382 tests[draganddrop] = function() { 383 return isEventSupported('drag') 384 && isEventSupported('dragstart') 385 && isEventSupported('dragenter') 386 && isEventSupported('dragover') 387 && isEventSupported('dragleave') 388 && isEventSupported('dragend') 389 && isEventSupported('drop'); 390 }; 391 392 393 tests[websockets] = function(){ 394 return ('WebSocket' in window); 395 }; 396 397
398 // http://css-tricks.com/rgba-browser-support/ 399 tests[rgba] = function() { 400 // Set an rgba() color and check the returned value 401 402 set_css( background + '-color:rgba(150,255,150,.5)' ); 403 404 return contains( m_style[backgroundColor], rgba ); 405 }; 406 407 tests[hsla] = function() { 408 // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally 409 410 set_css( background + '-color:hsla(120,40%,100%,.5)' ); 411 412 return contains( m_style[backgroundColor], rgba ); 413 }; 414 415 tests[multiplebgs] = function() { 416 // Setting multiple images AND a color on the background shorthand property 417 // and then querying the style.background property value for the number of 418 // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! 419 420 set_css( background + ':url(//:),url(//:),red url(//:)' ); 421 422 // If the UA supports multiple backgrounds, there should be three occurrences 423 // of the string "url(" in the return value for elem_style.background 424 425 return new RegExp("(url\\s*\\(.*?){3}").test(m_style[background]); 426 }; 427 428 429 // In testing support for a given CSS property, it's legit to test: 430 // elem.style[styleName] !== undefined 431 // If the property is supported it will return an empty string, 432 // if unsupported it will return undefined. 433 // We'll take advantage of this quick test and skip setting a style 434 // on our modernizr element, but instead just testing undefined vs 435 // empty string. 436 // The legacy set_css_all calls will remain in the source 437 // (however, commented) in for clarity, yet functionally they are 438 // no longer needed. 439 440 441 tests[backgroundsize] = function() { 442 return test_props_all( background + 'Size' ); 443 }; 444 445 tests[borderimage] = function() { 446 // set_css_all( 'border-image:url(m.png) 1 1 stretch' ); 447 return test_props_all( 'borderImage' ); 448 }; 449 450 451 // super comprehensive table about all the unique implementations of 452 // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance 453 454 tests[borderradius] = function() { 455 // set_css_all( 'border-radius:10px' ); 456 return test_props_all( 'borderRadius', '', function( prop ) { 457 return contains( prop, 'orderRadius' ); 458 }); 459 }; 460 461 462 tests[boxshadow] = function() { 463 // set_css_all( 'box-shadow:#000 1px 1px 3px' ); 464 return test_props_all( 'boxShadow' ); 465 }; 466 467 468 tests[opacity] = function() { 469 // Browsers that actually have CSS Opacity implemented have done so 470 // according to spec, which means their return values are within the 471 // range of [0.0,1.0] - including the leading zero. 472 473 set_css_all( 'opacity:.5' ); 474 475 return contains( m_style[opacity], '0.5' ); 476 }; 477 478 479 tests[cssanimations] = function() { 480 // set_css_all( 'animation:"animate" 2s ease 2', 'position:relative' ); 481 return test_props_all( 'animationName' ); 482 }; 483 484 485 tests[csscolumns] = function() { 486 // set_css_all( 'column-count:3' ); 487 return test_props_all( 'columnCount' ); 488 }; 489 490 491 tests[cssgradients] = function() { 492 /** 493 * For CSS Gradients syntax, please see: 494 * http://webkit.org/blog/175/introducing-css-gradients/ 495 * https://developer.mozilla.org/en/CSS/-moz-linear-gradient 496 * https://developer.mozilla.org/en/CSS/-moz-radial-gradient 497 * http://dev.w3.org/csswg/css3-images/#gradients- 498 */ 499 500 var str1 = background + '-image:', 501 str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', 502 str3 = 'linear-gradient(left top,#9f9, white);'; 503 504 set_css( 505 (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0,-str1.length) 506 ); 507 508 return contains( m_style.backgroundImage, 'gradient' ); 509 }; 510 511 512 tests[cssreflections] = function() { 513 // set_css_all( 'box-reflect:right 1px' ); 514 return test_props_all( 'boxReflect' ); 515 }; 516 517 518 tests[csstransforms] = function() { 519 // set_css_all( 'transform:rotate(3deg)' ); 520 return !!test_props([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); 521 }; 522 523 524 tests[csstransforms3d] = function() { 525 // set_css_all( 'perspective:500' ); 526 527 var ret = !!test_props([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); 528 529 // webkit has 3d transforms disabled for chrome, though 530 // it works fine in safari on leopard and snow leopard 531 // as a result, it 'recognizes' the syntax and throws a false positive 532 // thus we must do a more thorough check: 533 if (ret){ 534 var st = document.createElement('style'), 535 div = doc.createElement('div'); 536 537 // webkit allows this media query to succeed only if the feature is enabled. 538 // "@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){#modernizr{height:3px}}" 539 st.textContent = '@media ('+prefixes.join('transform-3d),(')+'modernizr){#modernizr{height:3px}}'; 540 doc.getElementsByTagName('head')[0].appendChild(st); 541 div.id = 'modernizr'; 542 docElement.appendChild(div); 543 544 ret = div.offsetHeight === 3; 545 546 st.parentNode.removeChild(st); 547 div.parentNode.removeChild(div); 548 } 549 return ret; 550 }; 551 552 553 tests[csstransitions] = function() { 554 // set_css_all( 'transition:all .5s linear' ); 555 return test_props_all( 'transitionProperty' ); 556 }; 557 558 559 // @font-face detection routine created by Paul Irish - paulirish.com
560 // Merged into Modernizr with approval. Read more about Paul's work here: 561 // http://paulirish.com/2009/font-face-feature-detection/ 562 tests[fontface] = function(){ 563 564 var fontret; 565 if (/*@cc_on@if(@_jscript_version>=5)!@end@*/0) fontret = true; 566 567 else { 568 569 // Create variables for dedicated @font-face test 570 var st = doc.createElement('style'), 571 spn = doc.createElement('span'), 572 size, isFakeBody = false, body = doc.body, 573 callback, isCallbackCalled; 574 575 // The following is a font-face + glyph definition for the . character: 576 st.textContent = "@font-face{font-family:testfont;src:url('data:font/ttf;base64,AAEAAAAMAIAAAwBAT1MvMliohmwAAADMAAAAVmNtYXCp5qrBAAABJAAAANhjdnQgACICiAAAAfwAAAAEZ2FzcP//AAMAAAIAAAAACGdseWYv5OZoAAACCAAAANxoZWFk69bnvwAAAuQAAAA2aGhlYQUJAt8AAAMcAAAAJGhtdHgGDgC4AAADQAAAABRsb2NhAIQAwgAAA1QAAAAMbWF4cABVANgAAANgAAAAIG5hbWUgXduAAAADgAAABPVwb3N03NkzmgAACHgAAAA4AAECBAEsAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAACAAMDAAAAAAAAgAACbwAAAAoAAAAAAAAAAFBmRWQAAAAgqS8DM/8zAFwDMwDNAAAABQAAAAAAAAAAAAMAAAADAAAAHAABAAAAAABGAAMAAQAAAK4ABAAqAAAABgAEAAEAAgAuqQD//wAAAC6pAP///9ZXAwAAAAAAAAACAAAABgBoAAAAAAAvAAEAAAAAAAAAAAAAAAAAAAABAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEACoAAAAGAAQAAQACAC6pAP//AAAALqkA////1lcDAAAAAAAAAAIAAAAiAogAAAAB//8AAgACACIAAAEyAqoAAwAHAC6xAQAvPLIHBADtMrEGBdw8sgMCAO0yALEDAC88sgUEAO0ysgcGAfw8sgECAO0yMxEhESczESMiARDuzMwCqv1WIgJmAAACAFUAAAIRAc0ADwAfAAATFRQWOwEyNj0BNCYrASIGARQGKwEiJj0BNDY7ATIWFX8aIvAiGhoi8CIaAZIoN/43KCg3/jcoAWD0JB4eJPQkHh7++EY2NkbVRjY2RgAAAAABAEH/+QCdAEEACQAANjQ2MzIWFAYjIkEeEA8fHw8QDxwWFhwWAAAAAQAAAAIAAIuYbWpfDzz1AAsEAAAAAADFn9IuAAAAAMWf0i797/8zA4gDMwAAAAgAAgAAAAAAAAABAAADM/8zAFwDx/3v/98DiAABAAAAAAAAAAAAAAAAAAAABQF2ACIAAAAAAVUAAAJmAFUA3QBBAAAAKgAqACoAWgBuAAEAAAAFAFAABwBUAAQAAgAAAAEAAQAAAEAALgADAAMAAAAQAMYAAQAAAAAAAACLAAAAAQAAAAAAAQAhAIsAAQAAAAAAAgAFAKwAAQAAAAAAAwBDALEAAQAAAAAABAAnAPQAAQAAAAAABQAKARsAAQAAAAAABgAmASUAAQAAAAAADgAaAUsAAwABBAkAAAEWAWUAAwABBAkAAQBCAnsAAwABBAkAAgAKAr0AAwABBAkAAwCGAscAAwABBAkABABOA00AAwABBAkABQAUA5sAAwABBAkABgBMA68AAwABBAkADgA0A/tDb3B5cmlnaHQgMjAwOSBieSBEYW5pZWwgSm9obnNvbi4gIFJlbGVhc2VkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgT3BlbiBGb250IExpY2Vuc2UuIEtheWFoIExpIGdseXBocyBhcmUgcmVsZWFzZWQgdW5kZXIgdGhlIEdQTCB2ZXJzaW9uIDMuYmFlYzJhOTJiZmZlNTAzMiAtIHN1YnNldCBvZiBKdXJhTGlnaHRiYWVjMmE5MmJmZmU1MDMyIC0gc3Vic2V0IG9mIEZvbnRGb3JnZSAyLjAgOiBKdXJhIExpZ2h0IDogMjMtMS0yMDA5YmFlYzJhOTJiZmZlNTAzMiAtIHN1YnNldCBvZiBKdXJhIExpZ2h0VmVyc2lvbiAyIGJhZWMyYTkyYmZmZTUwMzIgLSBzdWJzZXQgb2YgSnVyYUxpZ2h0aHR0cDovL3NjcmlwdHMuc2lsLm9yZy9PRkwAQwBvAHAAeQByAGkAZwBoAHQAIAAyADAAMAA5ACAAYgB5ACAARABhAG4AaQBlAGwAIABKAG8AaABuAHMAbwBuAC4AIAAgAFIAZQBsAGUAYQBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAdABlAHIAbQBzACAAbwBmACAAdABoAGUAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUALgAgAEsAYQB5AGEAaAAgAEwAaQAgAGcAbAB5AHAAaABzACAAYQByAGUAIAByAGUAbABlAGEAcwBlAGQAIAB1AG4AZABlAHIAIAB0AGgAZQAgAEcAUABMACAAdgBlAHIAcwBpAG8AbgAgADMALgBiAGEAZQBjADIAYQA5ADIAYgBmAGYAZQA1ADAAMwAyACAALQAgAHMAdQBiAHMAZQB0ACAAbwBmACAASgB1AHIAYQBMAGkAZwBoAHQAYgBhAGUAYwAyAGEAOQAyAGIAZgBmAGUANQAwADMAMgAgAC0AIABzAHUAYgBzAGUAdAAgAG8AZgAgAEYAbwBuAHQARgBvAHIAZwBlACAAMgAuADAAIAA6ACAASgB1AHIAYQAgAEwAaQBnAGgAdAAgADoAIAAyADMALQAxAC0AMgAwADAAOQBiAGEAZQBjADIAYQA5ADIAYgBmAGYAZQA1ADAAMwAyACAALQAgAHMAdQBiAHMAZQB0ACAAbwBmACAASgB1AHIAYQAgAEwAaQBnAGgAdABWAGUAcgBzAGkAbwBuACAAMgAgAGIAYQBlAGMAMgBhADkAMgBiAGYAZgBlADUAMAAzADIAIAAtACAAcwB1AGIAcwBlAHQAIABvAGYAIABKAHUAcgBhAEwAaQBnAGgAdABoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAAAAAgAAAAAAAP+BADMAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAQACAQIAEQt6ZXJva2F5YWhsaQ==')}"; 577 doc.getElementsByTagName('head')[0].appendChild(st); 578 579 // we don't use `serif` and we don't use `monospace` 580 // http://github.com/Modernizr/Modernizr/issues/closed#issue/39 581 // http://neugierig.org/software/chromium/notes/2009/09/monospace-fonts-workaround.html 582 spn.setAttribute('style','font:99px _,arial,helvetica;position:absolute;visibility:hidden'); 583 584 if (!body){ 585 body = docElement.appendChild(doc.createElement(fontface)); 586 isFakeBody = true; 587 } 588 589 // the data-uri'd font only has the . glyph; which is 3 pixels wide. 590 spn.innerHTML = '........'; 591 spn.id = 'fonttest'; 592 593 body.appendChild(spn); 594 size = spn.offsetWidth*spn.offsetHeight; 595 spn.style.font = '99px testfont,_,arial,helvetica'; 596 597 // needed for the CSSFontFaceRule false positives (ff3, chrome, op9) 598 fontret = size !== spn.offsetWidth*spn.offsetHeight; 599 600 function delayedCheck(){ 601 if (!body.parentNode) return; 602 fontret = ret[fontface] = size !== spn.offsetWidth*spn.offsetHeight; 603 docElement.className = docElement.className.replace(/(no-)?fontface\b/,'') + (fontret ? ' ' : ' no-') + fontface; 604 } 605 606 setTimeout(delayedCheck,fontfaceCheckDelay); 607 setTimeout(delayedCheck,fontfaceCheckDelay*2); 608 addEventListener('load',function(){ 609 delayedCheck(); 610 (isCallbackCalled = true) && callback && callback(fontret); 611 setTimeout(function(){ 612 if (!isFakeBody) body = spn; 613 body.parentNode.removeChild(body); 614 st.parentNode.removeChild(st); 615 }, 50); 616 },false); 617 } 618 619 // allow for a callback 620 ret._fontfaceready = function(fn){ 621 (isCallbackCalled || fontret) ? fn(fontret) : (callback = fn); 622 } 623 624 return fontret || size !== spn.offsetWidth; 625 626 }; 627 628 629 // These tests evaluate support of the video/audio elements, as well as 630 // testing what types of content they support. 631 // 632 // we're using the Boolean constructor here, so that we can extend the value 633 // e.g. Modernizr.video // true 634 // Modernizr.video.ogg // 'probably' 635 // 636 // codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 637 // thx to NielsLeenheer and zcorpan 638 639 tests[video] = function() { 640 var elem = doc.createElement(video), 641 bool = !!elem[canPlayType]; 642 643 if (bool){ 644 bool = new Boolean(bool); 645 bool.ogg = elem[canPlayType]('video/ogg; codecs="theora"'); 646 bool.h264 = elem[canPlayType]('video/mp4; codecs="avc1.42E01E"'); 647 bool.webm = elem[canPlayType]('video/webm; codecs="vp8, vorbis"'); 648 } 649 return bool; 650 }; 651 652 tests[audio] = function() { 653 var elem = doc.createElement(audio), 654 bool = !!elem[canPlayType]; 655 656 if (bool){ 657 bool = new Boolean(bool); 658 bool.ogg = elem[canPlayType]('audio/ogg; codecs="vorbis"'); 659 bool.mp3 = elem[canPlayType]('audio/mpeg;'); 660 661 // mimetypes accepted: 662 // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements 663 // http://bit.ly/iphoneoscodecs 664 bool.wav = elem[canPlayType]('audio/wav; codecs="1"'); 665 bool.m4a = elem[canPlayType]('audio/x-m4a;') || elem[canPlayType]('audio/aac;'); 666 } 667 return bool; 668 }; 669 670 671 // both localStorage and sessionStorage are 672 // tested in this method because otherwise Firefox will 673 // throw an error: https://bugzilla.mozilla.org/show_bug.cgi?id=365772 674 // if cookies are disabled 675 676 // FWIW miller device resolves to [object Storage] in all supporting browsers 677 // except for IE who does [object Object] 678 679 // IE8 Compat mode supports these features completely: 680 // http://www.quirksmode.org/dom/html5.html 681 682 tests[localstorage] = function() { 683 return ('localStorage' in window) && window[localstorage] !== null; 684 }; 685 686 tests[sessionstorage] = function() { 687 // try/catch required for pissy FF behavior 688 try { 689 return ('sessionStorage' in window) && window[sessionstorage] !== null; 690 } catch(e){ 691 return false; 692 } 693 }; 694 695 696 tests[webWorkers] = function () { 697 return !!window.Worker; 698 }; 699 700 701 tests[applicationcache] = function() { 702 var cache = window[applicationcache]; 703 return !!(cache && (typeof cache.status != 'undefined') && (typeof cache.update == 'function') && (typeof cache.swapCache == 'function')); 704 }; 705 706 707 // thanks to Erik Dahlstrom 708 tests[svg] = function(){ 709 return !!doc.createElementNS && !!doc.createElementNS( "http://www.w3.org/2000/svg", "svg").createSVGRect; 710 }; 711 712 // thanks to F1lt3r and lucideer 713 // http://github.com/Modernizr/Modernizr/issues#issue/35 714 tests[smil] = function(){ 715 return !!doc.createElementNS && /SVG/.test(tostring.call(doc.createElementNS('http://www.w3.org/2000/svg','animate'))); 716 }; 717 718 tests[svgclippaths] = function(){
719 // returns a false positive in saf 3.2? 720 return !!doc.createElementNS && /SVG/.test(tostring.call(doc.createElementNS('http://www.w3.org/2000/svg','clipPath'))); 721 }; 722 723 724 // input features and input types go directly onto the ret object, bypassing the tests loop. 725 // hold this guy to execute in a moment. 726 function webforms(){ 727 728 // Run through HTML5's new input attributes to see if the UA understands any. 729 // We're using f which is the <input> element created early on 730 // Mike Taylr has created a comprehensive resource for testing these attributes 731 // when applied to all input types: 732 // http://miketaylr.com/code/input-type-attr.html 733 // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary 734 ret[input] = (function(props) { 735 for (var i = 0,len=props.length;i<len;i++) { 736 attrs[ props[i] ] = !!(props[i] in f); 737 } 738 return attrs; 739 })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); 740 741 // Run through HTML5's new input types to see if the UA understands any. 742 // This is put behind the tests runloop because it doesn't return a 743 // true/false like all the other tests; instead, it returns an object 744 // containing each input type with its corresponding true/false value 745 746 // Big thx to @miketaylr for the html5 forms expertise. http://miketaylr.com/ 747 ret[inputtypes] = (function(props) { 748 for (var i = 0,bool,len=props.length;i<len;i++) { 749 f.setAttribute('type', props[i]); 750 bool = f.type !== 'text'; 751 752 // chrome likes to falsely purport support, so we feed it a textual value 753 // if that doesnt succeed then we know there's a custom UI 754 if (bool){ 755 756 f.value = smile; 757 758 /* Safari 4 is allowing the smiley as a value, and incorrecty failing.. 759 the test fixes for webkit only, but breaks Opera.. 760 if (/range/.test(f.type)){ 761 bool = test_props_all('appearance',function(prop,m){ return m_style[prop] !== 'textfield' }) 762 } 763 */ 764 765 if (/tel|search/.test(f.type)){ 766 // spec doesnt define any special parsing or detectable UI 767 // behaviors so we pass these through as true 768 769 } else if (/url|email/.test(f.type)) { 770 // real url and email support comes with prebaked validation. 771 bool = f.checkValidity && f.checkValidity() === false; 772 773 } else { 774 bool = f.value != smile; 775 } 776 } 777 778 inputs[ props[i] ] = !!bool; 779 } 780 return inputs; 781 })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); 782 783 } 784 785 786 787 // end of test definitions 788 789 790 // Run through all tests and detect their support in the current UA. 791 // todo: hypothetically we could be doing an array of tests and use a basic loop here. 792 for ( var feature in tests ) { 793 if ( hasOwnProperty( tests, feature ) ) { 794 // run the test, throw the return value into the Modernizr, 795 // then based on that boolean, define an appropriate className 796 // and push it into an array of classes we'll join later. 797 classes.push( ( ( ret[ feature.toLowerCase() ] = tests[ feature ]() ) ? '' : 'no-' ) + feature.toLowerCase() ); 798 } 799 } 800 801 // input tests need to run. 802 if (!ret[input]) webforms(); 803 804 805 806 807 808 809 /** 810 * Addtest allows the user to define their own feature tests 811 * the result will be added onto the Modernizr object, 812 * as well as an appropriate className set on the html element 813 * 814 * @param feature - String naming the feature 815 * @param test - Function returning true if feature is supported, false if not 816 */ 817 ret.addTest = function (feature, test) { 818 feature = feature.toLowerCase(); 819 820 if (ret[ feature ]) { 821 return; // quit if you're trying to overwrite an existing test 822 } 823 test = !!(test()); 824 docElement.className += ' ' + (test ? '' : 'no-') + feature; 825 ret[ feature ] = test; 826 return ret; // allow chaining. 827 }; 828 829 /** 830 * Reset m.style.cssText to nothing to reduce memory footprint. 831 */ 832 set_css( '' ); 833 m = f = null; 834 835 // Enable HTML 5 elements for styling in IE. 836 // fyi: jscript version does not reflect trident version 837 // therefore ie9 in ie7 mode will still have a jScript v.9 838 if ( enableHTML5 && (function(){ var elem = doc.createElement("div"); 839 elem.innerHTML = "<elem></elem>"; 840 return elem.childNodes.length !== 1; })()) { 841 // iepp v1.5.1 MIT @jon_neal http://code.google.com/p/ie-print-protector/ 842 (function(p,e){function q(a,b){if(g[a])g[a].styleSheet.cssText+=b;else{var c=r[l],d=e[j]("style");d.media=a;c.insertBefore(d,c[l]);g[a]=d;q(a,b)}}function s(a,b){for(var c=new RegExp("\\b("+m+")\\b(?!.*[;}])","gi"),d=function(k){return".iepp_"+k},h=-1;++h<a.length;){b=a[h].media||b;s(a[h].imports,b);q(b,a[h].cssText.replace(c,d))}}
842function t(){for(var a,b=e.getElementsByTagName("*"),c,d,h=new RegExp("^"+m+"$","i"),k=-1;++k<b.length;)if((a=b[k])&&(d=a.nodeName.match(h))){c=new RegExp("^\\s*<"+d+"(.*)\\/"+d+">\\s*$","i");i.innerHTML=a.outerHTML.replace(/\r|\n/g," ").replace(c,a.currentStyle.display=="block"?"<div$1/div>":"<span$1/span>");c=i.childNodes[0];c.className+=" iepp_"+d;c=f[f.length]=[a,c];a.parentNode.replaceChild(c[1],c[0])}s(e.styleSheets,"all")}function u(){for(var a=-1,b;++a<f.length;)f[a][1].parentNode.replaceChild(f[a][0],f[a][1]);for(b in g)r[l].removeChild(g[b]);g={};f=[]}for(var r=e.documentElement,i=e.createDocumentFragment(),g={},m="abbr|article|aside|audio|canvas|command|datalist|details|figure|figcaption|footer|header|hgroup|keygen|mark|meter|nav|output|progress|section|source|summary|time|video",n=m.split("|"),f=[],o=-1,l="firstChild",j="createElement";++o<n.length;){e[j](n[o]);i[j](n[o])}i=i.appendChild(e[j]("div"));p.attachEvent("onbeforeprint",t);p.attachEvent("onafterprint",u)})(this,doc); 843 } 844 845 // Assign private properties to the return object with prefix 846 ret._enableHTML5 = enableHTML5; 847 ret._version = version; 848 849 // Remove "no-js" class from <html> element, if it exists: 850 docElement.className=docElement.className.replace(/\bno-js\b/,'') + ' js'; 851 852 // Add the new classes to the <html> element. 853 docElement.className += ' ' + classes.join( ' ' ); 854 855 return ret; 856 857})(this,this.document);
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.