425 lines
12 KiB
JavaScript
425 lines
12 KiB
JavaScript
/*!
|
|
* modernizr v3.13.0
|
|
* Build https://modernizr.com/download?-fetch-inputtypes-time-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(scriptGlobalObject, window, document, undefined){
|
|
|
|
var tests = [];
|
|
|
|
|
|
/**
|
|
* ModernizrProto is the constructor for Modernizr
|
|
*
|
|
* @class
|
|
* @access public
|
|
*/
|
|
var ModernizrProto = {
|
|
_version: '3.13.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.
|
|
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);
|
|
}
|
|
})();
|
|
|
|
/*!
|
|
{
|
|
"name": "time Element",
|
|
"property": "time",
|
|
"tags": ["elem"],
|
|
"builderAliases": ["elem_time"],
|
|
"notes": [{
|
|
"name": "WHATWG Spec",
|
|
"href": "https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-time-element"
|
|
}]
|
|
}
|
|
!*/
|
|
|
|
Modernizr.addTest('time', 'valueAsDate' in createElement('time'));
|
|
|
|
/*!
|
|
{
|
|
"name": "Fetch API",
|
|
"property": "fetch",
|
|
"tags": ["network"],
|
|
"caniuse": "fetch",
|
|
"notes": [{
|
|
"name": "WHATWG Spec",
|
|
"href": "https://fetch.spec.whatwg.org/"
|
|
}],
|
|
"polyfills": ["fetch"]
|
|
}
|
|
!*/
|
|
/* DOC
|
|
Detects support for the fetch API, a modern replacement for XMLHttpRequest.
|
|
*/
|
|
|
|
Modernizr.addTest('fetch', 'fetch' in window);
|
|
|
|
|
|
// Run each test
|
|
testRunner();
|
|
|
|
// Remove the "no-js" class if it exists
|
|
setClasses(classes);
|
|
|
|
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
|
|
scriptGlobalObject.Modernizr = Modernizr;
|
|
|
|
|
|
;
|
|
|
|
})(window, window, document);
|