1/*! 2 * modernizr v3.3.1 3 * Build http://modernizr.com/download?-csstransforms-details-ellipsis-search-svg-addtest-fnbind-printshiv-setclasses-testprop-dontmin 4 * 5 * Copyright (c) 6 * Faruk Ates 7 * Paul Irish 8 * Alex Sexton 9 * Ryan Seddon 10 * Patrick Kettner 11 * Stu Cox 12 * Richard Herrera 13 14 * MIT License 15 */ 16 17/* 18 * Modernizr tests which native CSS3 and HTML5 features are available in the 19 * current UA and makes the results available to you in two ways: as properties on 20 * a global `Modernizr` object, and as classes on the `<html>` element. This 21 * information allows you to progressively enhance your pages with a granular level 22 * of control over the experience. 23*/ 24 25;(function(window, document, undefined){ 26 var tests = []; 27 28 29 /** 30 * 31 * ModernizrProto is the constructor for Modernizr 32 * 33 * @class 34 * @access public 35 */ 36 37 var ModernizrProto = { 38 // The current version, dummy 39 _version: '3.3.1', 40 41 // Any settings that don't work as separate modules 42 // can go in here as configuration. 43 _config: { 44 'classPrefix': '', 45 'enableClasses': true, 46 'enableJSClass': true, 47 'usePrefixes': true 48 }, 49 50 // Queue of tests 51 _q: [], 52 53 // Stub these for people who are listening 54 on: function(test, cb) { 55 // I don't really think people should do this, but we can 56 // safe guard it a bit. 57 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 58 // This is in case people listen to synchronous tests. I would leave it out, 59 // but the code to *disallow* sync tests in the real version of this 60 // function is actually larger than this. 61 var self = this; 62 setTimeout(function() { 63 cb(self[test]); 64 }, 0); 65 }, 66 67 addTest: function(name, fn, options) { 68 tests.push({name: name, fn: fn, options: options}); 69 }, 70 71 addAsyncTest: function(fn) { 72 tests.push({name: null, fn: fn}); 73 } 74 }; 75 76 77 78 // Fake some of Object.create so we can force non test results to be non "own" properties. 79 var Modernizr = function() {}; 80 Modernizr.prototype = ModernizrProto; 81 82 // Leak modernizr globally when you `require` it rather than force it here. 83 // Overwrite name so constructor name is nicer :D 84 Modernizr = new Modernizr(); 85 86 87 88 var classes = []; 89 90 91 /** 92 * is returns a boolean if the typeof an obj is exactly type. 93 * 94 * @access private 95 * @function is 96 * @param {*} obj - A thing we want to check the type of 97 * @param {string} type - A string to compare the typeof against 98 * @returns {boolean} 99 */ 100 101 function is(obj, type) { 102 return typeof obj === type; 103 } 104 ; 105 106 /** 107 * Run through all tests and detect their support in the current UA. 108 * 109 * @access private 110 */ 111 112 function testRunner() { 113 var featureNames; 114 var feature; 115 var aliasIdx; 116 var result; 117 var nameIdx; 118 var featureName; 119 var featureNameSplit; 120 121 for (var featureIdx in tests) { 122 if (tests.hasOwnProperty(featureIdx)) { 123 featureNames = []; 124 feature = tests[featureIdx]; 125 // run the test, throw the return value into the Modernizr, 126 // then based on that boolean, define an appropriate className 127 // and push it into an array of classes we'll join later. 128 // 129 // If there is no name, it's an 'async' test that is run, 130 // but not directly added to the object. That should 131 // be done with a post-run addTest call. 132 if (feature.name) { 133 featureNames.push(feature.name.toLowerCase()); 134 135 if (feature.options && feature.options.aliases && feature.options.aliases.length) { 136 // Add all the aliases into the names list 137 for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) { 138 featureNames.push(feature.options.aliases[aliasIdx].toLowerCase()); 139 } 140 } 141 } 142 143 // Run the test, or use the raw value if it's not a function 144 result = is(feature.fn, 'function') ? feature.fn() : feature.fn; 145 146 147 // Set each of the names on the Modernizr object 148 for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { 149 featureName = featureNames[nameIdx];
150 // Support dot properties as sub tests. We don't do checking to make sure 151 // that the implied parent tests have been added. You must call them in 152 // order (either in the test, or make the parent test a dependency). 153 // 154 // Cap it to TWO to make the logic simple and because who needs that kind of subtesting 155 // hashtag famous last words 156 featureNameSplit = featureName.split('.'); 157 158 if (featureNameSplit.length === 1) { 159 Modernizr[featureNameSplit[0]] = result; 160 } else { 161 // cast to a Boolean, if not one already 162 /* jshint -W053 */ 163 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 164 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 165 } 166 167 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 168 } 169 170 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 171 } 172 } 173 } 174 } 175 ; 176 177 /** 178 * docElement is a convenience wrapper to grab the root element of the document 179 * 180 * @access private 181 * @returns {HTMLElement|SVGElement} The root element of the document 182 */ 183 184 var docElement = document.documentElement; 185 186 187 /** 188 * A convenience helper to check if the document we are running in is an SVG document 189 * 190 * @access private 191 * @returns {boolean} 192 */ 193 194 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 195 196 197 /** 198 * setClasses takes an array of class names and adds them to the root element 199 * 200 * @access private 201 * @function setClasses 202 * @param {string[]} classes - Array of class names 203 */ 204 205 // Pass in an and array of class names, e.g.:
206 // ['no-webp', 'borderradius', ...] 207 function setClasses(classes) { 208 var className = docElement.className; 209 var classPrefix = Modernizr._config.classPrefix || ''; 210 211 if (isSVG) { 212 className = className.baseVal; 213 } 214 215 // Change `no-js` to `js` (independently of the `enableClasses` option) 216 // Handle classPrefix on this too 217 if (Modernizr._config.enableJSClass) { 218 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 219 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 220 } 221 222 if (Modernizr._config.enableClasses) { 223 // Add the new classes 224 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 225 isSVG ? docElement.className.baseVal = className : docElement.className = className; 226 } 227 228 } 229 230 ; 231 232 /** 233 * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support 234 * 235 * @author kangax 236 * @access private 237 * @function hasOwnProp 238 * @param {object} object - The object to check for a property 239 * @param {string} property - The property to check for 240 * @returns {boolean} 241 */ 242 243 // hasOwnProperty shim by kangax needed for Safari 2.0 support 244 var hasOwnProp; 245 246 (function() { 247 var _hasOwnProperty = ({}).hasOwnProperty; 248 /* istanbul ignore else */ 249 /* we have no way of testing IE 5.5 or safari 2, 250 * so just assume the else gets hit */ 251 if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) { 252 hasOwnProp = function(object, property) { 253 return _hasOwnProperty.call(object, property); 254 }; 255 } 256 else { 257 hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ 258 return ((property in object) && is(object.constructor.prototype[property], 'undefined')); 259 }; 260 } 261 })(); 262 263 264 265 266 // _l tracks listeners for async tests, as well as tests that execute after the initial run 267 ModernizrProto._l = {}; 268 269 /** 270 * Modernizr.on is a way to listen for the completion of async tests. Being 271 * asynchronous, they may not finish before your scripts run. As a result you 272 * will get a possibly false negative `undefined` value. 273 * 274 * @memberof Modernizr 275 * @name Modernizr.on 276 * @access public 277 * @function on 278 * @param {string} feature - String name of the feature detect 279 * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not 280 * @example 281 * 282 * ```js 283 * Modernizr.on('flash', function( result ) { 284 * if (result) { 285 * // the browser has flash 286 * } else { 287 * // the browser does not have flash 288 * } 289 * }); 290 * ``` 291 */ 292 293 ModernizrProto.on = function(feature, cb) { 294 // Create the list of listeners if it doesn't exist 295 if (!this._l[feature]) { 296 this._l[feature] = []; 297 } 298 299 // Push this test on to the listener list 300 this._l[feature].push(cb); 301 302 // If it's already been resolved, trigger it on next tick 303 if (Modernizr.hasOwnProperty(feature)) { 304 // Next Tick 305 setTimeout(function() { 306 Modernizr._trigger(feature, Modernizr[feature]); 307 }, 0); 308 } 309 }; 310 311 /** 312 * _trigger is the private function used to signal test completion and run any 313 * callbacks registered through [Modernizr.on](#modernizr-on) 314 * 315 * @memberof Modernizr 316 * @name Modernizr._trigger 317 * @access private 318 * @function _trigger 319 * @param {string} feature - string name of the feature detect 320 * @param {function|boolean} [res] - A feature detection function, or the boolean = 321 * result of a feature detection function 322 */ 323 324 ModernizrProto._trigger = function(feature, res) { 325 if (!this._l[feature]) { 326 return; 327 } 328 329 var cbs = this._l[feature]; 330 331 // Force async 332 setTimeout(function() { 333 var i, cb; 334 for (i = 0; i < cbs.length; i++) { 335 cb = cbs[i]; 336 cb(res); 337 } 338 }, 0); 339 340 // Don't trigger these again 341 delete this._l[feature]; 342 }; 343 344 /** 345 * addTest allows you to define your own feature detects that are not currently 346 * included in Modernizr (under the covers it's the exact same code Modernizr 347 * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result 348 * will be added onto the Modernizr object, as well as an appropriate className set on 349 * the html element when configured to do so 350 * 351 * @memberof Modernizr 352 * @name Modernizr.addTest 353 * @optionName Modernizr.addTest() 354 * @optionProp addTest 355 * @access public 356 * @function addTest 357 * @param {string|object} feature - The string name of the feature detect, or an 358 * object of feature detect names and test 359 * @param {function|boolean} test - Function returning true if feature is supported, 360 * false if not. Otherwise a boolean representing the results of a feature detection 361 * @example 362 * 363 * The most common way of creating your own feature detects is by calling 364 * `Modernizr.addTest` with a string (preferably just lowercase, without any 365 * punctuation), and a function you want executed that will return a boolean result 366 * 367 * ```js 368 * Modernizr.addTest('itsTuesday', function() { 369 * var d = new Date(); 370 * return d.getDay() === 2; 371 * }); 372 * ``` 373 * 374 * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday, 375 * and to `false` every other day of the week. One thing to notice is that the names of 376 * feature detect functions are always lowercased when added to the Modernizr object. That 377 * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will. 378 * 379 * 380 * Since we only look at the returned value from any feature detection function, 381 * you do not need to actually use a function. For simple detections, just passing 382 * in a statement that will return a boolean value works just fine. 383 * 384 * ```js 385 * Modernizr.addTest('hasJquery', 'jQuery' in window); 386 * ``` 387 * 388 * Just like before, when the above runs `Modernizr.hasjquery` will be true if 389 * jQuery has been included on the page. Not using a function saves a small amount
390 * of overhead for the browser, as well as making your code much more readable. 391 * 392 * Finally, you also have the ability to pass in an object of feature names and 393 * their tests. This is handy if you want to add multiple detections in one go. 394 * The keys should always be a string, and the value can be either a boolean or 395 * function that returns a boolean. 396 * 397 * ```js 398 * var detects = { 399 * 'hasjquery': 'jQuery' in window, 400 * 'itstuesday': function() { 401 * var d = new Date(); 402 * return d.getDay() === 2; 403 * } 404 * } 405 * 406 * Modernizr.addTest(detects); 407 * ``` 408 * 409 * There is really no difference between the first methods and this one, it is 410 * just a convenience to let you write more readable code. 411 */ 412 413 function addTest(feature, test) { 414 415 if (typeof feature == 'object') { 416 for (var key in feature) { 417 if (hasOwnProp(feature, key)) { 418 addTest(key, feature[ key ]); 419 } 420 } 421 } else { 422 423 feature = feature.toLowerCase(); 424 var featureNameSplit = feature.split('.'); 425 var last = Modernizr[featureNameSplit[0]]; 426 427 // Again, we don't check for parent test existence. Get that right, though. 428 if (featureNameSplit.length == 2) { 429 last = last[featureNameSplit[1]]; 430 } 431 432 if (typeof last != 'undefined') { 433 // we're going to quit if you're trying to overwrite an existing test 434 // if we were to allow it, we'd do this: 435 // var re = new RegExp("\\b(no-)?" + feature + "\\b"); 436 // docElement.className = docElement.className.replace( re, '' ); 437 // but, no rly, stuff 'em. 438 return Modernizr; 439 } 440 441 test = typeof test == 'function' ? test() : test; 442 443 // Set the value (this is the magic, right here). 444 if (featureNameSplit.length == 1) { 445 Modernizr[featureNameSplit[0]] = test; 446 } else { 447 // cast to a Boolean, if not one already 448 /* jshint -W053 */ 449 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 450 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 451 } 452 453 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test; 454 } 455 456 // Set a single class (either `feature` or `no-feature`) 457 /* jshint -W041 */ 458 setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]); 459 /* jshint +W041 */ 460 461 // Trigger the event 462 Modernizr._trigger(feature, test); 463 } 464 465 return Modernizr; // allow chaining. 466 } 467 468 // After all the tests are run, add self to the Modernizr prototype 469 Modernizr._q.push(function() { 470 ModernizrProto.addTest = addTest; 471 }); 472 473 474 475 476/** 477 * @optionName html5printshiv 478 * @optionProp html5printshiv 479 */ 480 481 // Take the html5 variable out of the html5shiv scope so we can return it. 482 var html5; 483 if (!isSVG) { 484 485 /** 486 * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 487 */ 488 ;(function(window, document) { 489 /*jshint evil:true */ 490 /** version */ 491 var version = '3.7.3'; 492 493 /** Preset options */ 494 var options = window.html5 || {}; 495 496 /** Used to skip problem elements */ 497 var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; 498 499 /** Not all elements can be cloned in IE **/ 500 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; 501 502 /** Detect whether the browser supports default html5 styles */ 503 var supportsHtml5Styles; 504 505 /** Name of the expando, to work with multiple documents or to re-shiv one document */ 506 var expando = '_html5shiv'; 507 508 /** The id for the the documents expando */ 509 var expanID = 0; 510 511 /** Cached data for each document */ 512 var expandoData = {}; 513 514 /** Detect whether the browser supports unknown elements */ 515 var supportsUnknownElements; 516 517 (function() { 518 try { 519 var a = document.createElement('a'); 520 a.innerHTML = '<xyz></xyz>'; 521 //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles 522 supportsHtml5Styles = ('hidden' in a); 523 524 supportsUnknownElements = a.childNodes.length == 1 || (function() { 525 // assign a false positive if unable to shiv 526 (document.createElement)('a'); 527 var frag = document.createDocumentFragment(); 528 return ( 529 typeof frag.cloneNode == 'undefined' || 530 typeof frag.createDocumentFragment == 'undefined' || 531 typeof frag.createElement == 'undefined' 532 ); 533 }()); 534 } catch(e) { 535 // assign a false positive if detection fails => unable to shiv 536 supportsHtml5Styles = true; 537 supportsUnknownElements = true; 538 } 539 540 }()); 541 542 /*--------------------------------------------------------------------------*/ 543 544 /** 545 * Creates a style sheet with the given CSS text and adds it to the document. 546 * @private 547 * @param {Document} ownerDocument The document. 548 * @param {String} cssText The CSS text. 549 * @returns {StyleSheet} The style element. 550 */ 551 function addStyleSheet(ownerDocument, cssText) { 552 var p = ownerDocument.createElement('p'), 553 parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; 554 555 p.innerHTML = 'x<style>' + cssText + '</style>'; 556 return parent.insertBefore(p.lastChild, parent.firstChild); 557 } 558 559 /** 560 * Returns the value of `html5.elements` as an array.
vendor: 5,922 bytes, lines 561-718
561 * @private 562 * @returns {Array} An array of shived element node names. 563 */ 564 function getElements() { 565 var elements = html5.elements; 566 return typeof elements == 'string' ? elements.split(' ') : elements; 567 } 568 569 /** 570 * Extends the built-in list of html5 elements 571 * @memberOf html5 572 * @param {String|Array} newElements whitespace separated list or array of new element names to shiv 573 * @param {Document} ownerDocument The context document. 574 */ 575 function addElements(newElements, ownerDocument) { 576 var elements = html5.elements; 577 if(typeof elements != 'string'){ 578 elements = elements.join(' '); 579 } 580 if(typeof newElements != 'string'){ 581 newElements = newElements.join(' '); 582 } 583 html5.elements = elements +' '+ newElements; 584 shivDocument(ownerDocument); 585 } 586 587 /** 588 * Returns the data associated to the given document 589 * @private 590 * @param {Document} ownerDocument The document. 591 * @returns {Object} An object of data. 592 */ 593 function getExpandoData(ownerDocument) { 594 var data = expandoData[ownerDocument[expando]]; 595 if (!data) { 596 data = {}; 597 expanID++; 598 ownerDocument[expando] = expanID; 599 expandoData[expanID] = data; 600 } 601 return data; 602 } 603 604 /** 605 * returns a shived element for the given nodeName and document 606 * @memberOf html5 607 * @param {String} nodeName name of the element 608 * @param {Document} ownerDocument The context document. 609 * @returns {Object} The shived element. 610 */ 611 function createElement(nodeName, ownerDocument, data){ 612 if (!ownerDocument) { 613 ownerDocument = document; 614 } 615 if(supportsUnknownElements){ 616 return ownerDocument.createElement(nodeName); 617 } 618 if (!data) { 619 data = getExpandoData(ownerDocument); 620 } 621 var node; 622 623 if (data.cache[nodeName]) { 624 node = data.cache[nodeName].cloneNode(); 625 } else if (saveClones.test(nodeName)) { 626 node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); 627 } else { 628 node = data.createElem(nodeName); 629 } 630 631 // Avoid adding some elements to fragments in IE < 9 because 632 // * Attributes like `name` or `type` cannot be set/changed once an element 633 // is inserted into a document/fragment 634 // * Link elements with `src` attributes that are inaccessible, as with 635 // a 403 response, will cause the tab/window to crash 636 // * Script elements appended to fragments will execute when their `src` 637 // or `text` property is set 638 return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; 639 } 640 641 /** 642 * returns a shived DocumentFragment for the given document 643 * @memberOf html5 644 * @param {Document} ownerDocument The context document. 645 * @returns {Object} The shived DocumentFragment. 646 */ 647 function createDocumentFragment(ownerDocument, data){ 648 if (!ownerDocument) { 649 ownerDocument = document; 650 } 651 if(supportsUnknownElements){ 652 return ownerDocument.createDocumentFragment(); 653 } 654 data = data || getExpandoData(ownerDocument); 655 var clone = data.frag.cloneNode(), 656 i = 0, 657 elems = getElements(), 658 l = elems.length; 659 for(;i<l;i++){ 660 clone.createElement(elems[i]); 661 } 662 return clone; 663 } 664 665 /** 666 * Shivs the `createElement` and `createDocumentFragment` methods of the document. 667 * @private 668 * @param {Document|DocumentFragment} ownerDocument The document. 669 * @param {Object} data of the document. 670 */ 671 function shivMethods(ownerDocument, data) { 672 if (!data.cache) { 673 data.cache = {}; 674 data.createElem = ownerDocument.createElement; 675 data.createFrag = ownerDocument.createDocumentFragment; 676 data.frag = data.createFrag(); 677 } 678 679 680 ownerDocument.createElement = function(nodeName) { 681 //abort shiv 682 if (!html5.shivMethods) { 683 return data.createElem(nodeName); 684 } 685 return createElement(nodeName, ownerDocument, data); 686 }; 687 688 ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' + 689 'var n=f.cloneNode(),c=n.createElement;' + 690 'h.shivMethods&&(' + 691 // unroll the `createElement` calls 692 getElements().join().replace(/[\w\-:]+/g, function(nodeName) { 693 data.createElem(nodeName); 694 data.frag.createElement(nodeName); 695 return 'c("' + nodeName + '")'; 696 }) + 697 ');return n}' 698 )(html5, data.frag); 699 } 700 701 /*--------------------------------------------------------------------------*/ 702 703 /** 704 * Shivs the given document. 705 * @memberOf html5 706 * @param {Document} ownerDocument The document to shiv. 707 * @returns {Document} The shived document. 708 */ 709 function shivDocument(ownerDocument) { 710 if (!ownerDocument) { 711 ownerDocument = document; 712 } 713 var data = getExpandoData(ownerDocument); 714 715 if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) { 716 data.hasCSS = !!addStyleSheet(ownerDocument, 717 // corrects block display not defined in IE6/7/8/9 718 'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
718play:block}' + 719 // adds styling not present in IE6/7/8/9 720 'mark{background:#FF0;color:#000}' + 721 // hides non-rendered elements 722 'template{display:none}' 723 ); 724 } 725 if (!supportsUnknownElements) { 726 shivMethods(ownerDocument, data); 727 } 728 return ownerDocument; 729 } 730 731 /*--------------------------------------------------------------------------*/ 732 733 /** 734 * The `html5` object is exposed so that more elements can be shived and 735 * existing shiving can be detected on iframes. 736 * @type Object 737 * @example 738 * 739 * // options can be changed before the script is included 740 * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false }; 741 */ 742 var html5 = { 743 744 /** 745 * An array or space separated string of node names of the elements to shiv. 746 * @memberOf html5 747 * @type Array|String 748 */ 749 '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', 750 751 /** 752 * current version of html5shiv 753 */ 754 'version': version, 755 756 /** 757 * A flag to indicate that the HTML5 style sheet should be inserted. 758 * @memberOf html5 759 * @type Boolean 760 */ 761 'shivCSS': (options.shivCSS !== false), 762 763 /** 764 * Is equal to true if a browser supports creating unknown/HTML5 elements 765 * @memberOf html5 766 * @type boolean 767 */ 768 'supportsUnknownElements': supportsUnknownElements, 769 770 /** 771 * A flag to indicate that the document's `createElement` and `createDocumentFragment` 772 * methods should be overwritten. 773 * @memberOf html5 774 * @type Boolean 775 */ 776 'shivMethods': (options.shivMethods !== false), 777 778 /** 779 * A string to describe the type of `html5` object ("default" or "default print"). 780 * @memberOf html5
vendor: 7,715 bytes, lines 781-1024
781 * @type String 782 */ 783 'type': 'default', 784 785 // shivs the document according to the specified `html5` object options 786 'shivDocument': shivDocument, 787 788 //creates a shived element 789 createElement: createElement, 790 791 //creates a shived documentFragment 792 createDocumentFragment: createDocumentFragment, 793 794 //extends list of elements 795 addElements: addElements 796 }; 797 798 /*--------------------------------------------------------------------------*/ 799 800 // expose html5 801 window.html5 = html5; 802 803 // shiv the document 804 shivDocument(document); 805 806 /*------------------------------- Print Shiv -------------------------------*/ 807 808 /** Used to filter media types */ 809 var reMedia = /^$|\b(?:all|print)\b/; 810 811 /** Used to namespace printable elements */ 812 var shivNamespace = 'html5shiv'; 813 814 /** Detect whether the browser supports shivable style sheets */ 815 var supportsShivableSheets = !supportsUnknownElements && (function() { 816 // assign a false negative if unable to shiv 817 var docEl = document.documentElement; 818 return !( 819 typeof document.namespaces == 'undefined' || 820 typeof document.parentWindow == 'undefined' || 821 typeof docEl.applyElement == 'undefined' || 822 typeof docEl.removeNode == 'undefined' || 823 typeof window.attachEvent == 'undefined' 824 ); 825 }()); 826 827 /*--------------------------------------------------------------------------*/ 828 829 /** 830 * Wraps all HTML5 elements in the given document with printable elements. 831 * (eg. the "header" element is wrapped with the "html5shiv:header" element) 832 * @private 833 * @param {Document} ownerDocument The document. 834 * @returns {Array} An array wrappers added. 835 */ 836 function addWrappers(ownerDocument) { 837 var node, 838 nodes = ownerDocument.getElementsByTagName('*'), 839 index = nodes.length, 840 reElements = RegExp('^(?:' + getElements().join('|') + ')$', 'i'), 841 result = []; 842 843 while (index--) { 844 node = nodes[index]; 845 if (reElements.test(node.nodeName)) { 846 result.push(node.applyElement(createWrapper(node))); 847 } 848 } 849 return result; 850 } 851 852 /** 853 * Creates a printable wrapper for the given element. 854 * @private 855 * @param {Element} element The element. 856 * @returns {Element} The wrapper. 857 */ 858 function createWrapper(element) { 859 var node, 860 nodes = element.attributes, 861 index = nodes.length, 862 wrapper = element.ownerDocument.createElement(shivNamespace + ':' + element.nodeName); 863 864 // copy element attributes to the wrapper 865 while (index--) { 866 node = nodes[index]; 867 node.specified && wrapper.setAttribute(node.nodeName, node.nodeValue); 868 } 869 // copy element styles to the wrapper 870 wrapper.style.cssText = element.style.cssText; 871 return wrapper; 872 } 873 874 /** 875 * Shivs the given CSS text. 876 * (eg. header{} becomes html5shiv\:header{}) 877 * @private 878 * @param {String} cssText The CSS text to shiv. 879 * @returns {String} The shived CSS text. 880 */ 881 function shivCssText(cssText) { 882 var pair, 883 parts = cssText.split('{'), 884 index = parts.length, 885 reElements = RegExp('(^|[\\s,>+~])(' + getElements().join('|') + ')(?=[[\\s,>+~#.:]|$)', 'gi'), 886 replacement = '$1' + shivNamespace + '\\:$2'; 887 888 while (index--) { 889 pair = parts[index] = parts[index].split('}'); 890 pair[pair.length - 1] = pair[pair.length - 1].replace(reElements, replacement); 891 parts[index] = pair.join('}'); 892 } 893 return parts.join('{'); 894 } 895 896 /** 897 * Removes the given wrappers, leaving the original elements. 898 * @private 899 * @params {Array} wrappers An array of printable wrappers. 900 */ 901 function removeWrappers(wrappers) { 902 var index = wrappers.length; 903 while (index--) { 904 wrappers[index].removeNode(); 905 } 906 } 907 908 /*--------------------------------------------------------------------------*/ 909 910 /** 911 * Shivs the given document for print. 912 * @memberOf html5 913 * @param {Document} ownerDocument The document to shiv. 914 * @returns {Document} The shived document. 915 */ 916 function shivPrint(ownerDocument) { 917 var shivedSheet, 918 wrappers, 919 data = getExpandoData(ownerDocument), 920 namespaces = ownerDocument.namespaces, 921 ownerWindow = ownerDocument.parentWindow; 922 923 if (!supportsShivableSheets || ownerDocument.printShived) { 924 return ownerDocument; 925 } 926 if (typeof namespaces[shivNamespace] == 'undefined') { 927 namespaces.add(shivNamespace); 928 } 929 930 function removeSheet() { 931 clearTimeout(data._removeSheetTimer); 932 if (shivedSheet) { 933 shivedSheet.removeNode(true); 934 } 935 shivedSheet= null; 936 } 937 938 ownerWindow.attachEvent('onbeforeprint', function() { 939 940 removeSheet(); 941 942 var imports, 943 length, 944 sheet, 945 collection = ownerDocument.styleSheets, 946 cssText = [], 947 index = collection.length, 948 sheets = Array(index); 949 950 // convert styleSheets collection to an array 951 while (index--) { 952 sheets[index] = collection[index]; 953 } 954 // concat all style sheet CSS text 955 while ((sheet = sheets.pop())) { 956 // IE does not enforce a same origin policy for external style sheets... 957 // but has trouble with some dynamically created stylesheets 958 if (!sheet.disabled && reMedia.test(sheet.media)) { 959 960 try { 961 imports = sheet.imports; 962 length = imports.length; 963 } catch(er){ 964 length = 0; 965 } 966 967 for (index = 0; index < length; index++) { 968 sheets.push(imports[index]); 969 } 970 971 try { 972 cssText.push(sheet.cssText); 973 } catch(er){} 974 } 975 } 976 977 // wrap all HTML5 elements with printable elements and add the shived style sheet 978 cssText = shivCssText(cssText.reverse().join('')); 979 wrappers = addWrappers(ownerDocument); 980 shivedSheet = addStyleSheet(ownerDocument, cssText); 981 982 }); 983 984 ownerWindow.attachEvent('onafterprint', function() { 985 // remove wrappers, leaving the original elements, and remove the shived style sheet 986 removeWrappers(wrappers); 987 clearTimeout(data._removeSheetTimer); 988 data._removeSheetTimer = setTimeout(removeSheet, 500); 989 }); 990 991 ownerDocument.printShived = true; 992 return ownerDocument; 993 } 994 995 /*--------------------------------------------------------------------------*/ 996 997 // expose API 998 html5.type += ' print'; 999 html5.shivPrint = shivPrint; 1000 1001 // shiv for print 1002 shivPrint(document); 1003 1004 if(typeof module == 'object' && module.exports){ 1005 module.exports = html5; 1006 } 1007 1008 }(typeof window !== "undefined" ? window : this, document)); 1009 } 1010 1011 ; 1012 1013 1014 /** 1015 * contains checks to see if a string contains another string 1016 * 1017 * @access private 1018 * @function contains 1019 * @param {string} str - The string we want to check for substrings 1020 * @param {string} substr - The substring we want to search the first string for 1021 * @returns {boolean} 1022 */ 1023 1024 function contains(str, substr) {
1025 return !!~('' + str).indexOf(substr); 1026 } 1027 1028 ; 1029 1030 /** 1031 * createElement is a convenience wrapper around document.createElement. Since we 1032 * use createElement all over the place, this allows for (slightly) smaller code 1033 * as well as abstracting away issues with creating elements in contexts other than 1034 * HTML documents (e.g. SVG documents). 1035 * 1036 * @access private 1037 * @function createElement 1038 * @returns {HTMLElement|SVGElement} An HTML or SVG element 1039 */ 1040 1041 function createElement() { 1042 if (typeof document.createElement !== 'function') { 1043 // This is the case in IE7, where the type of createElement is "object". 1044 // For this reason, we cannot call apply() as Object is not a Function. 1045 return document.createElement(arguments[0]); 1046 } else if (isSVG) { 1047 return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); 1048 } else { 1049 return document.createElement.apply(document, arguments); 1050 } 1051 } 1052 1053 ; 1054 1055 /** 1056 * Create our "modernizr" element that we do most feature tests on. 1057 * 1058 * @access private 1059 */ 1060 1061 var modElem = { 1062 elem: createElement('modernizr') 1063 }; 1064 1065 // Clean up this element 1066 Modernizr._q.push(function() { 1067 delete modElem.elem; 1068 }); 1069 1070 1071 1072 var mStyle = { 1073 style: modElem.elem.style 1074 }; 1075 1076 // kill ref for gc, must happen before mod.elem is removed, so we unshift on to 1077 // the front of the queue. 1078 Modernizr._q.unshift(function() { 1079 delete mStyle.style; 1080 }); 1081 1082 1083 1084 /** 1085 * getBody returns the body of a document, or an element that can stand in for 1086 * the body if a real body does not exist 1087 * 1088 * @access private 1089 * @function getBody 1090 * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an 1091 * artificially created element that stands in for the body 1092 */ 1093 1094 function getBody() { 1095 // After page load injecting a fake body doesn't work so check if body exists 1096 var body = document.body; 1097 1098 if (!body) { 1099 // Can't use the real body create a fake one. 1100 body = createElement(isSVG ? 'svg' : 'body'); 1101 body.fake = true; 1102 } 1103 1104 return body; 1105 } 1106 1107 ; 1108 1109 /** 1110 * injectElementWithStyles injects an element with style element and some CSS rules 1111 * 1112 * @access private 1113 * @function injectElementWithStyles 1114 * @param {string} rule - String representing a css rule 1115 * @param {function} callback - A function that is used to test the injected element 1116 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 1117 * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes 1118 * @returns {boolean} 1119 */ 1120 1121 function injectElementWithStyles(rule, callback, nodes, testnames) { 1122 var mod = 'modernizr'; 1123 var style; 1124 var ret; 1125 var node; 1126 var docOverflow; 1127 var div = createElement('div'); 1128 var body = getBody(); 1129 1130 if (parseInt(nodes, 10)) { 1131 // In order not to give false positives we create a node for each test 1132 // This also allows the method to scale for unspecified uses 1133 while (nodes--) { 1134 node = createElement('div'); 1135 node.id = testnames ? testnames[nodes] : mod + (nodes + 1); 1136 div.appendChild(node); 1137 } 1138 } 1139 1140 style = createElement('style'); 1141 style.type = 'text/css'; 1142 style.id = 's' + mod; 1143 1144 // 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. 1145 // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 1146 (!body.fake ? div : body).appendChild(style); 1147 body.appendChild(div); 1148 1149 if (style.styleSheet) { 1150 style.styleSheet.cssText = rule; 1151 } else { 1152 style.appendChild(document.createTextNode(rule)); 1153 } 1154 div.id = mod; 1155 1156 if (body.fake) { 1157 //avoid crashing IE8, if background image is used 1158 body.style.background = ''; 1159 //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible 1160 body.style.overflow = 'hidden'; 1161 docOverflow = docElement.style.overflow; 1162 docElement.style.overflow = 'hidden'; 1163 docElement.appendChild(body); 1164 } 1165 1166 ret = callback(div, rule); 1167 // If this is done after page load we don't want to remove the body so check if body exists 1168 if (body.fake) { 1169 body.parentNode.removeChild(body); 1170 docElement.style.overflow = docOverflow; 1171 // Trigger layout so kinetic scrolling isn't disabled in iOS6+ 1172 docElement.offsetHeight; 1173 } else { 1174 div.parentNode.removeChild(div); 1175 } 1176 1177 return !!ret; 1178 1179 } 1180 1181 ; 1182 1183 /** 1184 * domToCSS takes a camelCase string and converts it to kebab-case 1185 * e.g. boxSizing -> box-sizing 1186 * 1187 * @access private 1188 * @function domToCSS 1189 * @param {string} name - String name of camelCase prop we want to convert 1190 * @returns {string} The kebab-case version of the supplied name 1191 */ 1192 1193 function domToCSS(name) { 1194 return name.replace(/([A-Z])/g, function(str, m1) { 1195 return '-' + m1.toLowerCase(); 1196 }).replace(/^ms-/, '-ms-'); 1197 } 1198 ; 1199 1200 /** 1201 * nativeTestProps allows for us to use native feature detection functionality if available. 1202 * some prefixed form, or false, in the case of an unsupported rule 1203 * 1204 * @access private 1205 * @function nativeTestProps 1206 * @param {array} props - An array of property names 1207 * @param {string} value - A string representing the value we want to check via @supports 1208 * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise 1209 */ 1210 1211 // Accepts a list of property names and a single value 1212 // Returns `undefined` if native detection not available 1213 function nativeTestProps(props, value) { 1214 var i = props.length; 1215 // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface 1216 if ('CSS' in window && 'supports' in window.CSS) { 1217 // Try every prefixed variant of the property 1218 while (i--) { 1219 if (window.CSS.supports(domToCSS(props[i]), value)) { 1220 return true; 1221 } 1222 } 1223 return false;
1224 } 1225 // Otherwise fall back to at-rule (for Opera 12.x) 1226 else if ('CSSSupportsRule' in window) { 1227 // Build a condition string for every prefixed variant 1228 var conditionText = []; 1229 while (i--) { 1230 conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')'); 1231 } 1232 conditionText = conditionText.join(' or '); 1233 return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) { 1234 return getComputedStyle(node, null).position == 'absolute'; 1235 }); 1236 } 1237 return undefined; 1238 } 1239 ; 1240 1241 /** 1242 * cssToDOM takes a kebab-case string and converts it to camelCase 1243 * e.g. box-sizing -> boxSizing 1244 * 1245 * @access private 1246 * @function cssToDOM 1247 * @param {string} name - String name of kebab-case prop we want to convert 1248 * @returns {string} The camelCase version of the supplied name 1249 */ 1250 1251 function cssToDOM(name) { 1252 return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) { 1253 return m1 + m2.toUpperCase(); 1254 }).replace(/^-/, ''); 1255 } 1256 ; 1257 1258 // testProps is a generic CSS / DOM property test. 1259 1260 // In testing support for a given CSS property, it's legit to test: 1261 // `elem.style[styleName] !== undefined` 1262 // If the property is supported it will return an empty string, 1263 // if unsupported it will return undefined. 1264 1265 // We'll take advantage of this quick test and skip setting a style 1266 // on our modernizr element, but instead just testing undefined vs 1267 // empty string. 1268 1269 // Property names can be provided in either camelCase or kebab-case. 1270 1271 function testProps(props, prefixed, value, skipValueTest) { 1272 skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest; 1273 1274 // Try native detect first 1275 if (!is(value, 'undefined')) { 1276 var result = nativeTestProps(props, value); 1277 if (!is(result, 'undefined')) { 1278 return result; 1279 } 1280 } 1281 1282 // Otherwise do it properly 1283 var afterInit, i, propsLength, prop, before; 1284 1285 // If we don't have a style element, that means we're running async or after 1286 // the core tests, so we'll need to create our own elements to use 1287 1288 // inside of an SVG element, in certain browsers, the `style` element is only 1289 // defined for valid tags. Therefore, if `modernizr` does not have one, we 1290 // fall back to a less used element and hope for the best. 1291 var elems = ['modernizr', 'tspan']; 1292 while (!mStyle.style) { 1293 afterInit = true; 1294 mStyle.modElem = createElement(elems.shift()); 1295 mStyle.style = mStyle.modElem.style; 1296 } 1297 1298 // Delete the objects if we created them. 1299 function cleanElems() { 1300 if (afterInit) { 1301 delete mStyle.style; 1302 delete mStyle.modElem; 1303 } 1304 } 1305 1306 propsLength = props.length; 1307 for (i = 0; i < propsLength; i++) { 1308 prop = props[i]; 1309 before = mStyle.style[prop]; 1310 1311 if (contains(prop, '-')) { 1312 prop = cssToDOM(prop); 1313 } 1314 1315 if (mStyle.style[prop] !== undefined) { 1316 1317 // If value to test has been passed in, do a set-and-check test. 1318 // 0 (integer) is a valid property value, so check that `value` isn't 1319 // undefined, rather than just checking it's truthy. 1320 if (!skipValueTest && !is(value, 'undefined')) { 1321 1322 // Needs a try catch block because of old IE. This is slow, but will 1323 // be avoided in most cases because `skipValueTest` will be used. 1324 try { 1325 mStyle.style[prop] = value; 1326 } catch (e) {} 1327 1328 // If the property value has changed, we assume the value used is 1329 // supported. If `value` is empty string, it'll fail here (because 1330 // it hasn't changed), which matches how browsers have implemented 1331 // CSS.supports() 1332 if (mStyle.style[prop] != before) { 1333 cleanElems(); 1334 return prefixed == 'pfx' ? prop : true; 1335 } 1336 } 1337 // Otherwise just return true, or the property name if this is a 1338 // `prefixed()` call 1339 else { 1340 cleanElems(); 1341 return prefixed == 'pfx' ? prop : true; 1342 } 1343 } 1344 } 1345 cleanElems(); 1346 return false;
1347 } 1348 1349 ; 1350 1351 /** 1352 * testProp() investigates whether a given style property is recognized 1353 * Property names can be provided in either camelCase or kebab-case. 1354 * 1355 * @memberof Modernizr 1356 * @name Modernizr.testProp 1357 * @access public 1358 * @optionName Modernizr.testProp() 1359 * @optionProp testProp 1360 * @function testProp 1361 * @param {string} prop - Name of the CSS property to check 1362 * @param {string} [value] - Name of the CSS value to check 1363 * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported 1364 * @returns {boolean} 1365 * @example 1366 * 1367 * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed 1368 * version of the string. 1369 * 1370 * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing) 1371 * 1372 * ```js 1373 * Modernizr.testProp('pointerEvents') // true 1374 * ``` 1375 * 1376 * You can also provide a value as an optional second argument to check if a 1377 * specific value is supported 1378 * 1379 * ```js
1380 * Modernizr.testProp('pointerEvents', 'none') // true 1381 * Modernizr.testProp('pointerEvents', 'penguin') // false 1382 * ``` 1383 */ 1384 1385 var testProp = ModernizrProto.testProp = function(prop, value, useValue) { 1386 return testProps([prop], undefined, value, useValue); 1387 }; 1388 1389 1390 /** 1391 * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill. 1392 * 1393 * @access private 1394 * @function fnBind 1395 * @param {function} fn - a function you want to change `this` reference to 1396 * @param {object} that - the `this` you want to call the function with 1397 * @returns {function} The wrapped version of the supplied function 1398 */ 1399 1400 function fnBind(fn, that) { 1401 return function() { 1402 return fn.apply(that, arguments); 1403 }; 1404 } 1405 1406 ; 1407 1408 /** 1409 * Modernizr.hasEvent() detects support for a given event 1410 * 1411 * @memberof Modernizr 1412 * @name Modernizr.hasEvent 1413 * @optionName Modernizr.hasEvent() 1414 * @optionProp hasEvent 1415 * @access public 1416 * @function hasEvent 1417 * @param {string|*} eventName - the name of an event to test for (e.g. "resize") 1418 * @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on 1419 * @returns {boolean} 1420 * @example 1421 * `Modernizr.hasEvent` lets you determine if the browser supports a supplied event. 1422 * By default, it does this detection on a div element 1423 * 1424 * ```js 1425 * hasEvent('blur') // true; 1426 * ``` 1427 * 1428 * However, you are able to give an object as a second argument to hasEvent to 1429 * detect an event on something other than a div. 1430 * 1431 * ```js 1432 * hasEvent('devicelight', window) // true; 1433 * ``` 1434 * 1435 */ 1436 1437 var hasEvent = (function() { 1438 1439 // Detect whether event support can be detected via `in`. Test on a DOM element 1440 // using the "blur" event b/c it should always exist. bit.ly/event-detection 1441 var needsFallback = !('onblur' in document.documentElement); 1442 1443 function inner(eventName, element) { 1444 1445 var isSupported; 1446 if (!eventName) { return false; } 1447 if (!element || typeof element === 'string') { 1448 element = createElement(element || 'div'); 1449 } 1450 1451 // Testing via the `in` operator is sufficient for modern browsers and IE. 1452 // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and 1453 // "resize", whereas `in` "catches" those. 1454 eventName = 'on' + eventName; 1455 isSupported = eventName in element; 1456 1457 // Fallback technique for old Firefox - bit.ly/event-detection 1458 if (!isSupported && needsFallback) { 1459 if (!element.setAttribute) { 1460 // Switch to generic element if it lacks `setAttribute`. 1461 // It could be the `document`, `window`, or something else. 1462 element = createElement('div'); 1463 } 1464 1465 element.setAttribute(eventName, ''); 1466 isSupported = typeof element[eventName] === 'function'; 1467 1468 if (element[eventName] !== undefined) { 1469 // If property was created, "remove it" by setting value to `undefined`. 1470 element[eventName] = undefined; 1471 } 1472 element.removeAttribute(eventName); 1473 } 1474 1475 return isSupported; 1476 } 1477 return inner; 1478 })(); 1479 1480 1481 ModernizrProto.hasEvent = hasEvent; 1482 1483/*! 1484{ 1485 "name": "input[search] search event", 1486 "property": "search", 1487 "tags": ["input","search"], 1488 "authors": ["Calvin Webster"], 1489 "notes": [{ 1490 "name": "Wufoo demo", 1491 "href": "https://www.wufoo.com/html5/types/5-search.html?" 1492 }, { 1493 "name": "CSS Tricks", 1494 "href": "https://css-tricks.com/webkit-html5-search-inputs/" 1495 }] 1496} 1497!*/ 1498/* DOC 1499There is a custom `search` event implemented in webkit browsers when using an `input[search]` element. 1500*/ 1501 1502 Modernizr.addTest('inputsearchevent', hasEvent('search')); 1503 1504/*! 1505{ 1506 "name": "SVG", 1507 "property": "svg", 1508 "caniuse": "svg", 1509 "tags": ["svg"], 1510 "authors": ["Erik Dahlstrom"], 1511 "polyfills": [ 1512 "svgweb", 1513 "raphael", 1514 "amplesdk", 1515 "canvg", 1516 "svg-boilerplate", 1517 "sie", 1518 "dojogfx", 1519 "fabricjs" 1520 ] 1521} 1522!*/ 1523/* DOC 1524Detects support for SVG in `<embed>` or `<object>` elements. 1525*/ 1526 1527 Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect); 1528 1529 1530 /** 1531 * If the browsers follow the spec, then they would expose vendor-specific style as: 1532 * elem.style.WebkitBorderRadius 1533 * instead of something like the following, which would be technically incorrect: 1534 * elem.style.webkitBorderRadius 1535 1536 * Webkit ghosts their properties in lowercase but Opera & Moz do not. 1537 * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ 1538 * erik.eae.net/archives/2008/03/10/21.48.10/ 1539 1540 * More here: github.com/Modernizr/Modernizr/issues/issue/21 1541 * 1542 * @access private 1543 * @returns {string} The string representing the vendor-specific style properties 1544 */ 1545 1546 var omPrefixes = 'Moz O ms Webkit'; 1547 1548 1549 var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []); 1550 ModernizrProto._cssomPrefixes = cssomPrefixes; 1551 1552 1553 /** 1554 * List of JavaScript DOM values used for tests 1555 * 1556 * @memberof Modernizr 1557 * @name Modernizr._domPrefixes 1558 * @optionName Modernizr._domPrefixes 1559 * @optionProp domPrefixes 1560 * @access public 1561 * @example 1562 * 1563 * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather 1564 * than kebab-case properties, all properties are their Capitalized variant 1565 * 1566 * ```js 1567 * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ]; 1568 * ``` 1569 */ 1570 1571 var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []); 1572 ModernizrProto._domPrefixes = domPrefixes; 1573 1574 1575 /** 1576 * testDOMProps is a generic DOM property test; if a browser supports 1577 * a certain property, it won't return undefined for it. 1578 * 1579 * @access private 1580 * @function testDOMProps 1581 * @param {array.<string>} props - An array of properties to test for 1582 * @param {object} obj - An object or Element you want to use to test the parameters again 1583 * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check 1584 */ 1585 function testDOMProps(props, obj, elem) { 1586 var item; 1587 1588 for (var i in props) { 1589 if (props[i] in obj) { 1590 1591 // return the property name as a string 1592 if (elem === false) { 1593 return props[i]; 1594 } 1595 1596 item = obj[props[i]]; 1597 1598 // let's bind a function 1599 if (is(item, 'function')) { 1600 // bind to obj unless overriden 1601 return fnBind(item, elem || obj); 1602 } 1603 1604 // return the unbound function or obj or value 1605 return item; 1606 } 1607 } 1608 return false;
1609 } 1610 1611 ; 1612 1613 /** 1614 * testPropsAll tests a list of DOM properties we want to check against. 1615 * We specify literally ALL possible (known and/or likely) properties on 1616 * the element including the non-vendor prefixed one, for forward- 1617 * compatibility. 1618 * 1619 * @access private 1620 * @function testPropsAll 1621 * @param {string} prop - A string of the property to test for 1622 * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip 1623 * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against 1624 * @param {string} [value] - A string of a css value 1625 * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set 1626 */ 1627 function testPropsAll(prop, prefixed, elem, value, skipValueTest) { 1628 1629 var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), 1630 props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); 1631 1632 // did they call .prefixed('boxSizing') or are we just testing a prop? 1633 if (is(prefixed, 'string') || is(prefixed, 'undefined')) { 1634 return testProps(props, prefixed, value, skipValueTest); 1635 1636 // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) 1637 } else { 1638 props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); 1639 return testDOMProps(props, prefixed, elem); 1640 } 1641 } 1642 1643 // Modernizr.testAllProps() investigates whether a given style property, 1644 // or any of its vendor-prefixed variants, is recognized 1645 // 1646 // Note that the property names must be provided in the camelCase variant. 1647 // Modernizr.testAllProps('boxSizing') 1648 ModernizrProto.testAllProps = testPropsAll; 1649 1650 1651 1652 /** 1653 * testAllProps determines whether a given CSS property is supported in the browser 1654 * 1655 * @memberof Modernizr 1656 * @name Modernizr.testAllProps 1657 * @optionName Modernizr.testAllProps() 1658 * @optionProp testAllProps 1659 * @access public 1660 * @function testAllProps 1661 * @param {string} prop - String naming the property to test (either camelCase or kebab-case) 1662 * @param {string} [value] - String of the value to test 1663 * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection 1664 * @example 1665 * 1666 * testAllProps determines whether a given CSS property, in some prefixed form, 1667 * is supported by the browser. 1668 * 1669 * ```js 1670 * testAllProps('boxSizing') // true 1671 * ``` 1672 * 1673 * It can optionally be given a CSS value in string form to test if a property 1674 * value is valid 1675 * 1676 * ```js 1677 * testAllProps('display', 'block') // true 1678 * testAllProps('display', 'penguin') // false 1679 * ``` 1680 * 1681 * A boolean can be passed as a third parameter to skip the value check when 1682 * native detection (@supports) isn't available. 1683 * 1684 * ```js 1685 * testAllProps('shapeOutside', 'content-box', true); 1686 * ``` 1687 */ 1688 1689 function testAllProps(prop, value, skipValueTest) { 1690 return testPropsAll(prop, undefined, undefined, value, skipValueTest); 1691 } 1692 ModernizrProto.testAllProps = testAllProps; 1693 1694/*! 1695{ 1696 "name": "CSS text-overflow ellipsis", 1697 "property": "ellipsis", 1698 "caniuse": "text-overflow", 1699 "polyfills": [ 1700 "text-overflow" 1701 ], 1702 "tags": ["css"] 1703} 1704!*/ 1705 1706 Modernizr.addTest('ellipsis', testAllProps('textOverflow', 'ellipsis')); 1707 1708/*! 1709{ 1710 "name": "CSS Transforms", 1711 "property": "csstransforms", 1712 "caniuse": "transforms2d", 1713 "tags": ["css"] 1714} 1715!*/ 1716 1717 Modernizr.addTest('csstransforms', function() { 1718 // Android < 3.0 is buggy, so we sniff and blacklist 1719 // http://git.io/hHzL7w 1720 return navigator.userAgent.indexOf('Android 2.') === -1 && 1721 testAllProps('transform', 'scale(1)', true); 1722 }); 1723 1724 1725 /** 1726 * testStyles injects an element with style element and some CSS rules 1727 * 1728 * @memberof Modernizr 1729 * @name Modernizr.testStyles 1730 * @optionName Modernizr.testStyles() 1731 * @optionProp testStyles 1732 * @access public 1733 * @function testStyles 1734 * @param {string} rule - String representing a css rule 1735 * @param {function} callback - A function that is used to test the injected element 1736 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 1737 * @param {string[]}
1737 [testnames] - An array of strings that are used as ids for the additional nodes 1738 * @returns {boolean} 1739 * @example 1740 * 1741 * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page 1742 * along with (possibly multiple) DOM elements. This lets you check for features 1743 * 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). 1744 * 1745 * ```js 1746 * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) { 1747 * // elem is the first DOM node in the page (by default #modernizr) 1748 * // rule is the first argument you supplied - the CSS rule in string form 1749 * 1750 * addTest('widthworks', elem.style.width === '9px') 1751 * }); 1752 * ``` 1753 * 1754 * If your test requires multiple nodes, you can include a third argument 1755 * indicating how many additional div elements to include on the page. The 1756 * additional nodes are injected as children of the `elem` that is returned as 1757 * the first argument to the callback. 1758 * 1759 * ```js 1760 * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) { 1761 * document.getElementById('modernizr').style.width === '1px'; // true 1762 * document.getElementById('modernizr2').style.width === '2px'; // true 1763 * elem.firstChild === document.getElementById('modernizr2'); // true 1764 * }, 1); 1765 * ``` 1766 * 1767 * By default, all of the additional elements have an ID of `modernizr[n]`, where 1768 * `n` is its index (e.g. the first additional, second overall is `#modernizr2`, 1769 * the second additional is `#modernizr3`, etc.). 1770 * If you want to have more meaningful IDs for your function, you can provide 1771 * them as the fourth argument, as an array of strings 1772 * 1773 * ```js 1774 * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) { 1775 * elem.firstChild === document.getElementById('foo'); // true 1776 * elem.lastChild === document.getElementById('bar'); // true 1777 * }, 2, ['foo', 'bar']); 1778 * ``` 1779 * 1780 */ 1781 1782 var testStyles = ModernizrProto.testStyles = injectElementWithStyles; 1783 1784/*! 1785{ 1786 "name": "details Element", 1787 "caniuse": "details", 1788 "property": "details", 1789 "tags": ["elem"], 1790 "builderAliases": ["elem_details"], 1791 "authors": ["@mathias"], 1792 "notes": [{ 1793 "name": "Mathias' Original", 1794 "href": "https://mathiasbynens.be/notes/html5-details-jquery#comment-35" 1795 }] 1796} 1797!*/ 1798 1799 Modernizr.addTest('details', function() { 1800 var el = createElement('details'); 1801 var diff; 1802 1803 // return early if possible; thanks @aFarkas! 1804 if (!('open' in el)) { 1805 return false; 1806 } 1807 1808 testStyles('#modernizr details{display:block}', function(node) { 1809 node.appendChild(el); 1810 el.innerHTML = '<summary>a</summary>b'; 1811 diff = el.offsetHeight; 1812 el.open = true; 1813 diff = diff != el.offsetHeight; 1814 }); 1815 1816 1817 return diff; 1818 }); 1819 1820 1821 // Run each test 1822 testRunner(); 1823 1824 // Remove the "no-js" class if it exists 1825 setClasses(classes); 1826 1827 delete ModernizrProto.addTest; 1828 delete ModernizrProto.addAsyncTest; 1829 1830 // Run the things that are supposed to run after the tests 1831 for (var i = 0; i < Modernizr._q.length; i++) { 1832 Modernizr._q[i](); 1833 } 1834 1835 // Leak Modernizr namespace 1836 window.Modernizr = Modernizr; 1837 1838 1839; 1840 1841})(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.