const Modernizr = (window["Modernizr"] = (function( window, document, undefined ) { let tests = []; /** * * ModernizrProto is the constructor for Modernizr */ const ModernizrProto = { // The current version, dummy _version: "3.6.0", // Any settings that don't work as separate modules // can go in here as configuration. _config: { classPrefix: "", enableClasses: true, enableJSClass: true, usePrefixes: true }, // Queue of tests _q: [], // Stub these for people who are listening on: function(test, cb) { // I don't really think people should do this, but we can // safe guard it a bit. // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. // This is in case people listen to synchronous tests. I would leave it out, // but the code to *disallow* sync tests in the real version of this // function is actually larger than this. let self = this; setTimeout(function() { cb(self[test]); }, 0); }, addTest: function(name, fn, options) { tests.push({ name: name, fn: fn, options: options }); }, addAsyncTest: function(fn) { tests.push({ name: null, fn: fn }); } }; // Fake some of Object.create so we can force non test results to be non "own" properties. let Modernizr: any = function() {}; Modernizr.prototype = ModernizrProto; // Leak modernizr globally when you `require` it rather than force it here. // Overwrite name so constructor name is nicer :D Modernizr = new Modernizr(); const classes = []; /** * is returns a boolean if the typeof an obj is exactly type. */ const is = function(obj, type) { return typeof obj === type; }; /** * Run through all tests and detect their support in the current UA. */ const testRunner = function() { let featureNames; let feature; let aliasIdx; let result; let nameIdx; let featureName; let featureNameSplit; for (let featureIdx in tests) { if (tests.hasOwnProperty(featureIdx)) { featureNames = []; feature = tests[featureIdx]; // run the test, throw the return value into the Modernizr, // then based on that boolean, define an appropriate className // and push it into an array of classes we'll join later. // // If there is no name, it's an 'async' test that is run, // but not directly added to the object. That should // be done with a post-run addTest call. if (feature.name) { featureNames.push(feature.name.toLowerCase()); if ( feature.options && feature.options.aliases && feature.options.aliases.length ) { // Add all the aliases into the names list for ( aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++ ) { featureNames.push( feature.options.aliases[aliasIdx].toLowerCase() ); } } } // Run the test, or use the raw value if it's not a function result = is(feature.fn, "function") ? feature.fn() : feature.fn; // Set each of the names on the Modernizr object for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { featureName = featureNames[nameIdx]; // Support dot properties as sub tests. We don't do checking to make sure // that the implied parent tests have been added. You must call them in // order (either in the test, or make the parent test a dependency). // // Cap it to TWO to make the logic simple and because who needs that kind of subtesting // hashtag famous last words featureNameSplit = featureName.split("."); if (featureNameSplit.length === 1) { Modernizr[featureNameSplit[0]] = result; } else { // cast to a Boolean, if not one already if ( Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean) ) { Modernizr[featureNameSplit[0]] = new Boolean( Modernizr[featureNameSplit[0]] ); } Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; } classes.push((result ? "" : "no-") + featureNameSplit.join("-")); } } } }; /** * docElement is a convenience wrapper to grab the root element of the document */ let docElement = document.documentElement; /** * A convenience helper to check if the document we are running in is an SVG document */ let isSVG = docElement.nodeName.toLowerCase() === "svg"; /** * createElement is a convenience wrapper around document.createElement. Since we * use createElement all over the place, this allows for (slightly) smaller code * as well as abstracting away issues with creating elements in contexts other than * HTML documents (e.g. SVG documents). */ const createElement = function(...args) { if (typeof document.createElement !== "function") { // This is the case in IE7, where the type of createElement is "object". // For this reason, we cannot call apply() as Object is not a Function. return document.createElement(args[0]); } else if (isSVG) { return document.createElementNS.call( document, "http://www.w3.org/2000/svg", args[0] ); } else { return document.createElement.apply(document, args); } }; /** * since we have a fairly large number of input tests that don't mutate the input * we create a single element that can be shared with all of those tests for a * minor perf boost */ let inputElem = createElement("input"); /*! { "name": "Form input types", "property": "inputtypes", "caniuse": "forms", "tags": ["forms"], "authors": ["Mike Taylor"], "polyfills": [ "jquerytools", "webshims", "h5f", "webforms2", "nwxforms", "fdslider", "html5slider", "galleryhtml5forms", "jscolor", "html5formshim", "selectedoptionsjs", "formvalidationjs" ] } !*/ /* DOC Detects support for HTML5 form input types and exposes Boolean subproperties with the results: ```javascript Modernizr.inputtypes.color Modernizr.inputtypes.date Modernizr.inputtypes.datetime Modernizr.inputtypes['datetime-local'] Modernizr.inputtypes.email Modernizr.inputtypes.month Modernizr.inputtypes.number Modernizr.inputtypes.range Modernizr.inputtypes.search Modernizr.inputtypes.tel Modernizr.inputtypes.time Modernizr.inputtypes.url Modernizr.inputtypes.week ``` */ // Run through HTML5's new input types to see if the UA understands any. // This is put behind the tests runloop because it doesn't return a // true/false like all the other tests; instead, it returns an object // containing each input type with its corresponding true/false value // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ let inputtypes = "search tel url email datetime date month week time datetime-local number range color".split( " " ); let inputs = {}; Modernizr.inputtypes = (function(props) { let len = props.length; let smile = "1)"; let inputElemType; let defaultView; let bool; for (let i = 0; i < len; i++) { inputElem.setAttribute("type", (inputElemType = props[i])); bool = inputElem.type !== "text" && "style" in inputElem; // We first check to see if the type we give it sticks.. // If the type does, we feed it a textual value, which shouldn't be valid. // If the value doesn't stick, we know there's input sanitization which infers a custom UI if (bool) { inputElem.value = smile; inputElem.style.cssText = "position:absolute;visibility:hidden;"; if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { docElement.appendChild(inputElem); defaultView = document.defaultView; // Safari 2-4 allows the smiley as a value, despite making a slider bool = defaultView.getComputedStyle && defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== "textfield" && // Mobile android web browser has false positive, so must // check the height to see if the widget is actually there. inputElem.offsetHeight !== 0; docElement.removeChild(inputElem); } else if (/^(search|tel)$/.test(inputElemType)) { // Spec doesn't define any special parsing or detectable UI // behaviors so we pass these through as true // Interestingly, opera fails the earlier test, so it doesn't // even make it here. } else if (/^(url|email)$/.test(inputElemType)) { // Real url and email support comes with prebaked validation. bool = inputElem.checkValidity && inputElem.checkValidity() === false; } else { // If the upgraded input compontent rejects the :) text, we got a winner bool = inputElem.value != smile; } } inputs[props[i]] = !!bool; } return inputs; })(inputtypes); // Run each test testRunner(); delete ModernizrProto.addTest; delete ModernizrProto.addAsyncTest; // Run the things that are supposed to run after the tests for (let i = 0; i < Modernizr._q.length; i++) { Modernizr._q[i](); } return Modernizr; })(window, document)); export { Modernizr };