1//FIX EXTERNAL SVG THING 2var ajax = new XMLHttpRequest(); 3ajax.open("GET", "../images/defs.svg", true); 4ajax.send(); 5ajax.onload = function(e) { 6 var div = document.createElement("div"); 7 div.innerHTML = ajax.responseText; 8 var svg = div.firstChild; 9 document.body.insertBefore(svg, document.body.childNodes[0]); 10}; 11;/*! 12 * modernizr v3.6.0 13 * Build https://modernizr.com/download?-backgroundblendmode-backgroundsize-borderradius-cookies-cssanimations-csscalc-cssfilters-cssgradients-cssinvalid-cssremunit-csstransforms-csstransforms3d-csstransitions-cssvhunit-cssvwunit-eventlistener-filereader-filesystem-flexbox-fontface-fullscreen-hiddenscroll-inlinesvg-input-inputtypes-json-opacity-shapes-smil-stylescoped-svg-svgasimg-svgclippaths-svgfilters-svgforeignobject-textshadow-touchevents-video-videoautoplay-setclasses-dontmin 14 * 15 * Copyright (c) 16 * Faruk Ates 17 * Paul Irish 18 * Alex Sexton 19 * Ryan Seddon 20 * Patrick Kettner 21 * Stu Cox 22 * Richard Herrera 23 24 * MIT License 25 */ 26 27/* 28 * Modernizr tests which native CSS3 and HTML5 features are available in the 29 * current UA and makes the results available to you in two ways: as properties on 30 * a global `Modernizr` object, and as classes on the `<html>` element. This 31 * information allows you to progressively enhance your pages with a granular level 32 * of control over the experience. 33*/ 34 35;(function(window, document, undefined){ 36 var tests = []; 37 38 39 /** 40 * 41 * ModernizrProto is the constructor for Modernizr 42 * 43 * @class 44 * @access public 45 */ 46 47 var ModernizrProto = { 48 // The current version, dummy 49 _version: '3.6.0', 50 51 // Any settings that don't work as separate modules 52 // can go in here as configuration. 53 _config: { 54 'classPrefix': '', 55 'enableClasses': true, 56 'enableJSClass': true, 57 'usePrefixes': true 58 }, 59 60 // Queue of tests 61 _q: [], 62 63 // Stub these for people who are listening 64 on: function(test, cb) { 65 // I don't really think people should do this, but we can 66 // safe guard it a bit. 67 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 68 // This is in case people listen to synchronous tests. I would leave it out, 69 // but the code to *disallow* sync tests in the real version of this 70 // function is actually larger than this. 71 var self = this; 72 setTimeout(function() { 73 cb(self[test]); 74 }, 0); 75 }, 76 77 addTest: function(name, fn, options) { 78 tests.push({name: name, fn: fn, options: options}); 79 }, 80 81 addAsyncTest: function(fn) { 82 tests.push({name: null, fn: fn}); 83 } 84 }; 85 86 87 88 // Fake some of Object.create so we can force non test results to be non "own" properties. 89 var Modernizr = function() {}; 90 Modernizr.prototype = ModernizrProto; 91 92 // Leak modernizr globally when you `require` it rather than force it here. 93 // Overwrite name so constructor name is nicer :D 94 Modernizr = new Modernizr(); 95 96 97 98 var classes = []; 99 100 101 /** 102 * is returns a boolean if the typeof an obj is exactly type. 103 * 104 * @access private 105 * @function is 106 * @param {*} obj - A thing we want to check the type of 107 * @param {string} type - A string to compare the typeof against 108 * @returns {boolean} 109 */ 110 111 function is(obj, type) { 112 return typeof obj === type; 113 } 114 ; 115 116 /** 117 * Run through all tests and detect their support in the current UA. 118 * 119 * @access private 120 */ 121 122 function testRunner() { 123 var featureNames; 124 var feature; 125 var aliasIdx; 126 var result; 127 var nameIdx; 128 var featureName; 129 var featureNameSplit; 130 131 for (var featureIdx in tests) { 132 if (tests.hasOwnProperty(featureIdx)) { 133 featureNames = []; 134 feature = tests[featureIdx]; 135 // run the test, throw the return value into the Modernizr, 136 // then based on that boolean, define an appropriate className 137 // and push it into an array of classes we'll join later. 138 // 139 // If there is no name, it's an 'async' test that is run, 140 // but not directly added to the object. That should 141 // be done with a post-run addTest call. 142 if (feature.name) { 143 featureNames.push(feature.name.toLowerCase()); 144 145 if (feature.options && feature.options.aliases && feature.options.aliases.length) { 146 // Add all the aliases into the names list 147 for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) { 148 featureNames.push(feature.options.aliases[aliasIdx].toLowerCase()); 149 } 150 } 151 } 152 153 // Run the test, or use the raw value if it's not a function 154 result = is(feature.fn, 'function') ? feature.fn() : feature.fn; 155 156 157 // Set each of the names on the Modernizr object 158 for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { 159 featureName = featureNames[nameIdx];
160 // Support dot properties as sub tests. We don't do checking to make sure 161 // that the implied parent tests have been added. You must call them in 162 // order (either in the test, or make the parent test a dependency). 163 // 164 // Cap it to TWO to make the logic simple and because who needs that kind of subtesting 165 // hashtag famous last words 166 featureNameSplit = featureName.split('.'); 167 168 if (featureNameSplit.length === 1) { 169 Modernizr[featureNameSplit[0]] = result; 170 } else { 171 // cast to a Boolean, if not one already 172 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 173 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 174 } 175 176 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 177 } 178 179 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 180 } 181 } 182 } 183 } 184 ; 185 186 /** 187 * docElement is a convenience wrapper to grab the root element of the document 188 * 189 * @access private 190 * @returns {HTMLElement|SVGElement} The root element of the document 191 */ 192 193 var docElement = document.documentElement; 194 195 196 /** 197 * A convenience helper to check if the document we are running in is an SVG document 198 * 199 * @access private 200 * @returns {boolean} 201 */ 202 203 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 204 205 206 /** 207 * setClasses takes an array of class names and adds them to the root element 208 * 209 * @access private 210 * @function setClasses 211 * @param {string[]} classes - Array of class names 212 */ 213 214 // Pass in an and array of class names, e.g.:
215 // ['no-webp', 'borderradius', ...] 216 function setClasses(classes) { 217 var className = docElement.className; 218 var classPrefix = Modernizr._config.classPrefix || ''; 219 220 if (isSVG) { 221 className = className.baseVal; 222 } 223 224 // Change `no-js` to `js` (independently of the `enableClasses` option) 225 // Handle classPrefix on this too 226 if (Modernizr._config.enableJSClass) { 227 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 228 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 229 } 230 231 if (Modernizr._config.enableClasses) { 232 // Add the new classes 233 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 234 if (isSVG) { 235 docElement.className.baseVal = className; 236 } else { 237 docElement.className = className; 238 } 239 } 240 241 } 242 243 ; 244/*! 245{ 246 "name": "Cookies", 247 "property": "cookies", 248 "tags": ["storage"], 249 "authors": ["tauren"] 250} 251!*/ 252/* DOC 253Detects whether cookie support is enabled. 254*/ 255 256 // https://github.com/Modernizr/Modernizr/issues/191 257 258 Modernizr.addTest('cookies', function() { 259 // navigator.cookieEnabled cannot detect custom or nuanced cookie blocking 260 // configurations. For example, when blocking cookies via the Advanced 261 // Privacy Settings in IE9, it always returns true. And there have been 262 // issues in the past with site-specific exceptions. 263 // Don't rely on it. 264 265 // try..catch because some in situations `document.cookie` is exposed but throws a 266 // SecurityError if you try to access it; e.g. documents created from data URIs 267 // or in sandboxed iframes (depending on flags/context) 268 try { 269 // Create cookie 270 document.cookie = 'cookietest=1'; 271 var ret = document.cookie.indexOf('cookietest=') != -1; 272 // Delete cookie 273 document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT'; 274 return ret; 275 } 276 catch (e) { 277 return false; 278 } 279 }); 280 281/*! 282{ 283 "name": "Event Listener", 284 "property": "eventlistener", 285 "authors": ["Andrew Betts (@triblondon)"], 286 "notes": [{ 287 "name": "W3C Spec", 288 "href": "https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces" 289 }], 290 "polyfills": ["eventlistener"] 291} 292!*/ 293/* DOC 294Detects native support for addEventListener 295*/ 296 297 Modernizr.addTest('eventlistener', 'addEventListener' in window); 298 299 300 /** 301 * If the browsers follow the spec, then they would expose vendor-specific styles as: 302 * elem.style.WebkitBorderRadius 303 * instead of something like the following (which is technically incorrect): 304 * elem.style.webkitBorderRadius 305 306 * WebKit ghosts their properties in lowercase but Opera & Moz do not. 307 * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ 308 * erik.eae.net/archives/2008/03/10/21.48.10/ 309 310 * More here: github.com/Modernizr/Modernizr/issues/issue/21 311 * 312 * @access private 313 * @returns {string} The string representing the vendor-specific style properties 314 */ 315 316 var omPrefixes = 'Moz O ms Webkit'; 317 318 319 var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []); 320 ModernizrProto._cssomPrefixes = cssomPrefixes; 321 322 323 324 /** 325 * contains checks to see if a string contains another string 326 * 327 * @access private 328 * @function contains 329 * @param {string} str - The string we want to check for substrings 330 * @param {string} substr - The substring we want to search the first string for 331 * @returns {boolean} 332 */ 333 334 function contains(str, substr) { 335 return !!~('' + str).indexOf(substr); 336 } 337 338 ; 339 340 /** 341 * createElement is a convenience wrapper around document.createElement. Since we 342 * use createElement all over the place, this allows for (slightly) smaller code 343 * as well as abstracting away issues with creating elements in contexts other than 344 * HTML documents (e.g. SVG documents). 345 * 346 * @access private 347 * @function createElement 348 * @returns {HTMLElement|SVGElement} An HTML or SVG element 349 */ 350 351 function createElement() { 352 if (typeof document.createElement !== 'function') { 353 // This is the case in IE7, where the type of createElement is "object". 354 // For this reason, we cannot call apply() as Object is not a Function. 355 return document.createElement(arguments[0]); 356 } else if (isSVG) {
357 return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); 358 } else { 359 return document.createElement.apply(document, arguments); 360 } 361 } 362 363 ; 364 365 /** 366 * Create our "modernizr" element that we do most feature tests on. 367 * 368 * @access private 369 */ 370 371 var modElem = { 372 elem: createElement('modernizr') 373 }; 374 375 // Clean up this element 376 Modernizr._q.push(function() { 377 delete modElem.elem; 378 }); 379 380 381 382 var mStyle = { 383 style: modElem.elem.style 384 }; 385 386 // kill ref for gc, must happen before mod.elem is removed, so we unshift on to 387 // the front of the queue. 388 Modernizr._q.unshift(function() { 389 delete mStyle.style; 390 }); 391 392 393 394 /** 395 * getBody returns the body of a document, or an element that can stand in for 396 * the body if a real body does not exist 397 * 398 * @access private 399 * @function getBody 400 * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an 401 * artificially created element that stands in for the body 402 */ 403 404 function getBody() { 405 // After page load injecting a fake body doesn't work so check if body exists 406 var body = document.body; 407 408 if (!body) { 409 // Can't use the real body create a fake one. 410 body = createElement(isSVG ? 'svg' : 'body'); 411 body.fake = true; 412 } 413 414 return body; 415 } 416 417 ; 418 419 /** 420 * injectElementWithStyles injects an element with style element and some CSS rules 421 * 422 * @access private 423 * @function injectElementWithStyles 424 * @param {string} rule - String representing a css rule 425 * @param {function} callback - A function that is used to test the injected element 426 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 427 * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes 428 * @returns {boolean} 429 */ 430 431 function injectElementWithStyles(rule, callback, nodes, testnames) { 432 var mod = 'modernizr'; 433 var style; 434 var ret; 435 var node; 436 var docOverflow; 437 var div = createElement('div'); 438 var body = getBody(); 439 440 if (parseInt(nodes, 10)) { 441 // In order not to give false positives we create a node for each test 442 // This also allows the method to scale for unspecified uses 443 while (nodes--) { 444 node = createElement('div'); 445 node.id = testnames ? testnames[nodes] : mod + (nodes + 1); 446 div.appendChild(node); 447 } 448 } 449 450 style = createElement('style'); 451 style.type = 'text/css'; 452 style.id = 's' + mod; 453 454 // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody. 455 // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 456 (!body.fake ? div : body).appendChild(style); 457 body.appendChild(div); 458 459 if (style.styleSheet) { 460 style.styleSheet.cssText = rule; 461 } else { 462 style.appendChild(document.createTextNode(rule)); 463 } 464 div.id = mod; 465 466 if (body.fake) { 467 //avoid crashing IE8, if background image is used 468 body.style.background = ''; 469 //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible 470 body.style.overflow = 'hidden'; 471 docOverflow = docElement.style.overflow; 472 docElement.style.overflow = 'hidden'; 473 docElement.appendChild(body); 474 } 475 476 ret = callback(div, rule); 477 // If this is done after page load we don't want to remove the body so check if body exists 478 if (body.fake) { 479 body.parentNode.removeChild(body); 480 docElement.style.overflow = docOverflow; 481 // Trigger layout so kinetic scrolling isn't disabled in iOS6+ 482 // eslint-disable-next-line 483 docElement.offsetHeight; 484 } else { 485 div.parentNode.removeChild(div); 486 } 487 488 return !!ret; 489 490 } 491 492 ; 493 494 /** 495 * domToCSS takes a camelCase string and converts it to kebab-case 496 * e.g. boxSizing -> box-sizing 497 * 498 * @access private 499 * @function domToCSS 500 * @param {string} name - String name of camelCase prop we want to convert 501 * @returns {string} The kebab-case version of the supplied name 502 */ 503 504 function domToCSS(name) { 505 return name.replace(/([A-Z])/g, function(str, m1) { 506 return '-' + m1.toLowerCase(); 507 }).replace(/^ms-/, '-ms-'); 508 } 509 ; 510 511 512 /** 513 * wrapper around getComputedStyle, to fix issues with Firefox returning null when
514 * called inside of a hidden iframe 515 * 516 * @access private 517 * @function computedStyle 518 * @param {HTMLElement|SVGElement} - The element we want to find the computed styles of 519 * @param {string|null} [pseudoSelector]- An optional pseudo element selector (e.g. :before), of null if none 520 * @returns {CSSStyleDeclaration} 521 */ 522 523 function computedStyle(elem, pseudo, prop) { 524 var result; 525 526 if ('getComputedStyle' in window) { 527 result = getComputedStyle.call(window, elem, pseudo); 528 var console = window.console; 529 530 if (result !== null) { 531 if (prop) { 532 result = result.getPropertyValue(prop); 533 } 534 } else { 535 if (console) { 536 var method = console.error ? 'error' : 'log'; 537 console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate'); 538 } 539 } 540 } else { 541 result = !pseudo && elem.currentStyle && elem.currentStyle[prop]; 542 } 543 544 return result; 545 } 546 547 ; 548 549 /** 550 * nativeTestProps allows for us to use native feature detection functionality if available. 551 * some prefixed form, or false, in the case of an unsupported rule 552 * 553 * @access private 554 * @function nativeTestProps 555 * @param {array} props - An array of property names 556 * @param {string} value - A string representing the value we want to check via @supports 557 * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise 558 */ 559 560 // Accepts a list of property names and a single value 561 // Returns `undefined` if native detection not available 562 function nativeTestProps(props, value) { 563 var i = props.length; 564 // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface 565 if ('CSS' in window && 'supports' in window.CSS) { 566 // Try every prefixed variant of the property 567 while (i--) { 568 if (window.CSS.supports(domToCSS(props[i]), value)) { 569 return true; 570 } 571 } 572 return false; 573 } 574 // Otherwise fall back to at-rule (for Opera 12.x) 575 else if ('CSSSupportsRule' in window) { 576 // Build a condition string for every prefixed variant 577 var conditionText = []; 578 while (i--) { 579 conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')'); 580 } 581 conditionText = conditionText.join(' or '); 582 return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) { 583 return computedStyle(node, null, 'position') == 'absolute'; 584 }); 585 } 586 return undefined; 587 } 588 ; 589 590 /** 591 * cssToDOM takes a kebab-case string and converts it to camelCase 592 * e.g. box-sizing -> boxSizing 593 * 594 * @access private 595 * @function cssToDOM 596 * @param {string} name - String name of kebab-case prop we want to convert 597 * @returns {string} The camelCase version of the supplied name 598 */ 599 600 function cssToDOM(name) { 601 return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) { 602 return m1 + m2.toUpperCase(); 603 }).replace(/^-/, ''); 604 } 605 ; 606 607 // testProps is a generic CSS / DOM property test. 608 609 // In testing support for a given CSS property, it's legit to test: 610 // `elem.style[styleName] !== undefined` 611 // If the property is supported it will return an empty string, 612 // if unsupported it will return undefined. 613 614 // We'll take advantage of this quick test and skip setting a style 615 // on our modernizr element, but instead just testing undefined vs 616 // empty string. 617 618 // Property names can be provided in either camelCase or kebab-case. 619 620 function testProps(props, prefixed, value, skipValueTest) { 621 skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest; 622 623 // Try native detect first 624 if (!is(value, 'undefined')) { 625 var result = nativeTestProps(props, value); 626 if (!is(result, 'undefined')) { 627 return result; 628 } 629 } 630 631 // Otherwise do it properly 632 var afterInit, i, propsLength, prop, before; 633 634 // If we don't have a style element, that means we're running async or after 635 // the core tests, so we'll need to create our own elements to use 636 637 // inside of an SVG element, in certain browsers, the `style` element is only 638 // defined for valid tags. Therefore, if `modernizr` does not have one, we 639 // fall back to a less used element and hope for the best. 640 // for strict XHTML browsers the hardly used samp element is used 641 var elems = ['modernizr', 'tspan', 'samp']; 642 while (!mStyle.style && elems.length) { 643 afterInit = true; 644 mStyle.modElem = createElement(elems.shift()); 645 mStyle.style = mStyle.modElem.style; 646 } 647 648 // Delete the objects if we created them. 649 function cleanElems() { 650 if (afterInit) { 651 delete mStyle.style; 652 delete mStyle.modElem; 653 } 654 } 655 656 propsLength = props.length; 657 for (i = 0; i < propsLength; i++) { 658 prop = props[i]; 659 before = mStyle.style[prop]; 660 661 if (contains(prop, '-')) { 662 prop = cssToDOM(prop); 663 } 664 665 if (mStyle.style[prop] !== undefined) { 666 667 // If value to test has been passed in, do a set-and-check test. 668 // 0 (integer) is a valid property value, so check that `value` isn't 669 // undefined, rather than just checking it's truthy. 670 if (!skipValueTest && !is(value, 'undefined')) { 671 672 // Needs a try catch block because of old IE. This is slow, but will 673 // be avoided in most cases because `skipValueTest` will be used. 674 try { 675 mStyle.style[prop] = value; 676 } catch (e) {} 677 678 // If the property value has changed, we assume the value used is 679 // supported. If `value` is empty string, it'll fail here (because 680 // it hasn't changed), which matches how browsers have implemented 681 // CSS.supports() 682 if (mStyle.style[prop] != before) { 683 cleanElems(); 684 return prefixed == 'pfx' ? prop : true; 685 } 686 } 687 // Otherwise just return true, or the property name if this is a 688 // `prefixed()` call 689 else { 690 cleanElems(); 691 return prefixed == 'pfx' ? prop : true; 692 } 693 } 694 } 695 cleanElems(); 696 return false;
697 } 698 699 ; 700 701 /** 702 * List of JavaScript DOM values used for tests 703 * 704 * @memberof Modernizr 705 * @name Modernizr._domPrefixes 706 * @optionName Modernizr._domPrefixes 707 * @optionProp domPrefixes 708 * @access public 709 * @example 710 * 711 * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather 712 * than kebab-case properties, all properties are their Capitalized variant 713 * 714 * ```js 715 * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ]; 716 * ``` 717 */ 718 719 var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []); 720 ModernizrProto._domPrefixes = domPrefixes; 721 722 723 /** 724 * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill. 725 * 726 * @access private 727 * @function fnBind 728 * @param {function} fn - a function you want to change `this` reference to 729 * @param {object} that - the `this` you want to call the function with 730 * @returns {function} The wrapped version of the supplied function 731 */ 732 733 function fnBind(fn, that) { 734 return function() { 735 return fn.apply(that, arguments); 736 }; 737 } 738 739 ; 740 741 /** 742 * testDOMProps is a generic DOM property test; if a browser supports 743 * a certain property, it won't return undefined for it. 744 * 745 * @access private 746 * @function testDOMProps 747 * @param {array.<string>} props - An array of properties to test for 748 * @param {object} obj - An object or Element you want to use to test the parameters again 749 * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check 750 * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported 751 */ 752 function testDOMProps(props, obj, elem) { 753 var item; 754 755 for (var i in props) { 756 if (props[i] in obj) { 757 758 // return the property name as a string 759 if (elem === false) { 760 return props[i]; 761 } 762 763 item = obj[props[i]]; 764 765 // let's bind a function 766 if (is(item, 'function')) { 767 // bind to obj unless overriden 768 return fnBind(item, elem || obj); 769 } 770 771 // return the unbound function or obj or value 772 return item; 773 } 774 } 775 return false; 776 } 777 778 ; 779 780 /** 781 * testPropsAll tests a list of DOM properties we want to check against. 782 * We specify literally ALL possible (known and/or likely) properties on 783 * the element including the non-vendor prefixed one, for forward- 784 * compatibility. 785 * 786 * @access private 787 * @function testPropsAll 788 * @param {string} prop - A string of the property to test for 789 * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip 790 * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against 791 * @param {string} [value] - A string of a css value 792 * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set 793 * @returns {false|string} returns the string version of the property, or false if it is unsupported 794 */ 795 function testPropsAll(prop, prefixed, elem, value, skipValueTest) { 796 797 var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), 798 props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); 799 800 // did they call .prefixed('boxSizing') or are we just testing a prop? 801 if (is(prefixed, 'string') || is(prefixed, 'undefined')) { 802 return testProps(props, prefixed, value, skipValueTest); 803 804 // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) 805 } else { 806 props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); 807 return testDOMProps(props, prefixed, elem); 808 } 809 } 810 811 // Modernizr.testAllProps() investigates whether a given style property, 812 // or any of its vendor-prefixed variants, is recognized 813 // 814 // Note that the property names must be provided in the camelCase variant. 815 // Modernizr.testAllProps('boxSizing') 816 ModernizrProto.testAllProps = testPropsAll; 817 818 819 820 /** 821 * atRule returns a given CSS property at-rule (eg @keyframes), possibly in 822 * some prefixed form, or false, in the case of an unsupported rule 823 * 824 * @memberof Modernizr 825 * @name Modernizr.atRule 826 * @optionName Modernizr.atRule() 827 * @optionProp atRule 828 * @access public 829 * @function atRule 830 * @param {string} prop - String name of the @-rule to test for 831 * @returns {string|boolean} The string representing the (possibly prefixed) 832 * valid version of the @-rule, or `false` when it is unsupported. 833 * @example 834 * ```js 835 * var keyframes = Modernizr.atRule('@keyframes'); 836 * 837 * if (keyframes) { 838 * // keyframes are supported 839 * // could be `@-webkit-keyframes` or `@keyframes` 840 * } else { 841 * // keyframes === `false` 842 * } 843 * ``` 844 * 845 */ 846 847 var atRule = function(prop) { 848 var length = prefixes.length; 849 var cssrule = window.CSSRule; 850 var rule; 851 852 if (typeof cssrule === 'undefined') { 853 return undefined; 854 } 855 856 if (!prop) { 857 return false;
858 } 859 860 // remove literal @ from beginning of provided property 861 prop = prop.replace(/^@/, ''); 862 863 // CSSRules use underscores instead of dashes 864 rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE'; 865 866 if (rule in cssrule) { 867 return '@' + prop; 868 } 869 870 for (var i = 0; i < length; i++) { 871 // prefixes gives us something like -o-, and we want O_ 872 var prefix = prefixes[i]; 873 var thisRule = prefix.toUpperCase() + '_' + rule; 874 875 if (thisRule in cssrule) { 876 return '@-' + prefix.toLowerCase() + '-' + prop; 877 } 878 } 879 880 return false; 881 }; 882 883 ModernizrProto.atRule = atRule; 884 885 886 887 /** 888 * prefixed returns the prefixed or nonprefixed property name variant of your input 889 * 890 * @memberof Modernizr 891 * @name Modernizr.prefixed 892 * @optionName Modernizr.prefixed() 893 * @optionProp prefixed 894 * @access public 895 * @function prefixed 896 * @param {string} prop - String name of the property to test for 897 * @param {object} [obj] - An object to test for the prefixed properties on 898 * @param {HTMLElement} [elem] - An element used to test specific properties against 899 * @returns {string|false} The string representing the (possibly prefixed) valid 900 * version of the property, or `false` when it is unsupported. 901 * @example 902 * 903 * Modernizr.prefixed takes a string css value in the DOM style camelCase (as 904 * opposed to the css style kebab-case) form and returns the (possibly prefixed) 905 * version of that property that the browser actually supports. 906 * 907 * For example, in older Firefox... 908 * ```js 909 * prefixed('boxSizing') 910 * ``` 911 * returns 'MozBoxSizing' 912 * 913 * In newer Firefox, as well as any other browser that support the unprefixed 914 * version would simply return `boxSizing`. Any browser that does not support 915 * the property at all, it will return `false`. 916 * 917 * By default, prefixed is checked against a DOM element. If you want to check 918 * for a property on another object, just pass it as a second argument 919 * 920 * ```js 921 * var rAF = prefixed('requestAnimationFrame', window); 922 * 923 * raf(function() { 924 * renderFunction(); 925 * }) 926 * ``` 927 * 928 * Note that this will return _the actual function_ - not the name of the function. 929 * If you need the actual name of the property, pass in `false` as a third argument 930 * 931 * ```js 932 * var rAFProp = prefixed('requestAnimationFrame', window, false); 933 * 934 * rafProp === 'WebkitRequestAnimationFrame' // in older webkit 935 * ``` 936 * 937 * One common use case for prefixed is if you're trying to determine which transition 938 * end event to bind to, you might do something like... 939 * ```js 940 * var transEndEventNames = { 941 * 'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser 942 * 'MozTransition' : 'transitionend', * only for FF < 15 943 * 'transition' : 'transitionend' * IE10, Opera, Chrome, FF 15+, Saf 7+ 944 * }; 945 * 946 * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; 947 * ``` 948 * 949 * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss). 950 */ 951 952 var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) { 953 if (prop.indexOf('@') === 0) { 954 return atRule(prop); 955 } 956 957 if (prop.indexOf('-') != -1) { 958 // Convert kebab-case to camelCase 959 prop = cssToDOM(prop); 960 } 961 if (!obj) { 962 return testPropsAll(prop, 'pfx'); 963 } else { 964 // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame' 965 return testPropsAll(prop, obj, elem); 966 } 967 }; 968 969 970/*! 971{ 972 "name": "Fullscreen API", 973 "property": "fullscreen", 974 "caniuse": "fullscreen", 975 "notes": [{ 976 "name": "MDN documentation", 977 "href": "https://developer.mozilla.org/en/API/Fullscreen" 978 }], 979 "polyfills": ["screenfulljs"], 980 "builderAliases": ["fullscreen_api"] 981} 982!*/ 983/* DOC 984Detects support for the ability to make the current website take over the user's entire screen 985*/ 986 987 // github.com/Modernizr/Modernizr/issues/739 988 Modernizr.addTest('fullscreen', !!(prefixed('exitFullscreen', document, false) || prefixed('cancelFullScreen', document, false))); 989 990 991 /** 992 * testStyles injects an element with style element and some CSS rules 993 * 994 * @memberof Modernizr 995 * @name Modernizr.testStyles 996 * @optionName Modernizr.testStyles() 997 * @optionProp testStyles 998 * @access public 999 * @function testStyles 1000 * @param {string} rule - String representing a css rule 1001 * @param {function} callback - A function that is used to test the injected element 1002 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 1003 * @param {string[]}
1003 [testnames] - An array of strings that are used as ids for the additional nodes 1004 * @returns {boolean} 1005 * @example 1006 * 1007 * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page 1008 * along with (possibly multiple) DOM elements. This lets you check for features 1009 * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules). 1010 * 1011 * ```js 1012 * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) { 1013 * // elem is the first DOM node in the page (by default #modernizr) 1014 * // rule is the first argument you supplied - the CSS rule in string form 1015 * 1016 * addTest('widthworks', elem.style.width === '9px') 1017 * }); 1018 * ``` 1019 * 1020 * If your test requires multiple nodes, you can include a third argument 1021 * indicating how many additional div elements to include on the page. The 1022 * additional nodes are injected as children of the `elem` that is returned as 1023 * the first argument to the callback. 1024 * 1025 * ```js 1026 * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) { 1027 * document.getElementById('modernizr').style.width === '1px'; // true 1028 * document.getElementById('modernizr2').style.width === '2px'; // true 1029 * elem.firstChild === document.getElementById('modernizr2'); // true 1030 * }, 1); 1031 * ``` 1032 * 1033 * By default, all of the additional elements have an ID of `modernizr[n]`, where 1034 * `n` is its index (e.g. the first additional, second overall is `#modernizr2`, 1035 * the second additional is `#modernizr3`, etc.). 1036 * If you want to have more meaningful IDs for your function, you can provide 1037 * them as the fourth argument, as an array of strings 1038 * 1039 * ```js 1040 * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) { 1041 * elem.firstChild === document.getElementById('foo'); // true 1042 * elem.lastChild === document.getElementById('bar'); // true 1043 * }, 2, ['foo', 'bar']); 1044 * ``` 1045 * 1046 */ 1047 1048 var testStyles = ModernizrProto.testStyles = injectElementWithStyles; 1049 1050/*! 1051{ 1052 "name": "Hidden Scrollbar", 1053 "property": "hiddenscroll", 1054 "authors": ["Oleg Korsunsky"], 1055 "tags": ["overlay"], 1056 "notes": [{ 1057 "name": "Overlay Scrollbar description", 1058 "href": "https://developer.apple.com/library/mac/releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_7.html#//apple_ref/doc/uid/TP40010355-SW39" 1059 },{ 1060 "name": "Video example of overlay scrollbars", 1061 "href": "https://gfycat.com/FoolishMeaslyAtlanticsharpnosepuffer" 1062 }] 1063} 1064!*/ 1065/* DOC 1066Detects overlay scrollbars (when scrollbars on overflowed blocks are visible). This is found most commonly on mobile and OS X. 1067*/ 1068 1069 Modernizr.addTest('hiddenscroll', function() { 1070 return testStyles('#modernizr {width:100px;height:100px;overflow:scroll}', function(elem) { 1071 return elem.offsetWidth === elem.clientWidth; 1072 }); 1073 }); 1074 1075 1076 /** 1077 * since we have a fairly large number of input tests that don't mutate the input 1078 * we create a single element that can be shared with all of those tests for a 1079 * minor perf boost 1080 * 1081 * @access private 1082 * @returns {HTMLInputElement} 1083 */ 1084 var inputElem = createElement('input'); 1085 1086/*! 1087{ 1088 "name": "Input attributes", 1089 "property": "input", 1090 "tags": ["forms"], 1091 "authors": ["Mike Taylor"], 1092 "notes": [{ 1093 "name": "WHATWG spec", 1094 "href": "https://html.spec.whatwg.org/multipage/forms.html#input-type-attr-summary" 1095 }], 1096 "knownBugs": ["Some blackberry devices report false positive for input.multiple"] 1097} 1098!*/ 1099/* DOC 1100Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results: 1101 1102```javascript 1103Modernizr.input.autocomplete 1104Modernizr.input.autofocus 1105Modernizr.input.list 1106Modernizr.input.max 1107Modernizr.input.min 1108Modernizr.input.multiple 1109Modernizr.input.pattern 1110Modernizr.input.placeholder 1111Modernizr.input.required 1112Modernizr.input.step 1113``` 1114*/ 1115 1116 // Run through HTML5's new input attributes to see if the UA understands any. 1117 // Mike Taylr has created a comprehensive resource for testing these attributes 1118 // when applied to all input types: 1119 // miketaylr.com/code/input-type-attr.html 1120 1121 // Only input placeholder is tested while textarea's placeholder is not. 1122 // Currently Safari 4 and Opera 11 have support only for the input placeholder 1123 // Both tests are available in feature-detects/forms-placeholder.js 1124 1125 var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '); 1126 var attrs = {}; 1127 1128 Modernizr.input = (function(props) { 1129 for (var i = 0, len = props.length; i < len; i++) { 1130 attrs[ props[i] ] = !!(props[i] in inputElem); 1131 } 1132 if (attrs.list) { 1133 // safari false positive's on datalist: webk.it/74252 1134 // see also github.com/Modernizr/Modernizr/issues/146 1135 attrs.list = !!(createElement('datalist') && window.HTMLDataListElement); 1136 } 1137 return attrs; 1138 })(inputattrs); 1139 1140/*! 1141{ 1142 "name": "Form input types", 1143 "property": "inputtypes", 1144 "caniuse": "forms", 1145 "tags": ["forms"], 1146 "authors": ["Mike Taylor"],
1147 "polyfills": [ 1148 "jquerytools", 1149 "webshims", 1150 "h5f", 1151 "webforms2", 1152 "nwxforms", 1153 "fdslider", 1154 "html5slider", 1155 "galleryhtml5forms", 1156 "jscolor", 1157 "html5formshim", 1158 "selectedoptionsjs", 1159 "formvalidationjs" 1160 ] 1161} 1162!*/ 1163/* DOC 1164Detects support for HTML5 form input types and exposes Boolean subproperties with the results: 1165 1166```javascript 1167Modernizr.inputtypes.color 1168Modernizr.inputtypes.date 1169Modernizr.inputtypes.datetime 1170Modernizr.inputtypes['datetime-local'] 1171Modernizr.inputtypes.email 1172Modernizr.inputtypes.month 1173Modernizr.inputtypes.number 1174Modernizr.inputtypes.range 1175Modernizr.inputtypes.search 1176Modernizr.inputtypes.tel 1177Modernizr.inputtypes.time 1178Modernizr.inputtypes.url 1179Modernizr.inputtypes.week 1180``` 1181*/ 1182 1183 // Run through HTML5's new input types to see if the UA understands any. 1184 // This is put behind the tests runloop because it doesn't return a 1185 // true/false like all the other tests; instead, it returns an object 1186 // containing each input type with its corresponding true/false value 1187 1188 // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ 1189 var inputtypes = 'search tel url email datetime date month week time datetime-local number range color'.split(' '); 1190 var inputs = {}; 1191 1192 Modernizr.inputtypes = (function(props) { 1193 var len = props.length; 1194 var smile = '1)'; 1195 var inputElemType; 1196 var defaultView; 1197 var bool; 1198 1199 for (var i = 0; i < len; i++) { 1200 1201 inputElem.setAttribute('type', inputElemType = props[i]); 1202 bool = inputElem.type !== 'text' && 'style' in inputElem; 1203 1204 // We first check to see if the type we give it sticks.. 1205 // If the type does, we feed it a textual value, which shouldn't be valid. 1206 // If the value doesn't stick, we know there's input sanitization which infers a custom UI 1207 if (bool) { 1208 1209 inputElem.value = smile; 1210 inputElem.style.cssText = 'position:absolute;visibility:hidden;'; 1211 1212 if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) { 1213 1214 docElement.appendChild(inputElem); 1215 defaultView = document.defaultView; 1216 1217 // Safari 2-4 allows the smiley as a value, despite making a slider 1218 bool = defaultView.getComputedStyle && 1219 defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && 1220 // Mobile android web browser has false positive, so must 1221 // check the height to see if the widget is actually there. 1222 (inputElem.offsetHeight !== 0); 1223 1224 docElement.removeChild(inputElem); 1225 1226 } else if (/^(search|tel)$/.test(inputElemType)) { 1227 // Spec doesn't define any special parsing or detectable UI 1228 // behaviors so we pass these through as true 1229 1230 // Interestingly, opera fails the earlier test, so it doesn't 1231 // even make it here. 1232 1233 } else if (/^(url|email)$/.test(inputElemType)) { 1234 // Real url and email support comes with prebaked validation. 1235 bool = inputElem.checkValidity && inputElem.checkValidity() === false; 1236 1237 } else { 1238 // If the upgraded input compontent rejects the :) text, we got a winner 1239 bool = inputElem.value != smile; 1240 } 1241 } 1242 1243 inputs[ props[i] ] = !!bool; 1244 } 1245 return inputs; 1246 })(inputtypes); 1247 1248/*! 1249{ 1250 "name": "JSON", 1251 "property": "json", 1252 "caniuse": "json", 1253 "notes": [{ 1254 "name": "MDN documentation", 1255 "href": "https://developer.mozilla.org/en-US/docs/Glossary/JSON" 1256 }], 1257 "polyfills": ["json2"] 1258} 1259!*/ 1260/* DOC 1261Detects native support for JSON handling functions. 1262*/ 1263 1264 // this will also succeed if you've loaded the JSON2.js polyfill ahead of time 1265 // ... but that should be obvious. :) 1266 1267 Modernizr.addTest('json', 'JSON' in window && 'parse' in JSON && 'stringify' in JSON); 1268 1269/*! 1270{ 1271 "name": "SVG", 1272 "property": "svg", 1273 "caniuse": "svg", 1274 "tags": ["svg"], 1275 "authors": ["Erik Dahlstrom"], 1276 "polyfills": [ 1277 "svgweb", 1278 "raphael", 1279 "amplesdk", 1280 "canvg", 1281 "svg-boilerplate", 1282 "sie", 1283 "dojogfx", 1284 "fabricjs" 1285 ] 1286} 1287!*/ 1288/* DOC 1289Detects support for SVG in `<embed>` or `<object>` elements. 1290*/ 1291 1292 Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect); 1293 1294 1295 /** 1296 * List of property values to set for css tests. See ticket #21
1297 * http://git.io/vUGl4 1298 * 1299 * @memberof Modernizr 1300 * @name Modernizr._prefixes 1301 * @optionName Modernizr._prefixes 1302 * @optionProp prefixes 1303 * @access public 1304 * @example 1305 * 1306 * Modernizr._prefixes is the internal list of prefixes that we test against 1307 * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply 1308 * an array of kebab-case vendor prefixes you can use within your code. 1309 * 1310 * Some common use cases include 1311 * 1312 * Generating all possible prefixed version of a CSS property 1313 * ```js 1314 * var rule = Modernizr._prefixes.join('transform: rotate(20deg); '); 1315 * 1316 * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);' 1317 * ``` 1318 * 1319 * Generating all possible prefixed version of a CSS value 1320 * ```js 1321 * rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex'; 1322 * 1323 * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex' 1324 * ``` 1325 */ 1326 1327 // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test 1328 // values in feature detects to continue to work 1329 var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']); 1330 1331 // expose these for the plugin API. Look in the source for how to join() them against your input 1332 ModernizrProto._prefixes = prefixes; 1333 1334 1335/*! 1336{ 1337 "name": "Touch Events", 1338 "property": "touchevents", 1339 "caniuse" : "touch", 1340 "tags": ["media", "attribute"], 1341 "notes": [{ 1342 "name": "Touch Events spec", 1343 "href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/" 1344 }], 1345 "warnings": [ 1346 "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device" 1347 ], 1348 "knownBugs": [ 1349 "False-positive on some configurations of Nokia N900", 1350 "False-positive on some BlackBerry 6.0 builds â https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695" 1351 ] 1352} 1353!*/ 1354/* DOC 1355Indicates if the browser supports the W3C Touch Events API. 1356 1357This *does not* necessarily reflect a touchscreen device: 1358 1359* Older touchscreen devices only emulate mouse events 1360* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that 1361* Some browsers & OS setups may enable touch APIs when no touchscreen is connected 1362* Future browsers may implement other event models for touch interactions 1363 1364See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/). 1365 1366It's recommended to bind both mouse and touch/pointer events simultaneously â see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/). 1367 1368This test will also return `true` for Firefox 4 Multitouch support. 1369*/ 1370 1371 // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415 1372 Modernizr.addTest('touchevents', function() { 1373 var bool; 1374 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { 1375 bool = true; 1376 } else { 1377 // include the 'heartz' as a way to have a non matching MQ to help terminate the join 1378 // https://git.io/vznFH 1379 var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join(''); 1380 testStyles(query, function(node) { 1381 bool = node.offsetTop === 9; 1382 }); 1383 } 1384 return bool; 1385 }); 1386 1387/*! 1388{ 1389 "name": "HTML5 Video", 1390 "property": "video", 1391 "caniuse": "video", 1392 "tags": ["html5"], 1393 "knownBugs": [ 1394 "Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546" 1395 ], 1396 "polyfills": [ 1397 "html5media", 1398 "mediaelementjs", 1399 "sublimevideo", 1400 "videojs", 1401 "leanbackplayer", 1402 "videoforeverybody" 1403 ] 1404} 1405!*/ 1406/* DOC 1407Detects support for the video element, as well as testing what types of content it supports. 1408 1409Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.: 1410 1411```javascript 1412Modernizr.video // true 1413Modernizr.video.ogg // 'probably' 1414``` 1415*/ 1416 1417 // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 1418 // thx to NielsLeenheer and zcorpan 1419 1420 // Note: in some older browsers, "no" was a return value instead of empty string. 1421 // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2 1422 // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5 1423 1424 Modernizr.addTest('video', function() { 1425 var elem = createElement('video'); 1426 var bool = false;
1427 1428 // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 1429 try { 1430 bool = !!elem.canPlayType 1431 if (bool) { 1432 bool = new Boolean(bool); 1433 bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, ''); 1434 1435 // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546 1436 bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, ''); 1437 1438 bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, ''); 1439 1440 bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, ''); 1441 1442 bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, ''); 1443 } 1444 } catch (e) {} 1445 1446 return bool; 1447 }); 1448 1449 1450 /** 1451 * testAllProps determines whether a given CSS property is supported in the browser 1452 * 1453 * @memberof Modernizr 1454 * @name Modernizr.testAllProps 1455 * @optionName Modernizr.testAllProps() 1456 * @optionProp testAllProps 1457 * @access public 1458 * @function testAllProps 1459 * @param {string} prop - String naming the property to test (either camelCase or kebab-case) 1460 * @param {string} [value] - String of the value to test 1461 * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection 1462 * @example 1463 * 1464 * testAllProps determines whether a given CSS property, in some prefixed form, 1465 * is supported by the browser. 1466 * 1467 * ```js 1468 * testAllProps('boxSizing') // true 1469 * ``` 1470 * 1471 * It can optionally be given a CSS value in string form to test if a property 1472 * value is valid 1473 * 1474 * ```js 1475 * testAllProps('display', 'block') // true 1476 * testAllProps('display', 'penguin') // false 1477 * ``` 1478 * 1479 * A boolean can be passed as a third parameter to skip the value check when 1480 * native detection (@supports) isn't available. 1481 * 1482 * ```js 1483 * testAllProps('shapeOutside', 'content-box', true); 1484 * ``` 1485 */ 1486 1487 function testAllProps(prop, value, skipValueTest) { 1488 return testPropsAll(prop, undefined, undefined, value, skipValueTest); 1489 } 1490 ModernizrProto.testAllProps = testAllProps; 1491 1492/*! 1493{ 1494 "name": "CSS Animations", 1495 "property": "cssanimations", 1496 "caniuse": "css-animation", 1497 "polyfills": ["transformie", "csssandpaper"], 1498 "tags": ["css"], 1499 "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"], 1500 "notes": [{ 1501 "name" : "Article: 'Dispelling the Android CSS animation myths'", 1502 "href": "https://goo.gl/OGw5Gm" 1503 }] 1504} 1505!*/ 1506/* DOC 1507Detects whether or not elements can be animated using CSS 1508*/ 1509 1510 Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true)); 1511 1512/*! 1513{ 1514 "name": "CSS Background Blend Mode", 1515 "property": "backgroundblendmode", 1516 "caniuse": "css-backgroundblendmode", 1517 "tags": ["css"], 1518 "notes": [ 1519 { 1520 "name": "CSS Blend Modes could be the next big thing in Web Design", 1521 "href": " https://medium.com/@bennettfeely/css-blend-modes-could-be-the-next-big-thing-in-web-design-6b51bf53743a" 1522 }, { 1523 "name": "Demo", 1524 "href": "http://bennettfeely.com/gradients/" 1525 } 1526 ] 1527} 1528!*/ 1529/* DOC 1530Detects the ability for the browser to composite backgrounds using blending modes similar to ones found in Photoshop or Illustrator. 1531*/ 1532 1533 Modernizr.addTest('backgroundblendmode', prefixed('backgroundBlendMode', 'text')); 1534 1535/*! 1536{ 1537 "name": "Background Size", 1538 "property": "backgroundsize", 1539 "tags": ["css"], 1540 "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"], 1541 "notes": [{ 1542 "name": "Related Issue", 1543 "href": "https://github.com/Modernizr/Modernizr/issues/396" 1544 }] 1545} 1546!*/ 1547 1548 Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true)); 1549 1550/*! 1551{ 1552 "name": "Border Radius",
1553 "property": "borderradius", 1554 "caniuse": "border-radius", 1555 "polyfills": ["css3pie"], 1556 "tags": ["css"], 1557 "notes": [{ 1558 "name": "Comprehensive Compat Chart", 1559 "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance" 1560 }] 1561} 1562!*/ 1563 1564 Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true)); 1565 1566/*! 1567{ 1568 "name": "CSS Calc", 1569 "property": "csscalc", 1570 "caniuse": "calc", 1571 "tags": ["css"], 1572 "builderAliases": ["css_calc"], 1573 "authors": ["@calvein"] 1574} 1575!*/ 1576/* DOC 1577Method of allowing calculated values for length units. For example: 1578 1579```css 1580//lem { 1581 width: calc(100% - 3em); 1582} 1583``` 1584*/ 1585 1586 Modernizr.addTest('csscalc', function() { 1587 var prop = 'width:'; 1588 var value = 'calc(10px);'; 1589 var el = createElement('a'); 1590 1591 el.style.cssText = prop + prefixes.join(value + prop); 1592 1593 return !!el.style.length; 1594 }); 1595 1596/*! 1597{ 1598 "name": "CSS Supports", 1599 "property": "supports", 1600 "caniuse": "css-featurequeries", 1601 "tags": ["css"], 1602 "builderAliases": ["css_supports"], 1603 "notes": [{ 1604 "name": "W3 Spec", 1605 "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports" 1606 },{ 1607 "name": "Related Github Issue", 1608 "href": "https://github.com/Modernizr/Modernizr/issues/648" 1609 },{ 1610 "name": "W3 Info", 1611 "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface" 1612 }] 1613} 1614!*/ 1615 1616 var newSyntax = 'CSS' in window && 'supports' in window.CSS; 1617 var oldSyntax = 'supportsCSS' in window; 1618 Modernizr.addTest('supports', newSyntax || oldSyntax); 1619 1620/*! 1621{ 1622 "name": "CSS Filters", 1623 "property": "cssfilters", 1624 "caniuse": "css-filters", 1625 "polyfills": ["polyfilter"], 1626 "tags": ["css"], 1627 "builderAliases": ["css_filters"], 1628 "notes": [{ 1629 "name": "MDN article on CSS filters", 1630 "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/filter" 1631 }] 1632} 1633!*/ 1634 1635 Modernizr.addTest('cssfilters', function() { 1636 if (Modernizr.supports) { 1637 return testAllProps('filter', 'blur(2px)'); 1638 } else { 1639 var el = createElement('a'); 1640 el.style.cssText = prefixes.join('filter:blur(2px); '); 1641 // https://github.com/Modernizr/Modernizr/issues/615 1642 // documentMode is needed for false positives in oldIE, please see issue above 1643 return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9)); 1644 } 1645 }); 1646 1647 1648/*! 1649{ 1650 "name": "Flexbox", 1651 "property": "flexbox", 1652 "caniuse": "flexbox", 1653 "tags": ["css"], 1654 "notes": [{ 1655 "name": "The _new_ flexbox", 1656 "href": "http://dev.w3.org/csswg/css3-flexbox" 1657 }], 1658 "warnings": [ 1659 "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect." 1660 ] 1661} 1662!*/ 1663/* DOC 1664Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container. 1665*/ 1666 1667 Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true)); 1668 1669/*! 1670{ 1671 "name": "@font-face", 1672 "property": "fontface", 1673 "authors": ["Diego Perini", "Mat Marquis"], 1674 "tags": ["css"], 1675 "knownBugs": [ 1676 "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342", 1677 "False Postive: WP7 https://github.com/Modernizr/Modernizr/issues/538" 1678 ], 1679 "notes": [{ 1680 "name": "@font-face detection routine by Diego Perini", 1681 "href": "http://javascript.nwbox.com/CSSSupport/" 1682 },{ 1683 "name": "Filament Group @font-face compatibility research", 1684 "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p" 1685 },{ 1686 "name": "Filament Grunticon/@font-face device testing results", 1687 "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0" 1688 },{ 1689 "name": "CSS fonts on Android", 1690 "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android" 1691 },{ 1692 "name": "@font-face and Android", 1693 "href": "http://archivist.incutio.com/viewlist/css-discuss/115960" 1694 }] 1695} 1696!*/ 1697 1698 var blacklist = (function() { 1699 var ua = navigator.userAgent; 1700 var webos = ua.match(/w(eb)?osbrowser/gi); 1701 var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9; 1702 return webos || wppre8; 1703 }()); 1704 if (blacklist) { 1705 Modernizr.addTest('fontface', false); 1706 } else { 1707 testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) { 1708 var style = document.getElementById('smodernizr'); 1709 var sheet = style.sheet || style.styleSheet; 1710 var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : ''; 1711 var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0; 1712 Modernizr.addTest('fontface', bool); 1713 }); 1714 } 1715; 1716/*! 1717{ 1718 "name": "CSS Gradients", 1719 "caniuse": "css-gradients", 1720 "property": "cssgradients", 1721 "tags": ["css"], 1722 "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"], 1723 "notes": [{ 1724 "name": "Webkit Gradient Syntax", 1725 "href": "https://webkit.org/blog/175/introducing-css-gradients/" 1726 },{ 1727 "name": "Linear Gradient Syntax", 1728 "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient" 1729 },{ 1730 "name": "W3C Gradient Spec", 1731 "href": "https://drafts.csswg.org/css-images-3/#gradients" 1732 }] 1733} 1734!*/ 1735 1736 1737 Modernizr.addTest('cssgradients', function() { 1738 1739 var str1 = 'background-image:'; 1740 var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));'; 1741 var css = ''; 1742 var angle; 1743 1744 for (var i = 0, len = prefixes.length - 1; i < len; i++) { 1745 angle = (i === 0 ? 'to ' : ''); 1746 css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);'; 1747 } 1748
1749 if (Modernizr._config.usePrefixes) { 1750 // legacy webkit syntax (FIXME: remove when syntax not in use anymore) 1751 css += str1 + '-webkit-' + str2; 1752 } 1753 1754 var elem = createElement('a'); 1755 var style = elem.style; 1756 style.cssText = css; 1757 1758 // IE6 returns undefined so cast to string 1759 return ('' + style.backgroundImage).indexOf('gradient') > -1; 1760 }); 1761 1762/*! 1763{ 1764 "name": "CSS :invalid pseudo-class", 1765 "property": "cssinvalid", 1766 "notes": [{ 1767 "name": "MDN documentation", 1768 "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid" 1769 }] 1770} 1771!*/ 1772/* DOC 1773 Detects support for the ':invalid' CSS pseudo-class. 1774*/ 1775 1776 Modernizr.addTest('cssinvalid', function() { 1777 return testStyles('#modernizr input{height:0;border:0;padding:0;margin:0;width:10px} #modernizr input:invalid{width:50px}', function(elem) { 1778 var input = createElement('input'); 1779 input.required = true; 1780 elem.appendChild(input); 1781 return input.clientWidth > 10; 1782 }); 1783 }); 1784 1785/*! 1786{ 1787 "name": "CSS Opacity", 1788 "caniuse": "css-opacity", 1789 "property": "opacity", 1790 "tags": ["css"] 1791} 1792!*/ 1793 1794 // Browsers that actually have CSS Opacity implemented have done so 1795 // according to spec, which means their return values are within the 1796 // range of [0.0,1.0] - including the leading zero. 1797 1798 Modernizr.addTest('opacity', function() { 1799 var style = createElement('a').style; 1800 style.cssText = prefixes.join('opacity:.55;'); 1801 1802 // The non-literal . in this regex is intentional: 1803 // German Chrome returns this value as 0,55 1804 // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 1805 return (/^0.55$/).test(style.opacity); 1806 }); 1807 1808/*! 1809{ 1810 "name": "CSS Font rem Units", 1811 "caniuse": "rem", 1812 "authors": ["nsfmc"], 1813 "property": "cssremunit", 1814 "tags": ["css"], 1815 "builderAliases": ["css_remunit"], 1816 "notes": [{ 1817 "name": "W3C Spec", 1818 "href": "https://www.w3.org/TR/css3-values/#relative0" 1819 },{ 1820 "name": "Font Size with rem by Jonathan Snook", 1821 "href": "http://snook.ca/archives/html_and_css/font-size-with-rem" 1822 }] 1823} 1824!*/ 1825 1826 // "The 'rem' unit ('root em') is relative to the computed 1827 // value of the 'font-size' value of the root element." 1828 // you can test by checking if the prop was ditched 1829 1830 Modernizr.addTest('cssremunit', function() { 1831 var style = createElement('a').style; 1832 try { 1833 style.fontSize = '3rem'; 1834 } 1835 catch (e) {} 1836 return (/rem/).test(style.fontSize); 1837 }); 1838 1839/*! 1840{ 1841 "name": "CSS Shapes", 1842 "property": "shapes", 1843 "tags": ["css"], 1844 "notes": [{ 1845 "name": "CSS Shapes W3C specification", 1846 "href": "https://www.w3.org/TR/css-shapes" 1847 },{ 1848 "name": "Examples from Adobe", 1849 "href": "http://webplatform.adobe.com/shapes/" 1850 }, { 1851 "name": "Samples showcasing uses of Shapes", 1852 "href": "http://codepen.io/collection/qFesk" 1853 }] 1854} 1855!*/ 1856 1857 Modernizr.addTest('shapes', testAllProps('shapeOutside', 'content-box', true)); 1858 1859 1860 /** 1861 * testProp() investigates whether a given style property is recognized 1862 * Property names can be provided in either camelCase or kebab-case. 1863 * 1864 * @memberof Modernizr 1865 * @name Modernizr.testProp 1866 * @access public 1867 * @optionName Modernizr.testProp() 1868 * @optionProp testProp 1869 * @function testProp 1870 * @param {string} prop - Name of the CSS property to check 1871 * @param {string} [value] - Name of the CSS value to check 1872 * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported 1873 * @returns {boolean} 1874 * @example 1875 * 1876 * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed 1877 * version of the string. 1878 * 1879 * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing) 1880 * 1881 * ```js 1882 * Modernizr.testProp('pointerEvents') // true 1883 * ``` 1884 * 1885 * You can also provide a value as an optional second argument to check if a 1886 * specific value is supported 1887 * 1888 * ```js
1889 * Modernizr.testProp('pointerEvents', 'none') // true 1890 * Modernizr.testProp('pointerEvents', 'penguin') // false 1891 * ``` 1892 */ 1893 1894 var testProp = ModernizrProto.testProp = function(prop, value, useValue) { 1895 return testProps([prop], undefined, value, useValue); 1896 }; 1897 1898/*! 1899{ 1900 "name": "CSS textshadow", 1901 "property": "textshadow", 1902 "caniuse": "css-textshadow", 1903 "tags": ["css"], 1904 "knownBugs": ["FF3.0 will false positive on this test"] 1905} 1906!*/ 1907 1908 Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px')); 1909 1910/*! 1911{ 1912 "name": "CSS Transforms", 1913 "property": "csstransforms", 1914 "caniuse": "transforms2d", 1915 "tags": ["css"] 1916} 1917!*/ 1918 1919 Modernizr.addTest('csstransforms', function() { 1920 // Android < 3.0 is buggy, so we sniff and blacklist 1921 // http://git.io/hHzL7w 1922 return navigator.userAgent.indexOf('Android 2.') === -1 && 1923 testAllProps('transform', 'scale(1)', true); 1924 }); 1925 1926/*! 1927{ 1928 "name": "CSS Transforms 3D", 1929 "property": "csstransforms3d", 1930 "caniuse": "transforms3d", 1931 "tags": ["css"], 1932 "warnings": [ 1933 "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004" 1934 ] 1935} 1936!*/ 1937 1938 Modernizr.addTest('csstransforms3d', function() { 1939 return !!testAllProps('perspective', '1px', true); 1940 }); 1941 1942/*! 1943{ 1944 "name": "CSS Transitions", 1945 "property": "csstransitions", 1946 "caniuse": "css-transitions", 1947 "tags": ["css"] 1948} 1949!*/ 1950 1951 Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true)); 1952 1953 1954 /** 1955 * roundedEquals takes two integers and checks if the first is
1955within 1 of the second 1956 * 1957 * @access private 1958 * @function roundedEquals 1959 * @param {number} a 1960 * @param {number} b 1961 * @returns {boolean} 1962 */ 1963 1964 function roundedEquals(a, b) { 1965 return a - 1 === b || a === b || a + 1 === b; 1966 } 1967 1968 ; 1969/*! 1970{ 1971 "name": "CSS vh unit", 1972 "property": "cssvhunit", 1973 "caniuse": "viewport-units", 1974 "tags": ["css"], 1975 "builderAliases": ["css_vhunit"], 1976 "notes": [{ 1977 "name": "Related Modernizr Issue", 1978 "href": "https://github.com/Modernizr/Modernizr/issues/572" 1979 },{ 1980 "name": "Similar JSFiddle", 1981 "href": "https://jsfiddle.net/FWeinb/etnYC/" 1982 }] 1983} 1984!*/ 1985 1986 testStyles('#modernizr { height: 50vh; }', function(elem) { 1987 var height = parseInt(window.innerHeight / 2, 10); 1988 var compStyle = parseInt(computedStyle(elem, null, 'height'), 10); 1989 1990 Modernizr.addTest('cssvhunit', roundedEquals(compStyle, height)); 1991 }); 1992 1993/*! 1994{ 1995 "name": "CSS vw unit", 1996 "property": "cssvwunit", 1997 "caniuse": "viewport-units", 1998 "tags": ["css"], 1999 "builderAliases": ["css_vwunit"], 2000 "notes": [{ 2001 "name": "Related Modernizr Issue", 2002 "href": "https://github.com/Modernizr/Modernizr/issues/572" 2003 },{ 2004 "name": "JSFiddle Example", 2005 "href": "https://jsfiddle.net/FWeinb/etnYC/" 2006 }] 2007} 2008!*/ 2009 2010 testStyles('#modernizr { width: 50vw; }', function(elem) { 2011 var width = parseInt(window.innerWidth / 2, 10); 2012 var compStyle = parseInt(computedStyle(elem, null, 'width'), 10); 2013 2014 Modernizr.addTest('cssvwunit', roundedEquals(compStyle, width)); 2015 }); 2016 2017/*! 2018{ 2019 "name": "File API", 2020 "property": "filereader", 2021 "caniuse": "fileapi", 2022 "notes": [{ 2023 "name": "W3C Working Draft", 2024 "href": "https://www.w3.org/TR/FileAPI/" 2025 }], 2026 "tags": ["file"], 2027 "builderAliases": ["file_api"], 2028 "knownBugs": ["Will fail in Safari 5 due to its lack of support for the standards defined FileReader object"] 2029} 2030!*/ 2031/* DOC 2032`filereader` tests for the File API specification 2033 2034Tests for objects specific to the File API W3C specification without 2035being redundant (don't bother testing for Blob since it is assumed 2036to be the File object's prototype.) 2037*/ 2038 2039 Modernizr.addTest('filereader', !!(window.File && window.FileList && window.FileReader)); 2040 2041/*! 2042{ 2043 "name": "Filesystem API", 2044 "property": "filesystem", 2045 "caniuse": "filesystem", 2046 "notes": [{ 2047 "name": "W3 Draft", 2048 "href": "http://dev.w3.org/2009/dap/file-system/file-dir-sys.html" 2049 }], 2050 "authors": ["Eric Bidelman (@ebidel)"], 2051 "tags": ["file"], 2052 "builderAliases": ["file_filesystem"], 2053 "knownBugs": ["The API will be present in Chrome incognito, but will throw an exception. See crbug.com/93417"] 2054} 2055!*/ 2056 2057 Modernizr.addTest('filesystem', !!prefixed('requestFileSystem', window)); 2058 2059/*! 2060{ 2061 "name": "style[scoped]", 2062 "property": "stylescoped", 2063 "caniuse": "style-scoped", 2064 "tags": ["dom"], 2065 "builderAliases": ["style_scoped"], 2066 "authors": ["CÄtÄlin MariÈ"], 2067 "notes": [{ 2068 "name": "WHATWG Specification", 2069 "href": "https://html.spec.whatwg.org/multipage/semantics.html#attr-style-scoped" 2070 }], 2071 "polyfills": ["scoped-styles"] 2072} 2073!*/ 2074/* DOC 2075Support for the `scoped` attribute of the `<style>` element. 2076*/ 2077 2078 Modernizr.addTest('stylescoped', 'scoped' in createElement('style')); 2079 2080 2081 /** 2082 * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support 2083 * 2084 * @author kangax 2085 * @access private 2086 * @function hasOwnProp 2087 * @param {object} object - The object to check for a property 2088 * @param {string} property - The property to check for 2089 * @returns {boolean} 2090 */ 2091 2092 // hasOwnProperty shim by kangax needed for Safari 2.0 support 2093 var hasOwnProp; 2094 2095 (function() { 2096 var _hasOwnProperty = ({}).hasOwnProperty; 2097 /* istanbul ignore else */ 2098 /* we have no way of testing IE 5.5 or safari 2, 2099 * so just assume the else gets hit */ 2100 if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) { 2101 hasOwnProp = function(object, property) { 2102 return _hasOwnProperty.call(object, property); 2103 }; 2104 } 2105 else { 2106 hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ 2107 return ((property in object) && is(object.constructor.prototype[property], 'undefined')); 2108 }; 2109 } 2110 })(); 2111 2112 2113 2114 2115 // _l tracks listeners for async tests, as well as tests that execute after the initial run 2116 ModernizrProto._l = {}; 2117 2118 /** 2119 * Modernizr.on is a way to listen for the completion of async tests. Being 2120 * asynchronous, they may not finish before your scripts run. As a result you 2121 * will get a possibly false negative `undefined` value. 2122 * 2123 * @memberof Modernizr 2124 * @name Modernizr.on 2125 * @access public 2126 * @function on 2127 * @param {string} feature - String name of the feature detect
2128 * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not 2129 * @example 2130 * 2131 * ```js 2132 * Modernizr.on('flash', function( result ) { 2133 * if (result) { 2134 * // the browser has flash 2135 * } else { 2136 * // the browser does not have flash 2137 * } 2138 * }); 2139 * ``` 2140 */ 2141 2142 ModernizrProto.on = function(feature, cb) { 2143 // Create the list of listeners if it doesn't exist 2144 if (!this._l[feature]) { 2145 this._l[feature] = []; 2146 } 2147 2148 // Push this test on to the listener list 2149 this._l[feature].push(cb); 2150 2151 // If it's already been resolved, trigger it on next tick 2152 if (Modernizr.hasOwnProperty(feature)) { 2153 // Next Tick 2154 setTimeout(function() { 2155 Modernizr._trigger(feature, Modernizr[feature]); 2156 }, 0); 2157 } 2158 }; 2159 2160 /** 2161 * _trigger is the private function used to signal test completion and run any 2162 * callbacks registered through [Modernizr.on](#modernizr-on) 2163 * 2164 * @memberof Modernizr 2165 * @name Modernizr._trigger 2166 * @access private 2167 * @function _trigger 2168 * @param {string} feature - string name of the feature detect 2169 * @param {function|boolean} [res] - A feature detection function, or the boolean = 2170 * result of a feature detection function 2171 */ 2172 2173 ModernizrProto._trigger = function(feature, res) { 2174 if (!this._l[feature]) { 2175 return; 2176 } 2177 2178 var cbs = this._l[feature]; 2179 2180 // Force async 2181 setTimeout(function() { 2182 var i, cb; 2183 for (i = 0; i < cbs.length; i++) { 2184 cb = cbs[i]; 2185 cb(res); 2186 } 2187 }, 0); 2188 2189 // Don't trigger these again 2190 delete this._l[feature]; 2191 }; 2192 2193 /** 2194 * addTest allows you to define your own feature detects that are not currently 2195 * included in Modernizr (under the covers it's the exact same code Modernizr 2196 * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result 2197 * will be added onto the Modernizr object, as well as an appropriate className set on 2198 * the html element when configured to do so 2199 * 2200 * @memberof Modernizr 2201 * @name Modernizr.addTest 2202 * @optionName Modernizr.addTest() 2203 * @optionProp addTest 2204 * @access public 2205 * @function addTest 2206 * @param {string|object} feature - The string name of the feature detect, or an 2207 * object of feature detect names and test 2208 * @param {function|boolean} test - Function returning true if feature is supported, 2209 * false if not. Otherwise a boolean representing the results of a feature detection 2210 * @example 2211 * 2212 * The most common way of creating your own feature detects is by calling 2213 * `Modernizr.addTest` with a string (preferably just lowercase, without any 2214 * punctuation), and a function you want executed that will return a boolean result 2215 * 2216 * ```js 2217 * Modernizr.addTest('itsTuesday', function() { 2218 * var d = new Date(); 2219 * return d.getDay() === 2; 2220 * }); 2221 * ``` 2222 * 2223 * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday, 2224 * and to `false` every other day of the week. One thing to notice is that the names of 2225 * feature detect functions are always lowercased when added to the Modernizr object. That 2226 * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will. 2227 * 2228 * 2229 * Since we only look at the returned value from any feature detection function, 2230 * you do not need to actually use a function. For simple detections, just passing 2231 * in a statement that will return a boolean value works just fine. 2232 * 2233 * ```js 2234 * Modernizr.addTest('hasJquery', 'jQuery' in window); 2235 * ``` 2236 * 2237 * Just like before, when the above runs `Modernizr.hasjquery` will be true if 2238 * jQuery has been included on the page. Not using a function saves a small amount 2239 * of overhead for the browser, as well as making your code much more readable. 2240 * 2241 * Finally, you also have the ability to pass in an object of feature names and 2242 * their tests. This is handy if you want to add multiple detections in one go. 2243 * The keys should always be a string, and the value can be either a boolean or 2244 * function that returns a boolean. 2245 * 2246 * ```js 2247 * var detects = { 2248 * 'hasjquery': 'jQuery' in window, 2249 * 'itstuesday': function() { 2250 * var d = new Date(); 2251 * return d.getDay() === 2; 2252 * } 2253 * } 2254 * 2255 * Modernizr.addTest(detects); 2256 * ``` 2257 *
2258 * There is really no difference between the first methods and this one, it is 2259 * just a convenience to let you write more readable code. 2260 */ 2261 2262 function addTest(feature, test) { 2263 2264 if (typeof feature == 'object') { 2265 for (var key in feature) { 2266 if (hasOwnProp(feature, key)) { 2267 addTest(key, feature[ key ]); 2268 } 2269 } 2270 } else { 2271 2272 feature = feature.toLowerCase(); 2273 var featureNameSplit = feature.split('.'); 2274 var last = Modernizr[featureNameSplit[0]]; 2275 2276 // Again, we don't check for parent test existence. Get that right, though. 2277 if (featureNameSplit.length == 2) { 2278 last = last[featureNameSplit[1]]; 2279 } 2280 2281 if (typeof last != 'undefined') { 2282 // we're going to quit if you're trying to overwrite an existing test 2283 // if we were to allow it, we'd do this: 2284 // var re = new RegExp("\\b(no-)?" + feature + "\\b"); 2285 // docElement.className = docElement.className.replace( re, '' ); 2286 // but, no rly, stuff 'em. 2287 return Modernizr; 2288 } 2289 2290 test = typeof test == 'function' ? test() : test; 2291 2292 // Set the value (this is the magic, right here). 2293 if (featureNameSplit.length == 1) { 2294 Modernizr[featureNameSplit[0]] = test; 2295 } else { 2296 // cast to a Boolean, if not one already 2297 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 2298 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 2299 } 2300 2301 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test; 2302 } 2303 2304 // Set a single class (either `feature` or `no-feature`) 2305 setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]); 2306 2307 // Trigger the event 2308 Modernizr._trigger(feature, test); 2309 } 2310 2311 return Modernizr; // allow chaining. 2312 } 2313 2314 // After all the tests are run, add self to the Modernizr prototype 2315 Modernizr._q.push(function() { 2316 ModernizrProto.addTest = addTest; 2317 }); 2318 2319 2320 2321/*! 2322{ 2323 "name": "SVG as an <img> tag source", 2324 "property": "svgasimg", 2325 "caniuse" : "svg-img", 2326 "tags": ["svg"], 2327 "aliases": ["svgincss"], 2328 "authors": ["Chris Coyier"], 2329 "notes": [{ 2330 "name": "HTML5 Spec", 2331 "href": "http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element" 2332 }] 2333} 2334!*/ 2335 2336 2337 // Original Async test by Stu Cox 2338 // https://gist.github.com/chriscoyier/8774501 2339 2340 // Now a Sync test based on good results here 2341 // http://codepen.io/chriscoyier/pen/bADFx 2342 2343 // Note http://www.w3.org/TR/SVG11/feature#Image is *supposed* to represent 2344 // support for the `<image>` tag in SVG, not an SVG file linked from an `<img>` 2345 // tag in HTML â but itâs a heuristic which works 2346 Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1')); 2347 2348 2349 /** 2350 * Object.prototype.toString can be used with every object and allows you to 2351 * get its class easily. Abstracting it off of an object prevents situations 2352 * where the toString property has been overridden 2353 * 2354 * @access private 2355 * @function toStringFn 2356 * @returns {function} An abstracted toString function 2357 */ 2358 2359 var toStringFn = ({}).toString; 2360 2361/*! 2362{ 2363 "name": "SVG clip paths", 2364 "property": "svgclippaths", 2365 "tags": ["svg"], 2366 "notes": [{ 2367 "name": "Demo", 2368 "href": "http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg" 2369 }] 2370} 2371!*/ 2372/* DOC 2373Detects support for clip paths in SVG (only, not on HTML content). 2374 2375See [this discussion](https://github.com/Modernizr/Modernizr/issues/213) regarding applying SVG clip paths to HTML content. 2376*/ 2377 2378 Modernizr.addTest('svgclippaths', function() { 2379 return !!document.createElementNS && 2380 /SVGClipPath/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'clipPath'))); 2381 }); 2382 2383/*! 2384{ 2385 "name": "SVG filters", 2386 "property": "svgfilters", 2387 "caniuse": "svg-filters", 2388 "tags": ["svg"], 2389 "builderAliases": ["svg_filters"], 2390 "authors": ["Erik Dahlstrom"], 2391 "notes": [{ 2392 "name": "W3C Spec", 2393 "href": "https://www.w3.org/TR/SVG11/filters.html" 2394 }] 2395} 2396!*/ 2397 2398 // Should fail in Safari: https://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters. 2399 Modernizr.addTest('svgfilters', function() { 2400 var result = false;
2401 try { 2402 result = 'SVGFEColorMatrixElement' in window && 2403 SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2; 2404 } 2405 catch (e) {} 2406 return result; 2407 }); 2408 2409/*! 2410{ 2411 "name": "SVG foreignObject", 2412 "property": "svgforeignobject", 2413 "tags": ["svg"], 2414 "notes": [{ 2415 "name": "W3C Spec", 2416 "href": "https://www.w3.org/TR/SVG11/extend.html" 2417 }] 2418} 2419!*/ 2420/* DOC 2421Detects support for foreignObject tag in SVG. 2422*/ 2423 2424 Modernizr.addTest('svgforeignobject', function() { 2425 return !!document.createElementNS && 2426 /SVGForeignObject/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'))); 2427 }); 2428 2429/*! 2430{ 2431 "name": "Inline SVG", 2432 "property": "inlinesvg", 2433 "caniuse": "svg-html5", 2434 "tags": ["svg"], 2435 "notes": [{ 2436 "name": "Test page", 2437 "href": "https://paulirish.com/demo/inline-svg" 2438 }, { 2439 "name": "Test page and results", 2440 "href": "https://codepen.io/eltonmesquita/full/GgXbvo/" 2441 }], 2442 "polyfills": ["inline-svg-polyfill"], 2443 "knownBugs": ["False negative on some Chromia browsers."] 2444} 2445!*/ 2446/* DOC 2447Detects support for inline SVG in HTML (not within XHTML). 2448*/ 2449 2450 Modernizr.addTest('inlinesvg', function() { 2451 var div = createElement('div'); 2452 div.innerHTML = '<svg/>'; 2453 return (typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg'; 2454 }); 2455 2456/*! 2457{ 2458 "name": "SVG SMIL animation", 2459 "property": "smil", 2460 "caniuse": "svg-smil", 2461 "tags": ["svg"], 2462 "notes": [{ 2463 "name": "W3C Synchronised Multimedia spec", 2464 "href": "https://www.w3.org/AudioVideo/" 2465 }] 2466} 2467!*/ 2468 2469 // SVG SMIL animation 2470 Modernizr.addTest('smil', function() { 2471 return !!document.createElementNS && 2472 /SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate'))); 2473 }); 2474 2475/*! 2476{ 2477 "name": "Video Autoplay", 2478 "property": "videoautoplay", 2479 "tags": ["video"], 2480 "async" : true, 2481 "warnings": ["This test is very large â only include it if you absolutely need it"], 2482 "knownBugs": ["crashes with an alert on iOS7 when added to homescreen"] 2483} 2484!*/ 2485/* DOC 2486Checks for support of the autoplay attribute of the video element. 2487*/ 2488 2489 2490 Modernizr.addAsyncTest(function() { 2491 var timeout; 2492 var waitTime = 200; 2493 var retries = 5; 2494 var currentTry = 0; 2495 var elem = createElement('video'); 2496 var elemStyle = elem.style; 2497 2498 function testAutoplay(arg) { 2499 currentTry++; 2500 clearTimeout(timeout); 2501 2502 var result = arg && arg.type === 'playing' || elem.currentTime !== 0; 2503 2504 if (!result && currentTry < retries) { 2505 //Detection can be flaky if the browser is slow, so lets retry in a little bit 2506 timeout = setTimeout(testAutoplay, waitTime); 2507 return; 2508 } 2509 2510 elem.removeEventListener('playing', testAutoplay, false); 2511 addTest('videoautoplay', result); 2512 2513 // Cleanup, but don't assume elem is still in the page - 2514 // an extension (eg Flashblock) may already have removed it. 2515 if (elem.parentNode) { 2516 elem.parentNode.removeChild(elem); 2517 } 2518 } 2519 2520 //skip the test if video itself, or the autoplay 2521 //element on it isn't supported 2522 if (!Modernizr.video || !('autoplay' in elem)) { 2523 addTest('videoautoplay', false); 2524 return; 2525 } 2526 2527 elemStyle.position = 'absolute'; 2528 elemStyle.height = 0; 2529 elemStyle.width = 0; 2530 2531 try { 2532 if (Modernizr.video.ogg) { 2533 elem.src = 'data:video/ogg;base64,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'; 2534 } 2535 else if (Modernizr.video.h264) { 2536 elem.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAs1tZGF0AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0OCByMjYwMSBhMGNkN2QzIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEwIHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAD2WIhAA3//728P4FNjuZQQAAAu5tb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAZAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACGHRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAgAAAAIAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAGQAAAAAAAEAAAAAAZBtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAACgAAAAEAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAE7bWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAA+3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAgACAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFkAAr/4QAYZ2QACqzZX4iIhAAAAwAEAAADAFA8SJZYAQAGaOvjyyLAAAAAGHN0dHMAAAAAAAAAAQAAAAEAAAQAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAABRzdHN6AAAAAAAAAsUAAAABAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU2LjQwLjEwMQ=='; 2537 } 2538 else { 2539 addTest('videoautoplay', false); 2540 return; 2541 } 2542 } 2543 2544 catch (e) { 2545 addTest('videoautoplay', false); 2546 return; 2547 } 2548 2549 elem.setAttribute('autoplay', ''); 2550 elemStyle.cssText = 'display:none'; 2551 docElement.appendChild(elem); 2552 // wait for the next tick to add the listener, otherwise the element may 2553 // not have time to play in high load situations (e.g. the test suite) 2554 setTimeout(function() { 2555 elem.addEventListener('playing', testAutoplay, false); 2556 timeout = setTimeout(testAutoplay, waitTime); 2557 }, 0); 2558 }); 2559 2560 2561 // Run each test 2562 testRunner(); 2563 2564 // Remove the "no-js" class if it exists 2565 setClasses(classes); 2566 2567 delete ModernizrProto.addTest; 2568 delete ModernizrProto.addAsyncTest; 2569 2570 // Run the things that are supposed to run after the tests 2571 for (var i = 0; i < Modernizr._q.length; i++) { 2572 Modernizr._q[i](); 2573 } 2574 2575 // Leak Modernizr namespace 2576 window.Modernizr = Modernizr; 2577 2578 2579; 2580 2581})(window, document); 2582; 2583//# sourceMappingURL=scripts.617ea3354da11990.js.map
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.