Created
March 8, 2020 13:27
-
-
Save jelmerdemaat/3914d165b22ea9f24f43b6243b6924df to your computer and use it in GitHub Desktop.
Customizr build Modernizr v3.9.1 - test for adding classes when testing input types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* modernizr v3.9.1 | |
* Build https://modernizr.com/download?-inputtypes-setclasses-dontmin | |
* | |
* Copyright (c) | |
* Faruk Ates | |
* Paul Irish | |
* Alex Sexton | |
* Ryan Seddon | |
* Patrick Kettner | |
* Stu Cox | |
* Richard Herrera | |
* Veeck | |
* MIT License | |
*/ | |
/* | |
* Modernizr tests which native CSS3 and HTML5 features are available in the | |
* current UA and makes the results available to you in two ways: as properties on | |
* a global `Modernizr` object, and as classes on the `<html>` element. This | |
* information allows you to progressively enhance your pages with a granular level | |
* of control over the experience. | |
*/ | |
;(function(window, document, undefined){ | |
var tests = []; | |
/** | |
* ModernizrProto is the constructor for Modernizr | |
* | |
* @class | |
* @access public | |
*/ | |
var ModernizrProto = { | |
// The current version, dummy | |
_version: '3.9.1', | |
// 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. | |
var 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. | |
var Modernizr = 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(); | |
var classes = []; | |
/** | |
* is returns a boolean if the typeof an obj is exactly type. | |
* | |
* @access private | |
* @function is | |
* @param {*} obj - A thing we want to check the type of | |
* @param {string} type - A string to compare the typeof against | |
* @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise | |
*/ | |
function is(obj, type) { | |
return typeof obj === type; | |
} | |
; | |
/** | |
* Run through all tests and detect their support in the current UA. | |
* | |
* @access private | |
* @returns {void} | |
*/ | |
function testRunner() { | |
var featureNames; | |
var feature; | |
var aliasIdx; | |
var result; | |
var nameIdx; | |
var featureName; | |
var featureNameSplit; | |
for (var 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 or if it doesnt exist yet (like inputtypes) | |
if (!Modernizr[featureNameSplit[0]] || 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 | |
* | |
* @access private | |
* @returns {HTMLElement|SVGElement} The root element of the document | |
*/ | |
var docElement = document.documentElement; | |
/** | |
* A convenience helper to check if the document we are running in is an SVG document | |
* | |
* @access private | |
* @returns {boolean} | |
*/ | |
var isSVG = docElement.nodeName.toLowerCase() === 'svg'; | |
/** | |
* setClasses takes an array of class names and adds them to the root element | |
* | |
* @access private | |
* @function setClasses | |
* @param {string[]} classes - Array of class names | |
*/ | |
// Pass in an and array of class names, e.g.: | |
// ['no-webp', 'borderradius', ...] | |
function setClasses(classes) { | |
var className = docElement.className; | |
var classPrefix = Modernizr._config.classPrefix || ''; | |
if (isSVG) { | |
className = className.baseVal; | |
} | |
// Change `no-js` to `js` (independently of the `enableClasses` option) | |
// Handle classPrefix on this too | |
if (Modernizr._config.enableJSClass) { | |
var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); | |
className = className.replace(reJS, '$1' + classPrefix + 'js$2'); | |
} | |
if (Modernizr._config.enableClasses) { | |
// Add the new classes | |
if (classes.length > 0) { | |
className += ' ' + classPrefix + classes.join(' ' + classPrefix); | |
} | |
if (isSVG) { | |
docElement.className.baseVal = className; | |
} else { | |
docElement.className = className; | |
} | |
} | |
} | |
; | |
/** | |
* 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). | |
* | |
* @access private | |
* @function createElement | |
* @returns {HTMLElement|SVGElement} An HTML or SVG element | |
*/ | |
function createElement() { | |
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(arguments[0]); | |
} else if (isSVG) { | |
return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); | |
} else { | |
return document.createElement.apply(document, arguments); | |
} | |
} | |
; | |
/** | |
* 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 | |
* | |
* @access private | |
* @returns {HTMLInputElement} | |
*/ | |
var 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/ | |
(function() { | |
var props = ['search', 'tel', 'url', 'email', 'datetime', 'date', 'month', 'week','time', 'datetime-local', 'number', 'range', 'color']; | |
var smile = '1)'; | |
var inputElemType; | |
var defaultView; | |
var bool; | |
for (var i = 0; i < props.length; 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 component rejects the :) text, we got a winner | |
bool = inputElem.value !== smile; | |
} | |
} | |
Modernizr.addTest('inputtypes.' + inputElemType, !!bool); | |
} | |
})(); | |
// Run each test | |
testRunner(); | |
delete ModernizrProto.addTest; | |
delete ModernizrProto.addAsyncTest; | |
// Run the things that are supposed to run after the tests | |
for (var i = 0; i < Modernizr._q.length; i++) { | |
Modernizr._q[i](); | |
} | |
// Leak Modernizr namespace | |
window.Modernizr = Modernizr; | |
; | |
})(window, document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment