1/*! 2 * modernizr v3.6.0 3 * Build https://modernizr.com/download?-webp-webpalpha-dontmin 4 * 5 * Copyright (c) 6 * Faruk Ates 7 * Paul Irish 8 * Alex Sexton 9 * Ryan Seddon 10 * Patrick Kettner 11 * Stu Cox 12 * Richard Herrera 13 14 * MIT License 15 */ 16 17/* 18 * Modernizr tests which native CSS3 and HTML5 features are available in the 19 * current UA and makes the results available to you in two ways: as properties on 20 * a global `Modernizr` object, and as classes on the `<html>` element. This 21 * information allows you to progressively enhance your pages with a granular level 22 * of control over the experience. 23*/ 24 25;(function(window, document, undefined){ 26 var tests = []; 27 28 29 /** 30 * 31 * ModernizrProto is the constructor for Modernizr 32 * 33 * @class 34 * @access public 35 */ 36 37 var ModernizrProto = { 38 // The current version, dummy 39 _version: '3.6.0', 40 41 // Any settings that don't work as separate modules 42 // can go in here as configuration. 43 _config: { 44 'classPrefix': '', 45 'enableClasses': true, 46 'enableJSClass': true, 47 'usePrefixes': true 48 }, 49 50 // Queue of tests 51 _q: [], 52 53 // Stub these for people who are listening 54 on: function(test, cb) { 55 // I don't really think people should do this, but we can 56 // safe guard it a bit. 57 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 58 // This is in case people listen to synchronous tests. I would leave it out, 59 // but the code to *disallow* sync tests in the real version of this 60 // function is actually larger than this. 61 var self = this; 62 setTimeout(function() { 63 cb(self[test]); 64 }, 0); 65 }, 66 67 addTest: function(name, fn, options) { 68 tests.push({name: name, fn: fn, options: options}); 69 }, 70 71 addAsyncTest: function(fn) { 72 tests.push({name: null, fn: fn}); 73 } 74 }; 75 76 77 78 // Fake some of Object.create so we can force non test results to be non "own" properties. 79 var Modernizr = function() {}; 80 Modernizr.prototype = ModernizrProto; 81 82 // Leak modernizr globally when you `require` it rather than force it here. 83 // Overwrite name so constructor name is nicer :D 84 Modernizr = new Modernizr(); 85 86 87 88 var classes = []; 89 90 91 /** 92 * is returns a boolean if the typeof an obj is exactly type. 93 * 94 * @access private 95 * @function is 96 * @param {*} obj - A thing we want to check the type of 97 * @param {string} type - A string to compare the typeof against 98 * @returns {boolean} 99 */ 100 101 function is(obj, type) { 102 return typeof obj === type; 103 } 104 ; 105 106 /** 107 * Run through all tests and detect their support in the current UA. 108 * 109 * @access private 110 */ 111 112 function testRunner() { 113 var featureNames; 114 var feature; 115 var aliasIdx; 116 var result; 117 var nameIdx; 118 var featureName; 119 var featureNameSplit; 120 121 for (var featureIdx in tests) { 122 if (tests.hasOwnProperty(featureIdx)) { 123 featureNames = []; 124 feature = tests[featureIdx]; 125 // run the test, throw the return value into the Modernizr, 126 // then based on that boolean, define an appropriate className 127 // and push it into an array of classes we'll join later. 128 // 129 // If there is no name, it's an 'async' test that is run, 130 // but not directly added to the object. That should 131 // be done with a post-run addTest call. 132 if (feature.name) { 133 featureNames.push(feature.name.toLowerCase()); 134 135 if (feature.options && feature.options.aliases && feature.options.aliases.length) { 136 // Add all the aliases into the names list 137 for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) { 138 featureNames.push(feature.options.aliases[aliasIdx].toLowerCase()); 139 } 140 } 141 } 142 143 // Run the test, or use the raw value if it's not a function 144 result = is(feature.fn, 'function') ? feature.fn() : feature.fn; 145 146 147 // Set each of the names on the Modernizr object 148 for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { 149 featureName = featureNames[nameIdx];
150 // Support dot properties as sub tests. We don't do checking to make sure 151 // that the implied parent tests have been added. You must call them in 152 // order (either in the test, or make the parent test a dependency). 153 // 154 // Cap it to TWO to make the logic simple and because who needs that kind of subtesting 155 // hashtag famous last words 156 featureNameSplit = featureName.split('.'); 157 158 if (featureNameSplit.length === 1) { 159 Modernizr[featureNameSplit[0]] = result; 160 } else { 161 // cast to a Boolean, if not one already 162 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 163 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 164 } 165 166 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 167 } 168 169 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 170 } 171 } 172 } 173 } 174 ; 175 176 /** 177 * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support 178 * 179 * @author kangax 180 * @access private 181 * @function hasOwnProp 182 * @param {object} object - The object to check for a property 183 * @param {string} property - The property to check for 184 * @returns {boolean} 185 */ 186 187 // hasOwnProperty shim by kangax needed for Safari 2.0 support 188 var hasOwnProp; 189 190 (function() { 191 var _hasOwnProperty = ({}).hasOwnProperty; 192 /* istanbul ignore else */ 193 /* we have no way of testing IE 5.5 or safari 2, 194 * so just assume the else gets hit */ 195 if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) { 196 hasOwnProp = function(object, property) { 197 return _hasOwnProperty.call(object, property); 198 }; 199 } 200 else { 201 hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ 202 return ((property in object) && is(object.constructor.prototype[property], 'undefined')); 203 }; 204 } 205 })(); 206 207 208 209 /** 210 * docElement is a convenience wrapper to grab the root element of the document 211 * 212 * @access private 213 * @returns {HTMLElement|SVGElement} The root element of the document 214 */ 215 216 var docElement = document.documentElement; 217 218 219 /** 220 * A convenience helper to check if the document we are running in is an SVG document 221 * 222 * @access private 223 * @returns {boolean} 224 */ 225 226 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 227 228 229 /** 230 * setClasses takes an array of class names and adds them to the root element 231 * 232 * @access private 233 * @function setClasses 234 * @param {string[]} classes - Array of class names 235 */ 236 237 // Pass in an and array of class names, e.g.:
238 // ['no-webp', 'borderradius', ...] 239 function setClasses(classes) { 240 var className = docElement.className; 241 var classPrefix = Modernizr._config.classPrefix || ''; 242 243 if (isSVG) { 244 className = className.baseVal; 245 } 246 247 // Change `no-js` to `js` (independently of the `enableClasses` option) 248 // Handle classPrefix on this too 249 if (Modernizr._config.enableJSClass) { 250 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 251 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 252 } 253 254 if (Modernizr._config.enableClasses) { 255 // Add the new classes 256 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 257 if (isSVG) { 258 docElement.className.baseVal = className; 259 } else { 260 docElement.className = className; 261 } 262 } 263 264 } 265 266 ; 267 268 269 // _l tracks listeners for async tests, as well as tests that execute after the initial run 270 ModernizrProto._l = {}; 271 272 /** 273 * Modernizr.on is a way to listen for the completion of async tests. Being 274 * asynchronous, they may not finish before your scripts run. As a result you 275 * will get a possibly false negative `undefined` value. 276 * 277 * @memberof Modernizr 278 * @name Modernizr.on 279 * @access public 280 * @function on 281 * @param {string} feature - String name of the feature detect 282 * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not 283 * @example 284 * 285 * ```js 286 * Modernizr.on('flash', function( result ) { 287 * if (result) { 288 * // the browser has flash 289 * } else { 290 * // the browser does not have flash 291 * } 292 * }); 293 * ``` 294 */ 295 296 ModernizrProto.on = function(feature, cb) { 297 // Create the list of listeners if it doesn't exist 298 if (!this._l[feature]) { 299 this._l[feature] = []; 300 } 301 302 // Push this test on to the listener list 303 this._l[feature].push(cb); 304 305 // If it's already been resolved, trigger it on next tick 306 if (Modernizr.hasOwnProperty(feature)) { 307 // Next Tick 308 setTimeout(function() { 309 Modernizr._trigger(feature, Modernizr[feature]); 310 }, 0); 311 } 312 }; 313 314 /** 315 * _trigger is the private function used to signal test completion and run any 316 * callbacks registered through [Modernizr.on](#modernizr-on) 317 * 318 * @memberof Modernizr 319 * @name Modernizr._trigger 320 * @access private 321 * @function _trigger 322 * @param {string} feature - string name of the feature detect 323 * @param {function|boolean} [res] - A feature detection function, or the boolean = 324 * result of a feature detection function 325 */ 326 327 ModernizrProto._trigger = function(feature, res) { 328 if (!this._l[feature]) { 329 return; 330 } 331 332 var cbs = this._l[feature]; 333 334 // Force async 335 setTimeout(function() { 336 var i, cb; 337 for (i = 0; i < cbs.length; i++) { 338 cb = cbs[i]; 339 cb(res); 340 } 341 }, 0); 342 343 // Don't trigger these again 344 delete this._l[feature]; 345 }; 346 347 /** 348 * addTest allows you to define your own feature detects that are not currently 349 * included in Modernizr (under the covers it's the exact same code Modernizr 350 * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result 351 * will be added onto the Modernizr object, as well as an appropriate className set on 352 * the html element when configured to do so 353 * 354 * @memberof Modernizr 355 * @name Modernizr.addTest 356 * @optionName Modernizr.addTest() 357 * @optionProp addTest 358 * @access public 359 * @function addTest 360 * @param {string|object} feature - The string name of the feature detect, or an 361 * object of feature detect names and test 362 * @param {function|boolean} test - Function returning true if feature is supported, 363 * false if not. Otherwise a boolean representing the results of a feature detection 364 * @example 365 * 366 * The most common way of creating your own feature detects is by calling 367 * `Modernizr.addTest` with a string (preferably just lowercase, without any 368 * punctuation), and a function you want executed that will return a boolean result 369 * 370 * ```js 371 * Modernizr.addTest('itsTuesday', function() { 372 * var d = new Date(); 373 * return d.getDay() === 2; 374 * }); 375 * ``` 376 * 377 * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday, 378 * and to `false` every other day of the week. One thing to notice is that the names of 379 * feature detect functions are always lowercased when added to the Modernizr object. That 380 * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will. 381 * 382 * 383 * Since we only look at the returned value from any feature detection function, 384 * you do not need to actually use a function. For simple detections, just passing 385 * in a statement that will return a boolean value works just fine. 386 * 387 * ```js 388 * Modernizr.addTest('hasJquery', 'jQuery' in window); 389 * ``` 390 * 391 * Just like before, when the above runs `Modernizr.hasjquery` will be true if 392 * jQuery has been included on the page. Not using a function saves a small amount
393 * of overhead for the browser, as well as making your code much more readable. 394 * 395 * Finally, you also have the ability to pass in an object of feature names and 396 * their tests. This is handy if you want to add multiple detections in one go. 397 * The keys should always be a string, and the value can be either a boolean or 398 * function that returns a boolean. 399 * 400 * ```js 401 * var detects = { 402 * 'hasjquery': 'jQuery' in window, 403 * 'itstuesday': function() { 404 * var d = new Date(); 405 * return d.getDay() === 2; 406 * } 407 * } 408 * 409 * Modernizr.addTest(detects); 410 * ``` 411 * 412 * There is really no difference between the first methods and this one, it is 413 * just a convenience to let you write more readable code. 414 */ 415 416 function addTest(feature, test) { 417 418 if (typeof feature == 'object') { 419 for (var key in feature) { 420 if (hasOwnProp(feature, key)) { 421 addTest(key, feature[ key ]); 422 } 423 } 424 } else { 425 426 feature = feature.toLowerCase(); 427 var featureNameSplit = feature.split('.'); 428 var last = Modernizr[featureNameSplit[0]]; 429 430 // Again, we don't check for parent test existence. Get that right, though. 431 if (featureNameSplit.length == 2) { 432 last = last[featureNameSplit[1]]; 433 } 434 435 if (typeof last != 'undefined') { 436 // we're going to quit if you're trying to overwrite an existing test 437 // if we were to allow it, we'd do this: 438 // var re = new RegExp("\\b(no-)?" + feature + "\\b"); 439 // docElement.className = docElement.className.replace( re, '' ); 440 // but, no rly, stuff 'em. 441 return Modernizr; 442 } 443 444 test = typeof test == 'function' ? test() : test; 445 446 // Set the value (this is the magic, right here). 447 if (featureNameSplit.length == 1) { 448 Modernizr[featureNameSplit[0]] = test; 449 } else { 450 // cast to a Boolean, if not one already 451 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 452 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 453 } 454 455 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test; 456 } 457 458 // Set a single class (either `feature` or `no-feature`) 459 setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]); 460 461 // Trigger the event 462 Modernizr._trigger(feature, test); 463 } 464 465 return Modernizr; // allow chaining. 466 } 467 468 // After all the tests are run, add self to the Modernizr prototype 469 Modernizr._q.push(function() { 470 ModernizrProto.addTest = addTest; 471 }); 472 473 474 475/*! 476{ 477 "name": "Webp Alpha", 478 "async": true, 479 "property": "webpalpha", 480 "aliases": ["webp-alpha"], 481 "tags": ["image"], 482 "authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"], 483 "notes": [{ 484 "name": "WebP Info", 485 "href": "https://developers.google.com/speed/webp/" 486 },{ 487 "name": "Article about WebP support on Android browsers", 488 "href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/" 489 },{ 490 "name": "Chromium WebP announcement", 491 "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1" 492 }] 493} 494!*/ 495/* DOC 496Tests for transparent webp support. 497*/ 498 499 Modernizr.addAsyncTest(function() { 500 var image = new Image(); 501 502 image.onerror = function() { 503 addTest('webpalpha', false, {aliases: ['webp-alpha']}); 504 }; 505 506 image.onload = function() { 507 addTest('webpalpha', image.width == 1, {aliases: ['webp-alpha']}); 508 }; 509 510 image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA=='; 511 }); 512 513/*! 514{ 515 "name": "Webp", 516 "async": true, 517 "property": "webp", 518 "tags": ["image"], 519 "builderAliases": ["img_webp"], 520 "authors": ["Krister Kari", "@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"], 521 "notes": [{ 522 "name": "Webp Info", 523 "href": "https://developers.google.com/speed/webp/" 524 }, { 525 "name": "Chormium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input", 526 "href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html" 527 }, { 528 "name": "Webp Lossless Spec", 529 "href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification" 530 }, { 531 "name": "Article about WebP support on Android browsers", 532 "href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/" 533 }, { 534 "name": "Chormium WebP announcement", 535 "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1" 536 }] 537} 538!*/ 539/* DOC 540Tests for lossy, non-alpha webp support. 541 542Tests for all forms of webp support (lossless, lossy, alpha, and animated).. 543 544 Modernizr.webp // Basic support (lossy) 545 Modernizr.webp.lossless // Lossless 546 Modernizr.webp.alpha // Alpha (both lossy and lossless) 547 Modernizr.webp.animation // Animated WebP 548 549*/ 550 551 552 Modernizr.addAsyncTest(function() { 553 554 var webpTests = [{ 555 'uri': 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=', 556 'name': 'webp' 557 }, {
558 'uri': 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==', 559 'name': 'webp.alpha' 560 }, { 561 'uri': 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA', 562 'name': 'webp.animation' 563 }, { 564 'uri': 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=', 565 'name': 'webp.lossless' 566 }]; 567 568 var webp = webpTests.shift(); 569 function test(name, uri, cb) { 570 571 var image = new Image(); 572 573 function addResult(event) { 574 // if the event is from 'onload', check the see if the image's width is 575 // 1 pixel (which indiciates support). otherwise, it fails 576 577 var result = event && event.type === 'load' ? image.width == 1 : false; 578 var baseTest = name === 'webp'; 579 580 // if it is the base test, and the result is false, just set a literal false 581 // rather than use the Boolean contrsuctor 582 addTest(name, (baseTest && result) ? new Boolean(result) : result); 583 584 if (cb) { 585 cb(event); 586 } 587 } 588 589 image.onerror = addResult; 590 image.onload = addResult; 591 592 image.src = uri; 593 } 594 595 // test for webp support in general 596 test(webp.name, webp.uri, function(e) { 597 // if the webp test loaded, test everything else. 598 if (e && e.type === 'load') { 599 for (var i = 0; i < webpTests.length; i++) { 600 test(webpTests[i].name, webpTests[i].uri); 601 } 602 } 603 }); 604 605 }); 606 607 608 609 // Run each test 610 testRunner(); 611 612 delete ModernizrProto.addTest; 613 delete ModernizrProto.addAsyncTest; 614 615 // Run the things that are supposed to run after the tests 616 for (var i = 0; i < Modernizr._q.length; i++) { 617 Modernizr._q[i](); 618 } 619 620 // Leak Modernizr namespace 621 window.Modernizr = Modernizr; 622 623 624; 625 626})(window, 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.