1/*! 2 * modernizr v3.3.1 3 * Build https://modernizr.com/download?-backgroundsize-borderimage-borderradius-boxshadow-cssanimations-csstransforms-csstransforms3d-csstransitions-fontface-generatedcontent-inlinesvg-opacity-rgba-textshadow-touchevents-domprefixes-mq-prefixes-setclasses-shiv-testallprops-testprop-teststyles-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 classes = []; 27 28 29 var tests = []; 30 31 32 /** 33 * 34 * ModernizrProto is the constructor for Modernizr 35 * 36 * @class 37 * @access public 38 */ 39 40 var ModernizrProto = { 41 // The current version, dummy 42 _version: '3.3.1', 43 44 // Any settings that don't work as separate modules 45 // can go in here as configuration. 46 _config: { 47 'classPrefix': '', 48 'enableClasses': true, 49 'enableJSClass': true, 50 'usePrefixes': true 51 }, 52 53 // Queue of tests 54 _q: [], 55 56 // Stub these for people who are listening 57 on: function(test, cb) { 58 // I don't really think people should do this, but we can 59 // safe guard it a bit. 60 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 61 // This is in case people listen to synchronous tests. I would leave it out, 62 // but the code to *disallow* sync tests in the real version of this 63 // function is actually larger than this. 64 var self = this; 65 setTimeout(function() { 66 cb(self[test]); 67 }, 0); 68 }, 69 70 addTest: function(name, fn, options) { 71 tests.push({name: name, fn: fn, options: options}); 72 }, 73 74 addAsyncTest: function(fn) { 75 tests.push({name: null, fn: fn}); 76 } 77 }; 78 79 80 81 // Fake some of Object.create so we can force non test results to be non "own" properties. 82 var Modernizr = function() {}; 83 Modernizr.prototype = ModernizrProto; 84 85 // Leak modernizr globally when you `require` it rather than force it here. 86 // Overwrite name so constructor name is nicer :D 87 Modernizr = new Modernizr(); 88 89 90 91 /** 92 * List of property values to set for css tests. See ticket #21 93 * http://git.io/vUGl4 94 * 95 * @memberof Modernizr 96 * @name Modernizr._prefixes 97 * @optionName Modernizr._prefixes 98 * @optionProp prefixes 99 * @access public 100 * @example 101 * 102 * Modernizr._prefixes is the internal list of prefixes that we test against 103 * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply 104 * an array of kebab-case vendor prefixes you can use within your code. 105 * 106 * Some common use cases include 107 * 108 * Generating all possible prefixed version of a CSS property 109 * ```js 110 * var rule = Modernizr._prefixes.join('transform: rotate(20deg); '); 111 * 112 * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);' 113 * ``` 114 * 115 * Generating all possible prefixed version of a CSS value 116 * ```js 117 * rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex'; 118 * 119 * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex' 120 * ``` 121 */ 122 123 // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test 124 // values in feature detects to continue to work 125 var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']); 126 127 // expose these for the plugin API. Look in the source for how to join() them against your input 128 ModernizrProto._prefixes = prefixes; 129 130 131 132 /** 133 * is returns a boolean if the typeof an obj is exactly type. 134 * 135 * @access private 136 * @function is 137 * @param {*} obj - A thing we want to check the type of 138 * @param {string} type - A string to compare the typeof against 139 * @returns {boolean} 140 */ 141 142 function is(obj, type) { 143 return typeof obj === type; 144 } 145 ; 146 147 /** 148 * Run through all tests and detect their support in the current UA. 149 * 150 * @access private 151 */ 152 153 function testRunner() { 154 var featureNames; 155 var feature; 156 var aliasIdx; 157 var result; 158 var nameIdx; 159 var featureName; 160 var featureNameSplit; 161 162 for (var featureIdx in tests) { 163 if (tests.hasOwnProperty(featureIdx)) { 164 featureNames = []; 165 feature = tests[featureIdx]; 166 // run the test, throw the return value into the Modernizr, 167 // then based on that boolean, define an appropriate className 168 // and push it into an array of classes we'll join later. 169 // 170 // If there is no name, it's an 'async' test that is run, 171 // but not directly added to the object. That should 172 // be done with a post-run addTest call. 173 if (feature.name) { 174 featureNames.push(feature.name.toLowerCase()); 175 176 if (feature.options && feature.options.aliases && feature.options.aliases.length) { 177 // Add all the aliases into the names list 178 for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) { 179 featureNames.push(feature.options.aliases[aliasIdx].toLowerCase()); 180 } 181 } 182 } 183 184 // Run the test, or use the raw value if it's not a function 185 result = is(feature.fn, 'function') ? feature.fn() : feature.fn; 186 187 188 // Set each of the names on the Modernizr object 189 for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { 190 featureName = featureNames[nameIdx];
191 // Support dot properties as sub tests. We don't do checking to make sure 192 // that the implied parent tests have been added. You must call them in 193 // order (either in the test, or make the parent test a dependency). 194 // 195 // Cap it to TWO to make the logic simple and because who needs that kind of subtesting 196 // hashtag famous last words 197 featureNameSplit = featureName.split('.'); 198 199 if (featureNameSplit.length === 1) { 200 Modernizr[featureNameSplit[0]] = result; 201 } else { 202 // cast to a Boolean, if not one already 203 /* jshint -W053 */ 204 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 205 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 206 } 207 208 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 209 } 210 211 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 212 } 213 } 214 } 215 } 216 ; 217 218 /** 219 * docElement is a convenience wrapper to grab the root element of the document 220 * 221 * @access private 222 * @returns {HTMLElement|SVGElement} The root element of the document 223 */ 224 225 var docElement = document.documentElement; 226 227 228 /** 229 * A convenience helper to check if the document we are running in is an SVG document 230 * 231 * @access private 232 * @returns {boolean} 233 */ 234 235 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 236 237 238 /** 239 * setClasses takes an array of class names and adds them to the root element 240 * 241 * @access private 242 * @function setClasses 243 * @param {string[]} classes - Array of class names 244 */ 245 246 // Pass in an and array of class names, e.g.:
247 // ['no-webp', 'borderradius', ...] 248 function setClasses(classes) { 249 var className = docElement.className; 250 var classPrefix = Modernizr._config.classPrefix || ''; 251 252 if (isSVG) { 253 className = className.baseVal; 254 } 255 256 // Change `no-js` to `js` (independently of the `enableClasses` option) 257 // Handle classPrefix on this too 258 if (Modernizr._config.enableJSClass) { 259 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 260 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 261 } 262 263 if (Modernizr._config.enableClasses) { 264 // Add the new classes 265 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 266 isSVG ? docElement.className.baseVal = className : docElement.className = className; 267 } 268 269 } 270 271 ; 272 273/** 274 * @optionName html5shiv 275 * @optionProp html5shiv 276 */ 277 278 // Take the html5 variable out of the html5shiv scope so we can return it. 279 var html5; 280 if (!isSVG) { 281 /** 282 * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 283 */ 284 ;(function(window, document) { 285 /*jshint evil:true */ 286 /** version */ 287 var version = '3.7.3'; 288 289 /** Preset options */ 290 var options = window.html5 || {}; 291 292 /** Used to skip problem elements */ 293 var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; 294 295 /** Not all elements can be cloned in IE **/ 296 var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; 297 298 /** Detect whether the browser supports default html5 styles */ 299 var supportsHtml5Styles; 300 301 /** Name of the expando, to work with multiple documents or to re-shiv one document */ 302 var expando = '_html5shiv'; 303 304 /** The id for the the documents expando */ 305 var expanID = 0; 306 307 /** Cached data for each document */ 308 var expandoData = {}; 309 310 /** Detect whether the browser supports unknown elements */ 311 var supportsUnknownElements; 312 313 (function() { 314 try { 315 var a = document.createElement('a'); 316 a.innerHTML = '<xyz></xyz>'; 317 //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles 318 supportsHtml5Styles = ('hidden' in a); 319 320 supportsUnknownElements = a.childNodes.length == 1 || (function() { 321 // assign a false positive if unable to shiv 322 (document.createElement)('a'); 323 var frag = document.createDocumentFragment(); 324 return ( 325 typeof frag.cloneNode == 'undefined' || 326 typeof frag.createDocumentFragment == 'undefined' || 327 typeof frag.createElement == 'undefined' 328 ); 329 }()); 330 } catch(e) { 331 // assign a false positive if detection fails => unable to shiv 332 supportsHtml5Styles = true; 333 supportsUnknownElements = true; 334 } 335 336 }()); 337 338 /*--------------------------------------------------------------------------*/ 339 340 /** 341 * Creates a style sheet with the given CSS text and adds it to the document. 342 * @private 343 * @param {Document} ownerDocument The document. 344 * @param {String} cssText The CSS text. 345 * @returns {StyleSheet} The style element. 346 */ 347 function addStyleSheet(ownerDocument, cssText) { 348 var p = ownerDocument.createElement('p'), 349 parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; 350 351 p.innerHTML = 'x<style>' + cssText + '</style>'; 352 return parent.insertBefore(p.lastChild, parent.firstChild); 353 } 354 355 /** 356 * Returns the value of `html5.elements` as an array. 357 * @private 358 * @returns {Array} An array of shived element node names. 359 */ 360 function getElements() { 361 var elements = html5.elements; 362 return typeof elements == 'string' ? elements.split(' ') : elements; 363 } 364 365 /** 366 * Extends the built-in list of html5 elements 367 * @memberOf html5 368 * @param {String|Array} newElements whitespace separated list or array of new element names to shiv 369 * @param {Document} ownerDocument The context document. 370 */ 371 function addElements(newElements, ownerDocument) { 372 var elements = html5.elements; 373 if(typeof elements != 'string'){ 374 elements = elements.join(' '); 375 } 376 if(typeof newElements != 'string'){ 377 newElements = newElements.join(' '); 378 } 379 html5.elements = elements +' '+ newElements; 380 shivDocument(ownerDocument); 381 } 382 383 /** 384 * Returns the data associated to the given document 385 * @private 386 * @param {Document} ownerDocument The document. 387 * @returns {Object} An object of data. 388 */ 389 function getExpandoData(ownerDocument) { 390 var data = expandoData[ownerDocument[expando]]; 391 if (!data) { 392 data = {}; 393 expanID++; 394 ownerDocument[expando] = expanID; 395 expandoData[expanID] = data; 396 } 397 return data; 398 } 399 400 /** 401 * returns a shived element for the given nodeName and document 402 * @memberOf html5 403 * @param {String}
vendor: 4,418 bytes, lines 403-514
403 nodeName name of the element 404 * @param {Document|DocumentFragment} ownerDocument The context document. 405 * @returns {Object} The shived element. 406 */ 407 function createElement(nodeName, ownerDocument, data){ 408 if (!ownerDocument) { 409 ownerDocument = document; 410 } 411 if(supportsUnknownElements){ 412 return ownerDocument.createElement(nodeName); 413 } 414 if (!data) { 415 data = getExpandoData(ownerDocument); 416 } 417 var node; 418 419 if (data.cache[nodeName]) { 420 node = data.cache[nodeName].cloneNode(); 421 } else if (saveClones.test(nodeName)) { 422 node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); 423 } else { 424 node = data.createElem(nodeName); 425 } 426 427 // Avoid adding some elements to fragments in IE < 9 because 428 // * Attributes like `name` or `type` cannot be set/changed once an element 429 // is inserted into a document/fragment 430 // * Link elements with `src` attributes that are inaccessible, as with 431 // a 403 response, will cause the tab/window to crash 432 // * Script elements appended to fragments will execute when their `src` 433 // or `text` property is set 434 return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; 435 } 436 437 /** 438 * returns a shived DocumentFragment for the given document 439 * @memberOf html5 440 * @param {Document} ownerDocument The context document. 441 * @returns {Object} The shived DocumentFragment. 442 */ 443 function createDocumentFragment(ownerDocument, data){ 444 if (!ownerDocument) { 445 ownerDocument = document; 446 } 447 if(supportsUnknownElements){ 448 return ownerDocument.createDocumentFragment(); 449 } 450 data = data || getExpandoData(ownerDocument); 451 var clone = data.frag.cloneNode(), 452 i = 0, 453 elems = getElements(), 454 l = elems.length; 455 for(;i<l;i++){ 456 clone.createElement(elems[i]); 457 } 458 return clone; 459 } 460 461 /** 462 * Shivs the `createElement` and `createDocumentFragment` methods of the document. 463 * @private 464 * @param {Document|DocumentFragment} ownerDocument The document. 465 * @param {Object} data of the document. 466 */ 467 function shivMethods(ownerDocument, data) { 468 if (!data.cache) { 469 data.cache = {}; 470 data.createElem = ownerDocument.createElement; 471 data.createFrag = ownerDocument.createDocumentFragment; 472 data.frag = data.createFrag(); 473 } 474 475 476 ownerDocument.createElement = function(nodeName) { 477 //abort shiv 478 if (!html5.shivMethods) { 479 return data.createElem(nodeName); 480 } 481 return createElement(nodeName, ownerDocument, data); 482 }; 483 484 ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' + 485 'var n=f.cloneNode(),c=n.createElement;' + 486 'h.shivMethods&&(' + 487 // unroll the `createElement` calls 488 getElements().join().replace(/[\w\-:]+/g, function(nodeName) { 489 data.createElem(nodeName); 490 data.frag.createElement(nodeName); 491 return 'c("' + nodeName + '")'; 492 }) + 493 ');return n}' 494 )(html5, data.frag); 495 } 496 497 /*--------------------------------------------------------------------------*/ 498 499 /** 500 * Shivs the given document. 501 * @memberOf html5 502 * @param {Document} ownerDocument The document to shiv. 503 * @returns {Document} The shived document. 504 */ 505 function shivDocument(ownerDocument) { 506 if (!ownerDocument) { 507 ownerDocument = document; 508 } 509 var data = getExpandoData(ownerDocument); 510 511 if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) { 512 data.hasCSS = !!addStyleSheet(ownerDocument, 513 // corrects block display not defined in IE6/7/8/9 514 'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
514play:block}' + 515 // adds styling not present in IE6/7/8/9 516 'mark{background:#FF0;color:#000}' + 517 // hides non-rendered elements 518 'template{display:none}' 519 ); 520 } 521 if (!supportsUnknownElements) { 522 shivMethods(ownerDocument, data); 523 } 524 return ownerDocument; 525 } 526 527 /*--------------------------------------------------------------------------*/ 528 529 /** 530 * The `html5` object is exposed so that more elements can be shived and 531 * existing shiving can be detected on iframes. 532 * @type Object 533 * @example 534 * 535 * // options can be changed before the script is included 536 * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false }; 537 */ 538 var html5 = { 539 540 /** 541 * An array or space separated string of node names of the elements to shiv. 542 * @memberOf html5 543 * @type Array|String 544 */ 545 'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video', 546 547 /** 548 * current version of html5shiv 549 */ 550 'version': version, 551 552 /** 553 * A flag to indicate that the HTML5 style sheet should be inserted. 554 * @memberOf html5 555 * @type Boolean 556 */ 557 'shivCSS': (options.shivCSS !== false), 558 559 /** 560 * Is equal to true if a browser supports creating unknown/HTML5 elements 561 * @memberOf html5 562 * @type boolean 563 */ 564 'supportsUnknownElements': supportsUnknownElements, 565 566 /** 567 * A flag to indicate that the document's `createElement` and `createDocumentFragment` 568 * methods should be overwritten. 569 * @memberOf html5 570 * @type Boolean 571 */ 572 'shivMethods': (options.shivMethods !== false), 573 574 /** 575 * A string to describe the type of `html5` object ("default" or "default print"). 576 * @memberOf html5
577 * @type String 578 */ 579 'type': 'default', 580 581 // shivs the document according to the specified `html5` object options 582 'shivDocument': shivDocument, 583 584 //creates a shived element 585 createElement: createElement, 586 587 //creates a shived documentFragment 588 createDocumentFragment: createDocumentFragment, 589 590 //extends list of elements 591 addElements: addElements 592 }; 593 594 /*--------------------------------------------------------------------------*/ 595 596 // expose html5 597 window.html5 = html5; 598 599 // shiv the document 600 shivDocument(document); 601 602 if(typeof module == 'object' && module.exports){ 603 module.exports = html5; 604 } 605 606 }(typeof window !== "undefined" ? window : this, document)); 607 } 608; 609 610 /** 611 * If the browsers follow the spec, then they would expose vendor-specific style as: 612 * elem.style.WebkitBorderRadius 613 * instead of something like the following, which would be technically incorrect: 614 * elem.style.webkitBorderRadius 615 616 * Webkit ghosts their properties in lowercase but Opera & Moz do not. 617 * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ 618 * erik.eae.net/archives/2008/03/10/21.48.10/ 619 620 * More here: github.com/Modernizr/Modernizr/issues/issue/21 621 * 622 * @access private 623 * @returns {string} The string representing the vendor-specific style properties 624 */ 625 626 var omPrefixes = 'Moz O ms Webkit'; 627 628 629 /** 630 * List of JavaScript DOM values used for tests 631 * 632 * @memberof Modernizr 633 * @name Modernizr._domPrefixes 634 * @optionName Modernizr._domPrefixes 635 * @optionProp domPrefixes 636 * @access public 637 * @example 638 * 639 * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather 640 * than kebab-case properties, all properties are their Capitalized variant 641 * 642 * ```js 643 * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ]; 644 * ``` 645 */ 646 647 var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []); 648 ModernizrProto._domPrefixes = domPrefixes; 649 650 651 /** 652 * createElement is a convenience wrapper around document.createElement. Since we 653 * use createElement all over the place, this allows for (slightly) smaller code 654 * as well as abstracting away issues with creating elements in contexts other than 655 * HTML documents (e.g. SVG documents). 656 * 657 * @access private 658 * @function createElement 659 * @returns {HTMLElement|SVGElement} An HTML or SVG element 660 */ 661 662 function createElement() { 663 if (typeof document.createElement !== 'function') { 664 // This is the case in IE7, where the type of createElement is "object". 665 // For this reason, we cannot call apply() as Object is not a Function. 666 return document.createElement(arguments[0]); 667 } else if (isSVG) { 668 return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); 669 } else { 670 return document.createElement.apply(document, arguments); 671 } 672 } 673 674 ; 675/*! 676{ 677 "name": "CSS Opacity", 678 "caniuse": "css-opacity", 679 "property": "opacity", 680 "tags": ["css"] 681} 682!*/ 683 684 // Browsers that actually have CSS Opacity implemented have done so 685 // according to spec, which means their return values are within the 686 // range of [0.0,1.0] - including the leading zero. 687 688 Modernizr.addTest('opacity', function() { 689 var style = createElement('a').style; 690 style.cssText = prefixes.join('opacity:.55;'); 691 692 // The non-literal . in this regex is intentional: 693 // German Chrome returns this value as 0,55 694 // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 695 return (/^0.55$/).test(style.opacity); 696 }); 697 698/*! 699{ 700 "name": "CSS rgba", 701 "caniuse": "css3-colors", 702 "property": "rgba", 703 "tags": ["css"], 704 "notes": [{ 705 "name": "CSSTricks Tutorial", 706 "href": "https://css-tricks.com/rgba-browser-support/" 707 }] 708} 709!*/ 710 711 Modernizr.addTest('rgba', function() { 712 var style = createElement('a').style; 713 style.cssText = 'background-color:rgba(150,255,150,.5)'; 714 715 return ('' + style.backgroundColor).indexOf('rgba') > -1; 716 }); 717 718/*! 719{ 720 "name": "Inline SVG", 721 "property": "inlinesvg", 722 "caniuse": "svg-html5", 723 "tags": ["svg"], 724 "notes": [{ 725 "name": "Test page", 726 "href": "https://paulirish.com/demo/inline-svg" 727 }, { 728 "name": "Test page and results", 729 "href": "https://codepen.io/eltonmesquita/full/GgXbvo/" 730 }], 731 "polyfills": ["inline-svg-polyfill"],
732 "knownBugs": ["False negative on some Chromia browsers."] 733} 734!*/ 735/* DOC 736Detects support for inline SVG in HTML (not within XHTML). 737*/ 738 739 Modernizr.addTest('inlinesvg', function() { 740 var div = createElement('div'); 741 div.innerHTML = '<svg/>'; 742 return (typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg'; 743 }); 744 745/*! 746{ 747 "name": "CSS Supports", 748 "property": "supports", 749 "caniuse": "css-featurequeries", 750 "tags": ["css"], 751 "builderAliases": ["css_supports"], 752 "notes": [{ 753 "name": "W3 Spec", 754 "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports" 755 },{ 756 "name": "Related Github Issue", 757 "href": "github.com/Modernizr/Modernizr/issues/648" 758 },{ 759 "name": "W3 Info", 760 "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface" 761 }] 762} 763!*/ 764 765 var newSyntax = 'CSS' in window && 'supports' in window.CSS; 766 var oldSyntax = 'supportsCSS' in window; 767 Modernizr.addTest('supports', newSyntax || oldSyntax); 768 769 770 /** 771 * getBody returns the body of a document, or an element that can stand in for 772 * the body if a real body does not exist 773 * 774 * @access private 775 * @function getBody 776 * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an 777 * artificially created element that stands in for the body 778 */ 779 780 function getBody() { 781 // After page load injecting a fake body doesn't work so check if body exists 782 var body = document.body; 783 784 if (!body) { 785 // Can't use the real body create a fake one. 786 body = createElement(isSVG ? 'svg' : 'body'); 787 body.fake = true; 788 } 789 790 return body; 791 } 792 793 ; 794 795 /** 796 * injectElementWithStyles injects an element with style element and some CSS rules 797 * 798 * @access private 799 * @function injectElementWithStyles 800 * @param {string} rule - String representing a css rule 801 * @param {function} callback - A function that is used to test the injected element 802 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 803 * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes 804 * @returns {boolean} 805 */ 806 807 function injectElementWithStyles(rule, callback, nodes, testnames) { 808 var mod = 'modernizr'; 809 var style; 810 var ret; 811 var node; 812 var docOverflow; 813 var div = createElement('div'); 814 var body = getBody(); 815 816 if (parseInt(nodes, 10)) { 817 // In order not to give false positives we create a node for each test 818 // This also allows the method to scale for unspecified uses 819 while (nodes--) { 820 node = createElement('div'); 821 node.id = testnames ? testnames[nodes] : mod + (nodes + 1); 822 div.appendChild(node); 823 } 824 } 825 826 style = createElement('style'); 827 style.type = 'text/css'; 828 style.id = 's' + mod; 829 830 // 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. 831 // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 832 (!body.fake ? div : body).appendChild(style); 833 body.appendChild(div); 834 835 if (style.styleSheet) { 836 style.styleSheet.cssText = rule; 837 } else { 838 style.appendChild(document.createTextNode(rule)); 839 } 840 div.id = mod; 841 842 if (body.fake) { 843 //avoid crashing IE8, if background image is used 844 body.style.background = ''; 845 //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible 846 body.style.overflow = 'hidden'; 847 docOverflow = docElement.style.overflow; 848 docElement.style.overflow = 'hidden'; 849 docElement.appendChild(body); 850 } 851 852 ret = callback(div, rule); 853 // If this is done after page load we don't want to remove the body so check if body exists 854 if (body.fake) { 855 body.parentNode.removeChild(body); 856 docElement.style.overflow = docOverflow; 857 // Trigger layout so kinetic scrolling isn't disabled in iOS6+ 858 docElement.offsetHeight; 859 } else { 860 div.parentNode.removeChild(div); 861 } 862 863 return !!ret; 864 865 } 866 867 ; 868 869 /** 870 * Modernizr.mq tests a given media query, live against the current state of the window 871 * adapted from matchMedia polyfill by Scott Jehl and Paul Irish 872 * gist.github.com/786768 873 * 874 * @memberof Modernizr 875 * @name Modernizr.mq 876 * @optionName Modernizr.mq() 877 * @optionProp mq 878 * @access public 879 * @function mq 880 * @param {string} mq - String of the media query we want to test 881 * @returns {boolean} 882 * @example 883 * Modernizr.mq allows for you to programmatically check if the current browser 884 * window state matches a media query. 885 * 886 * ```js 887 * var query = Modernizr.mq('(min-width: 900px)'); 888 * 889 * if (query) { 890 * // the browser window is larger than 900px 891 * } 892 * ``` 893 * 894 * Only valid media queries are supported, therefore you must always include values 895 * with your media query 896 * 897 * ```js 898 * // good 899 * Modernizr.mq('(min-width: 900px)'); 900 * 901 * // bad 902 * Modernizr.mq('min-width'); 903 * ``` 904 * 905 * If you would just like to test that media queries are supported in general, use 906 * 907 * ```js 908 * Modernizr.mq('only all'); // true if MQ are supported, false if not 909 * ``` 910 * 911 * 912 * Note that if the browser does not support media queries (e.g. old IE) mq will 913 * always return false. 914 */ 915 916 var mq = (function() { 917 var matchMedia = window.matchMedia || window.msMatchMedia; 918 if (matchMedia) { 919 return function(mq) { 920 var mql = matchMedia(mq); 921 return mql && mql.matches || false; 922 }; 923 } 924 925 return function(mq) { 926 var bool = false;
927 928 injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) { 929 bool = (window.getComputedStyle ? 930 window.getComputedStyle(node, null) : 931 node.currentStyle).position == 'absolute'; 932 }); 933 934 return bool; 935 }; 936 })(); 937 938 939 ModernizrProto.mq = mq; 940 941 942 943 /** 944 * testStyles injects an element with style element and some CSS rules 945 * 946 * @memberof Modernizr 947 * @name Modernizr.testStyles 948 * @optionName Modernizr.testStyles() 949 * @optionProp testStyles 950 * @access public 951 * @function testStyles 952 * @param {string} rule - String representing a css rule 953 * @param {function} callback - A function that is used to test the injected element 954 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 955 * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes 956 * @returns {boolean} 957 * @example 958 * 959 * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page 960 * along with (possibly multiple) DOM elements. This lets you check for features 961 * 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). 962 * 963 * ```js 964 * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) { 965 * // elem is the first DOM node in the page (by default #modernizr) 966 * // rule is the first argument you supplied - the CSS rule in string form 967 * 968 * addTest('widthworks', elem.style.width === '9px') 969 * }); 970 * ``` 971 * 972 * If your test requires multiple nodes, you can include a third argument 973 * indicating how many additional div elements to include on the page. The 974 * additional nodes are injected as children of the `elem` that is returned as 975 * the first argument to the callback. 976 * 977 * ```js 978 * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) { 979 * document.getElementById('modernizr').style.width === '1px'; // true 980 * document.getElementById('modernizr2').style.width === '2px'; // true 981 * elem.firstChild === document.getElementById('modernizr2'); // true 982 * }, 1); 983 * ``` 984 * 985 * By default, all of the additional elements have an ID of `modernizr[n]`, where 986 * `n` is its index (e.g. the first additional, second overall is `#modernizr2`, 987 * the second additional is `#modernizr3`, etc.). 988 * If you want to have more meaningful IDs for your function, you can provide 989 * them as the fourth argument, as an array of strings 990 * 991 * ```js 992 * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) { 993 * elem.firstChild === document.getElementById('foo'); // true 994 * elem.lastChild === document.getElementById('bar'); // true 995 * }, 2, ['foo', 'bar']); 996 * ``` 997 * 998 */ 999 1000 var testStyles = ModernizrProto.testStyles = injectElementWithStyles; 1001 1002/*! 1003{ 1004 "name": "Touch Events", 1005 "property": "touchevents", 1006 "caniuse" : "touch", 1007 "tags": ["media", "attribute"], 1008 "notes": [{ 1009 "name": "Touch Events spec", 1010 "href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/" 1011 }], 1012 "warnings": [ 1013 "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device" 1014 ], 1015 "knownBugs": [ 1016 "False-positive on some configurations of Nokia N900", 1017 "False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695" 1018 ] 1019} 1020!*/ 1021/* DOC 1022Indicates if the browser supports the W3C Touch Events API. 1023 1024This *does not* necessarily reflect a touchscreen device: 1025 1026* Older touchscreen devices only emulate mouse events 1027* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that 1028* Some browsers & OS setups may enable touch APIs when no touchscreen is connected 1029* Future browsers may implement other event models for touch interactions 1030 1031See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/). 1032 1033It's recommended to bind both mouse and touch/pointer events simultaneously – see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/). 1034 1035This test will also return `true` for Firefox 4 Multitouch support. 1036*/ 1037 1038 // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415 1039 Modernizr.addTest('touchevents', function() { 1040 var bool; 1041 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { 1042 bool = true; 1043 } else { 1044 // include the 'heartz' as a way to have a non matching MQ to help terminate the join 1045 // https://git.io/vznFH 1046 var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join(''); 1047 testStyles(query, function(node) { 1048 bool = node.offsetTop === 9; 1049 }); 1050 } 1051 return bool; 1052 }); 1053 1054/*! 1055{ 1056 "name": "@font-face", 1057 "property": "fontface", 1058 "authors": ["Diego Perini", "Mat Marquis"], 1059 "tags": ["css"], 1060 "knownBugs": [ 1061 "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342", 1062 "False Postive: WP7 https://github.com/Modernizr/Modernizr/issues/538" 1063 ], 1064 "notes": [{ 1065 "name": "@font-face detection routine by Diego Perini", 1066 "href": "http://javascript.nwbox.com/CSSSupport/" 1067 },{ 1068 "name": "Filament Group @font-face compatibility research", 1069 "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_
1069Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p" 1070 },{ 1071 "name": "Filament Grunticon/@font-face device testing results", 1072 "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0" 1073 },{ 1074 "name": "CSS fonts on Android", 1075 "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android" 1076 },{ 1077 "name": "@font-face and Android", 1078 "href": "http://archivist.incutio.com/viewlist/css-discuss/115960" 1079 }] 1080} 1081!*/ 1082 1083 var blacklist = (function() { 1084 var ua = navigator.userAgent; 1085 var wkvers = ua.match(/applewebkit\/([0-9]+)/gi) && parseFloat(RegExp.$1); 1086 var webos = ua.match(/w(eb)?osbrowser/gi); 1087 var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9; 1088 var oldandroid = wkvers < 533 && ua.match(/android/gi); 1089 return webos || oldandroid || wppre8; 1090 }()); 1091 if (blacklist) { 1092 Modernizr.addTest('fontface', false); 1093 } else { 1094 testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) { 1095 var style = document.getElementById('smodernizr'); 1096 var sheet = style.sheet || style.styleSheet; 1097 var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : ''; 1098 var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0; 1099 Modernizr.addTest('fontface', bool); 1100 }); 1101 } 1102; 1103/*! 1104{ 1105 "name": "CSS Generated Content", 1106 "property": "generatedcontent", 1107 "tags": ["css"], 1108 "warnings": ["Android won't return correct height for anything below 7px #738"], 1109 "notes": [{ 1110 "name": "W3C CSS Selectors Level 3 spec", 1111 "href": "https://www.w3.org/TR/css3-selectors/#gen-content" 1112 },{ 1113 "name": "MDN article on :before", 1114 "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before" 1115 },{ 1116 "name": "MDN article on :after", 1117 "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before" 1118 }] 1119} 1120!*/ 1121 1122 testStyles('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}', function(node) { 1123 Modernizr.addTest('generatedcontent', node.offsetHeight >= 7); 1124 }); 1125 1126 1127 var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []); 1128 ModernizrProto._cssomPrefixes = cssomPrefixes; 1129 1130 1131 1132 /** 1133 * contains checks to see if a string contains another string 1134 * 1135 * @access private 1136 * @function contains 1137 * @param {string} str - The string we want to check for substrings 1138 * @param {string} substr - The substring we want to search the first string for 1139 * @returns {boolean} 1140 */ 1141 1142 function contains(str, substr) { 1143 return !!~('' + str).indexOf(substr); 1144 } 1145 1146 ; 1147 1148 /** 1149 * cssToDOM takes a kebab-case string and converts it to camelCase 1150 * e.g. box-sizing -> boxSizing 1151 * 1152 * @access private 1153 * @function cssToDOM 1154 * @param {string} name - String name of kebab-case prop we want to convert 1155 * @returns {string} The camelCase version of the supplied name 1156 */ 1157 1158 function cssToDOM(name) { 1159 return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) { 1160 return m1 + m2.toUpperCase(); 1161 }).replace(/^-/, ''); 1162 } 1163 ; 1164 1165 /** 1166 * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill. 1167 * 1168 * @access private 1169 * @function fnBind 1170 * @param {function} fn - a function you want to change `this` reference to 1171 * @param {object} that - the `this` you want to call the function with 1172 * @returns {function} The wrapped version of the supplied function 1173 */ 1174 1175 function fnBind(fn, that) { 1176 return function() { 1177 return fn.apply(that, arguments); 1178 }; 1179 } 1180 1181 ; 1182 1183 /** 1184 * testDOMProps is a generic DOM property test; if a browser supports 1185 * a certain property, it won't return undefined for it. 1186 * 1187 * @access private 1188 * @function testDOMProps 1189 * @param {array.<string>} props - An array of properties to test for 1190 * @param {object} obj - An object or Element you want to use to test the parameters again 1191 * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check 1192 */ 1193 function testDOMProps(props, obj, elem) { 1194 var item; 1195 1196 for (var i in props) { 1197 if (props[i] in obj) { 1198 1199 // return the property name as a string 1200 if (elem === false) { 1201 return props[i]; 1202 } 1203 1204 item = obj[props[i]]; 1205 1206 // let's bind a function 1207 if (is(item, 'function')) { 1208 // bind to obj unless overriden 1209 return fnBind(item, elem || obj); 1210 } 1211 1212 // return the unbound function or obj or value 1213 return item; 1214 } 1215 } 1216 return false;
1217 } 1218 1219 ; 1220 1221 /** 1222 * Create our "modernizr" element that we do most feature tests on. 1223 * 1224 * @access private 1225 */ 1226 1227 var modElem = { 1228 elem: createElement('modernizr') 1229 }; 1230 1231 // Clean up this element 1232 Modernizr._q.push(function() { 1233 delete modElem.elem; 1234 }); 1235 1236 1237 1238 var mStyle = { 1239 style: modElem.elem.style 1240 }; 1241 1242 // kill ref for gc, must happen before mod.elem is removed, so we unshift on to 1243 // the front of the queue. 1244 Modernizr._q.unshift(function() { 1245 delete mStyle.style; 1246 }); 1247 1248 1249 1250 /** 1251 * domToCSS takes a camelCase string and converts it to kebab-case 1252 * e.g. boxSizing -> box-sizing 1253 * 1254 * @access private 1255 * @function domToCSS 1256 * @param {string} name - String name of camelCase prop we want to convert 1257 * @returns {string} The kebab-case version of the supplied name 1258 */ 1259 1260 function domToCSS(name) { 1261 return name.replace(/([A-Z])/g, function(str, m1) { 1262 return '-' + m1.toLowerCase(); 1263 }).replace(/^ms-/, '-ms-'); 1264 } 1265 ; 1266 1267 /** 1268 * nativeTestProps allows for us to use native feature detection functionality if available. 1269 * some prefixed form, or false, in the case of an unsupported rule 1270 * 1271 * @access private 1272 * @function nativeTestProps 1273 * @param {array} props - An array of property names 1274 * @param {string} value - A string representing the value we want to check via @supports 1275 * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise 1276 */ 1277 1278 // Accepts a list of property names and a single value 1279 // Returns `undefined` if native detection not available 1280 function nativeTestProps(props, value) { 1281 var i = props.length; 1282 // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface 1283 if ('CSS' in window && 'supports' in window.CSS) { 1284 // Try every prefixed variant of the property 1285 while (i--) { 1286 if (window.CSS.supports(domToCSS(props[i]), value)) { 1287 return true; 1288 } 1289 } 1290 return false; 1291 } 1292 // Otherwise fall back to at-rule (for Opera 12.x) 1293 else if ('CSSSupportsRule' in window) { 1294 // Build a condition string for every prefixed variant 1295 var conditionText = []; 1296 while (i--) { 1297 conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')'); 1298 } 1299 conditionText = conditionText.join(' or '); 1300 return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) { 1301 return getComputedStyle(node, null).position == 'absolute'; 1302 }); 1303 } 1304 return undefined; 1305 } 1306 ; 1307 1308 // testProps is a generic CSS / DOM property test. 1309 1310 // In testing support for a given CSS property, it's legit to test: 1311 // `elem.style[styleName] !== undefined` 1312 // If the property is supported it will return an empty string, 1313 // if unsupported it will return undefined. 1314 1315 // We'll take advantage of this quick test and skip setting a style 1316 // on our modernizr element, but instead just testing undefined vs 1317 // empty string. 1318 1319 // Property names can be provided in either camelCase or kebab-case. 1320 1321 function testProps(props, prefixed, value, skipValueTest) { 1322 skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest; 1323 1324 // Try native detect first 1325 if (!is(value, 'undefined')) { 1326 var result = nativeTestProps(props, value); 1327 if (!is(result, 'undefined')) { 1328 return result; 1329 } 1330 } 1331 1332 // Otherwise do it properly 1333 var afterInit, i, propsLength, prop, before; 1334 1335 // If we don't have a style element, that means we're running async or after 1336 // the core tests, so we'll need to create our own elements to use 1337 1338 // inside of an SVG element, in certain browsers, the `style` element is only 1339 // defined for valid tags. Therefore, if `modernizr` does not have one, we 1340 // fall back to a less used element and hope for the best. 1341 // for strict XHTML browsers the hardly used samp element is used 1342 var elems = ['modernizr', 'tspan', 'samp']; 1343 while (!mStyle.style && elems.length) { 1344 afterInit = true; 1345 mStyle.modElem = createElement(elems.shift()); 1346 mStyle.style = mStyle.modElem.style; 1347 } 1348 1349 // Delete the objects if we created them. 1350 function cleanElems() { 1351 if (afterInit) { 1352 delete mStyle.style; 1353 delete mStyle.modElem; 1354 } 1355 } 1356 1357 propsLength = props.length; 1358 for (i = 0; i < propsLength; i++) { 1359 prop = props[i]; 1360 before = mStyle.style[prop]; 1361 1362 if (contains(prop, '-')) { 1363 prop = cssToDOM(prop); 1364 } 1365 1366 if (mStyle.style[prop] !== undefined) { 1367 1368 // If value to test has been passed in, do a set-and-check test. 1369 // 0 (integer) is a valid property value, so check that `value` isn't 1370 // undefined, rather than just checking it's truthy. 1371 if (!skipValueTest && !is(value, 'undefined')) { 1372 1373 // Needs a try catch block because of old IE. This is slow, but will 1374 // be avoided in most cases because `skipValueTest` will be used. 1375 try { 1376 mStyle.style[prop] = value; 1377 } catch (e) {} 1378 1379 // If the property value has changed, we assume the value used is 1380 // supported. If `value` is empty string, it'll fail here (because 1381 // it hasn't changed), which matches how browsers have implemented 1382 // CSS.supports() 1383 if (mStyle.style[prop] != before) { 1384 cleanElems(); 1385 return prefixed == 'pfx' ? prop : true; 1386 } 1387 } 1388 // Otherwise just return true, or the property name if this is a 1389 // `prefixed()` call 1390 else { 1391 cleanElems(); 1392 return prefixed == 'pfx' ? prop : true; 1393 } 1394 } 1395 } 1396 cleanElems(); 1397 return false;
1398 } 1399 1400 ; 1401 1402 /** 1403 * testProp() investigates whether a given style property is recognized 1404 * Property names can be provided in either camelCase or kebab-case. 1405 * 1406 * @memberof Modernizr 1407 * @name Modernizr.testProp 1408 * @access public 1409 * @optionName Modernizr.testProp() 1410 * @optionProp testProp 1411 * @function testProp 1412 * @param {string} prop - Name of the CSS property to check 1413 * @param {string} [value] - Name of the CSS value to check 1414 * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported 1415 * @returns {boolean} 1416 * @example 1417 * 1418 * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed 1419 * version of the string. 1420 * 1421 * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing) 1422 * 1423 * ```js 1424 * Modernizr.testProp('pointerEvents') // true 1425 * ``` 1426 * 1427 * You can also provide a value as an optional second argument to check if a 1428 * specific value is supported 1429 * 1430 * ```js
1431 * Modernizr.testProp('pointerEvents', 'none') // true 1432 * Modernizr.testProp('pointerEvents', 'penguin') // false 1433 * ``` 1434 */ 1435 1436 var testProp = ModernizrProto.testProp = function(prop, value, useValue) { 1437 return testProps([prop], undefined, value, useValue); 1438 }; 1439 1440/*! 1441{ 1442 "name": "CSS textshadow", 1443 "property": "textshadow", 1444 "caniuse": "css-textshadow", 1445 "tags": ["css"], 1446 "knownBugs": ["FF3.0 will false positive on this test"] 1447} 1448!*/ 1449 1450 Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px')); 1451 1452 1453 /** 1454 * testPropsAll tests a list of DOM properties we want to check against. 1455 * We specify literally ALL possible (known and/or likely) properties on 1456 * the element including the non-vendor prefixed one, for forward- 1457 * compatibility. 1458 * 1459 * @access private 1460 * @function testPropsAll 1461 * @param {string} prop - A string of the property to test for 1462 * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip 1463 * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against 1464 * @param {string} [value] - A string of a css value 1465 * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set 1466 */ 1467 function testPropsAll(prop, prefixed, elem, value, skipValueTest) { 1468 1469 var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), 1470 props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); 1471 1472 // did they call .prefixed('boxSizing') or are we just testing a prop? 1473 if (is(prefixed, 'string') || is(prefixed, 'undefined')) { 1474 return testProps(props, prefixed, value, skipValueTest); 1475 1476 // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) 1477 } else { 1478 props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); 1479 return testDOMProps(props, prefixed, elem); 1480 } 1481 } 1482 1483 // Modernizr.testAllProps() investigates whether a given style property, 1484 // or any of its vendor-prefixed variants, is recognized 1485 // 1486 // Note that the property names must be provided in the camelCase variant. 1487 // Modernizr.testAllProps('boxSizing') 1488 ModernizrProto.testAllProps = testPropsAll; 1489 1490 1491 1492 /** 1493 * testAllProps determines whether a given CSS property is supported in the browser 1494 * 1495 * @memberof Modernizr 1496 * @name Modernizr.testAllProps 1497 * @optionName Modernizr.testAllProps() 1498 * @optionProp testAllProps 1499 * @access public 1500 * @function testAllProps 1501 * @param {string} prop - String naming the property to test (either camelCase or kebab-case) 1502 * @param {string} [value] - String of the value to test 1503 * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection 1504 * @example 1505 * 1506 * testAllProps determines whether a given CSS property, in some prefixed form, 1507 * is supported by the browser. 1508 * 1509 * ```js 1510 * testAllProps('boxSizing') // true 1511 * ``` 1512 * 1513 * It can optionally be given a CSS value in string form to test if a property 1514 * value is valid 1515 * 1516 * ```js 1517 * testAllProps('display', 'block') // true 1518 * testAllProps('display', 'penguin') // false 1519 * ``` 1520 * 1521 * A boolean can be passed as a third parameter to skip the value check when 1522 * native detection (@supports) isn't available. 1523 * 1524 * ```js 1525 * testAllProps('shapeOutside', 'content-box', true); 1526 * ``` 1527 */ 1528 1529 function testAllProps(prop, value, skipValueTest) { 1530 return testPropsAll(prop, undefined, undefined, value, skipValueTest); 1531 } 1532 ModernizrProto.testAllProps = testAllProps; 1533 1534/*! 1535{ 1536 "name": "CSS Animations", 1537 "property": "cssanimations", 1538 "caniuse": "css-animation", 1539 "polyfills": ["transformie", "csssandpaper"], 1540 "tags": ["css"], 1541 "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"], 1542 "notes": [{ 1543 "name" : "Article: 'Dispelling the Android CSS animation myths'", 1544 "href": "https://goo.gl/OGw5Gm" 1545 }] 1546} 1547!*/ 1548/* DOC 1549Detects whether or not elements can be animated using CSS 1550*/ 1551 1552 Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true)); 1553 1554/*! 1555{
1556 "name": "Background Size", 1557 "property": "backgroundsize", 1558 "tags": ["css"], 1559 "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"], 1560 "notes": [{ 1561 "name": "Related Issue", 1562 "href": "https://github.com/Modernizr/Modernizr/issues/396" 1563 }] 1564} 1565!*/ 1566 1567 Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true)); 1568 1569/*! 1570{ 1571 "name": "Border Image", 1572 "property": "borderimage", 1573 "caniuse": "border-image", 1574 "polyfills": ["css3pie"], 1575 "knownBugs": ["Android < 2.0 is true, but has a broken implementation"], 1576 "tags": ["css"] 1577} 1578!*/ 1579 1580 Modernizr.addTest('borderimage', testAllProps('borderImage', 'url() 1', true)); 1581 1582/*! 1583{ 1584 "name": "Border Radius", 1585 "property": "borderradius", 1586 "caniuse": "border-radius", 1587 "polyfills": ["css3pie"], 1588 "tags": ["css"], 1589 "notes": [{ 1590 "name": "Comprehensive Compat Chart", 1591 "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance" 1592 }] 1593} 1594!*/ 1595 1596 Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true)); 1597 1598/*! 1599{ 1600 "name": "Box Shadow", 1601 "property": "boxshadow", 1602 "caniuse": "css-boxshadow", 1603 "tags": ["css"], 1604 "knownBugs": [ 1605 "WebOS false positives on this test.", 1606 "The Kindle Silk browser false positives" 1607 ] 1608} 1609!*/ 1610 1611 Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true)); 1612 1613/*! 1614{ 1615 "name": "CSS Transforms", 1616 "property": "csstransforms", 1617 "caniuse": "transforms2d", 1618 "tags": ["css"] 1619} 1620!*/ 1621 1622 Modernizr.addTest('csstransforms', function() { 1623 // Android < 3.0 is buggy, so we sniff and blacklist 1624 // http://git.io/hHzL7w 1625 return navigator.userAgent.indexOf('Android 2.') === -1 && 1626 testAllProps('transform', 'scale(1)', true); 1627 }); 1628 1629/*! 1630{ 1631 "name": "CSS Transforms 3D", 1632 "property": "csstransforms3d", 1633 "caniuse": "transforms3d", 1634 "tags": ["css"], 1635 "warnings": [ 1636 "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004" 1637 ] 1638} 1639!*/ 1640 1641 Modernizr.addTest('csstransforms3d', function() { 1642 var ret = !!testAllProps('perspective', '1px', true); 1643 var usePrefix = Modernizr._config.usePrefixes; 1644 1645 // Webkit's 3D transforms are passed off to the browser's own graphics renderer. 1646 // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in 1647 // some conditions. As a result, Webkit typically recognizes the syntax but 1648 // will sometimes throw a false positive, thus we must do a more thorough check: 1649 if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) { 1650 var mq; 1651 var defaultStyle = '#modernizr{width:0;height:0}'; 1652 // Use CSS Conditional Rules if available 1653 if (Modernizr.supports) { 1654 mq = '@supports (perspective: 1px)'; 1655 } else { 1656 // Otherwise, Webkit allows this media query to succeed only if the feature is enabled. 1657 // `@media (transform-3d),(-webkit-transform-3d){ ... }` 1658 mq = '@media (transform-3d)'; 1659 if (usePrefix) { 1660 mq += ',(-webkit-transform-3d)'; 1661 } 1662 } 1663 1664 mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}'; 1665 1666 testStyles(defaultStyle + mq, function(elem) { 1667 ret = elem.offsetWidth === 7 && elem.offsetHeight === 18; 1668 }); 1669 } 1670 1671 return ret; 1672 }); 1673 1674/*! 1675{ 1676 "name": "CSS Transitions", 1677 "property": "csstransitions", 1678 "caniuse": "css-transitions", 1679 "tags": ["css"] 1680} 1681!*/ 1682 1683 Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true)); 1684 1685 1686 // Run each test 1687 testRunner(); 1688 1689 // Remove the "no-js" class if it exists 1690 setClasses(classes); 1691 1692 delete ModernizrProto.addTest; 1693 delete ModernizrProto.addAsyncTest; 1694 1695 // Run the things that are supposed to run after the tests 1696 for (var i = 0; i < Modernizr._q.length; i++) { 1697 Modernizr._q[i](); 1698 } 1699 1700 // Leak Modernizr namespace 1701 window.Modernizr = Modernizr; 1702 1703 1704; 1705 1706})(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.