Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> # Conflicts: # src/vector/modernizr.js
1997 lines
60 KiB
JavaScript
1997 lines
60 KiB
JavaScript
/*!
|
||
* modernizr v3.13.0
|
||
* Build https://modernizr.com/download?-cors-cryptography-cssanimations-cssfilters-displaytable-es5date-es5function-es5object-es5undefined-es6array-es6collections-es6string-fetch-flexbox-json-localstorage-objectfit-promises-resizeobserver-sandbox-svg-svgasimg-svgfilters-urlparser-urlsearchparams-webaudio-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': false,
|
||
'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('-'));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
;
|
||
|
||
/**
|
||
* If the browsers follow the spec, then they would expose vendor-specific styles as:
|
||
* elem.style.WebkitBorderRadius
|
||
* instead of something like the following (which is technically incorrect):
|
||
* elem.style.webkitBorderRadius
|
||
*
|
||
* WebKit ghosts their properties in lowercase but Opera & Moz do not.
|
||
* Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
|
||
* erik.eae.net/archives/2008/03/10/21.48.10/
|
||
*
|
||
* More here: github.com/Modernizr/Modernizr/issues/issue/21
|
||
*
|
||
* @access private
|
||
* @returns {string} The string representing the vendor-specific style properties
|
||
*/
|
||
var omPrefixes = 'Moz O ms Webkit';
|
||
|
||
|
||
var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
|
||
ModernizrProto._cssomPrefixes = cssomPrefixes;
|
||
|
||
|
||
/**
|
||
* contains checks to see if a string contains another string
|
||
*
|
||
* @access private
|
||
* @function contains
|
||
* @param {string} str - The string we want to check for substrings
|
||
* @param {string} substr - The substring we want to search the first string for
|
||
* @returns {boolean} true if and only if the first string 'str' contains the second string 'substr'
|
||
*/
|
||
function contains(str, substr) {
|
||
return !!~('' + str).indexOf(substr);
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* 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';
|
||
|
||
|
||
|
||
/**
|
||
* 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);
|
||
}
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* Create our "modernizr" element that we do most feature tests on.
|
||
*
|
||
* @access private
|
||
*/
|
||
var modElem = {
|
||
elem: createElement('modernizr')
|
||
};
|
||
|
||
// Clean up this element
|
||
Modernizr._q.push(function() {
|
||
delete modElem.elem;
|
||
});
|
||
|
||
|
||
|
||
var mStyle = {
|
||
style: modElem.elem.style
|
||
};
|
||
|
||
// kill ref for gc, must happen before mod.elem is removed, so we unshift on to
|
||
// the front of the queue.
|
||
Modernizr._q.unshift(function() {
|
||
delete mStyle.style;
|
||
});
|
||
|
||
|
||
|
||
/**
|
||
* getBody returns the body of a document, or an element that can stand in for
|
||
* the body if a real body does not exist
|
||
*
|
||
* @access private
|
||
* @function getBody
|
||
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
|
||
* artificially created element that stands in for the body
|
||
*/
|
||
function getBody() {
|
||
// After page load injecting a fake body doesn't work so check if body exists
|
||
var body = document.body;
|
||
|
||
if (!body) {
|
||
// Can't use the real body create a fake one.
|
||
body = createElement(isSVG ? 'svg' : 'body');
|
||
body.fake = true;
|
||
}
|
||
|
||
return body;
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* injectElementWithStyles injects an element with style element and some CSS rules
|
||
*
|
||
* @access private
|
||
* @function injectElementWithStyles
|
||
* @param {string} rule - String representing a css rule
|
||
* @param {Function} callback - A function that is used to test the injected element
|
||
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
|
||
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
|
||
* @returns {boolean} the result of the specified callback test
|
||
*/
|
||
function injectElementWithStyles(rule, callback, nodes, testnames) {
|
||
var mod = 'modernizr';
|
||
var style;
|
||
var ret;
|
||
var node;
|
||
var docOverflow;
|
||
var div = createElement('div');
|
||
var body = getBody();
|
||
|
||
if (parseInt(nodes, 10)) {
|
||
// In order not to give false positives we create a node for each test
|
||
// This also allows the method to scale for unspecified uses
|
||
while (nodes--) {
|
||
node = createElement('div');
|
||
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
|
||
div.appendChild(node);
|
||
}
|
||
}
|
||
|
||
style = createElement('style');
|
||
style.type = 'text/css';
|
||
style.id = 's' + mod;
|
||
|
||
// 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.
|
||
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
|
||
(!body.fake ? div : body).appendChild(style);
|
||
body.appendChild(div);
|
||
|
||
if (style.styleSheet) {
|
||
style.styleSheet.cssText = rule;
|
||
} else {
|
||
style.appendChild(document.createTextNode(rule));
|
||
}
|
||
div.id = mod;
|
||
|
||
if (body.fake) {
|
||
//avoid crashing IE8, if background image is used
|
||
body.style.background = '';
|
||
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
|
||
body.style.overflow = 'hidden';
|
||
docOverflow = docElement.style.overflow;
|
||
docElement.style.overflow = 'hidden';
|
||
docElement.appendChild(body);
|
||
}
|
||
|
||
ret = callback(div, rule);
|
||
// If this is done after page load we don't want to remove the body so check if body exists
|
||
if (body.fake && body.parentNode) {
|
||
body.parentNode.removeChild(body);
|
||
docElement.style.overflow = docOverflow;
|
||
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
|
||
// eslint-disable-next-line
|
||
docElement.offsetHeight;
|
||
} else {
|
||
div.parentNode.removeChild(div);
|
||
}
|
||
|
||
return !!ret;
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* domToCSS takes a camelCase string and converts it to hyphen-case
|
||
* e.g. boxSizing -> box-sizing
|
||
*
|
||
* @access private
|
||
* @function domToCSS
|
||
* @param {string} name - String name of camelCase prop we want to convert
|
||
* @returns {string} The hyphen-case version of the supplied name
|
||
*/
|
||
function domToCSS(name) {
|
||
return name.replace(/([A-Z])/g, function(str, m1) {
|
||
return '-' + m1.toLowerCase();
|
||
}).replace(/^ms-/, '-ms-');
|
||
}
|
||
|
||
;
|
||
|
||
|
||
/**
|
||
* wrapper around getComputedStyle, to fix issues with Firefox returning null when
|
||
* called inside of a hidden iframe
|
||
*
|
||
* @access private
|
||
* @function computedStyle
|
||
* @param {HTMLElement|SVGElement} elem - The element we want to find the computed styles of
|
||
* @param {string|null} [pseudo] - An optional pseudo element selector (e.g. :before), of null if none
|
||
* @param {string} prop - A CSS property
|
||
* @returns {CSSStyleDeclaration} the value of the specified CSS property
|
||
*/
|
||
function computedStyle(elem, pseudo, prop) {
|
||
var result;
|
||
|
||
if ('getComputedStyle' in window) {
|
||
result = getComputedStyle.call(window, elem, pseudo);
|
||
var console = window.console;
|
||
|
||
if (result !== null) {
|
||
if (prop) {
|
||
result = result.getPropertyValue(prop);
|
||
}
|
||
} else {
|
||
if (console) {
|
||
var method = console.error ? 'error' : 'log';
|
||
console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate');
|
||
}
|
||
}
|
||
} else {
|
||
result = !pseudo && elem.currentStyle && elem.currentStyle[prop];
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* nativeTestProps allows for us to use native feature detection functionality if available.
|
||
* some prefixed form, or false, in the case of an unsupported rule
|
||
*
|
||
* @access private
|
||
* @function nativeTestProps
|
||
* @param {Array} props - An array of property names
|
||
* @param {string} value - A string representing the value we want to check via @supports
|
||
* @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
|
||
*/
|
||
// Accepts a list of property names and a single value
|
||
// Returns `undefined` if native detection not available
|
||
function nativeTestProps(props, value) {
|
||
var i = props.length;
|
||
// Start with the JS API: https://www.w3.org/TR/css3-conditional/#the-css-interface
|
||
if ('CSS' in window && 'supports' in window.CSS) {
|
||
// Try every prefixed variant of the property
|
||
while (i--) {
|
||
if (window.CSS.supports(domToCSS(props[i]), value)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
// Otherwise fall back to at-rule (for Opera 12.x)
|
||
else if ('CSSSupportsRule' in window) {
|
||
// Build a condition string for every prefixed variant
|
||
var conditionText = [];
|
||
while (i--) {
|
||
conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
|
||
}
|
||
conditionText = conditionText.join(' or ');
|
||
return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
|
||
return computedStyle(node, null, 'position') === 'absolute';
|
||
});
|
||
}
|
||
return undefined;
|
||
}
|
||
;
|
||
|
||
/**
|
||
* cssToDOM takes a hyphen-case string and converts it to camelCase
|
||
* e.g. box-sizing -> boxSizing
|
||
*
|
||
* @access private
|
||
* @function cssToDOM
|
||
* @param {string} name - String name of hyphen-case prop we want to convert
|
||
* @returns {string} The camelCase version of the supplied name
|
||
*/
|
||
function cssToDOM(name) {
|
||
return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
|
||
return m1 + m2.toUpperCase();
|
||
}).replace(/^-/, '');
|
||
}
|
||
|
||
;
|
||
|
||
// testProps is a generic CSS / DOM property test.
|
||
|
||
// In testing support for a given CSS property, it's legit to test:
|
||
// `elem.style[styleName] !== undefined`
|
||
// If the property is supported it will return an empty string,
|
||
// if unsupported it will return undefined.
|
||
|
||
// We'll take advantage of this quick test and skip setting a style
|
||
// on our modernizr element, but instead just testing undefined vs
|
||
// empty string.
|
||
|
||
// Property names can be provided in either camelCase or hyphen-case.
|
||
|
||
function testProps(props, prefixed, value, skipValueTest) {
|
||
skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
|
||
|
||
// Try native detect first
|
||
if (!is(value, 'undefined')) {
|
||
var result = nativeTestProps(props, value);
|
||
if (!is(result, 'undefined')) {
|
||
return result;
|
||
}
|
||
}
|
||
|
||
// Otherwise do it properly
|
||
var afterInit, i, propsLength, prop, before;
|
||
|
||
// If we don't have a style element, that means we're running async or after
|
||
// the core tests, so we'll need to create our own elements to use.
|
||
|
||
// Inside of an SVG element, in certain browsers, the `style` element is only
|
||
// defined for valid tags. Therefore, if `modernizr` does not have one, we
|
||
// fall back to a less used element and hope for the best.
|
||
// For strict XHTML browsers the hardly used samp element is used.
|
||
var elems = ['modernizr', 'tspan', 'samp'];
|
||
while (!mStyle.style && elems.length) {
|
||
afterInit = true;
|
||
mStyle.modElem = createElement(elems.shift());
|
||
mStyle.style = mStyle.modElem.style;
|
||
}
|
||
|
||
// Delete the objects if we created them.
|
||
function cleanElems() {
|
||
if (afterInit) {
|
||
delete mStyle.style;
|
||
delete mStyle.modElem;
|
||
}
|
||
}
|
||
|
||
propsLength = props.length;
|
||
for (i = 0; i < propsLength; i++) {
|
||
prop = props[i];
|
||
before = mStyle.style[prop];
|
||
|
||
if (contains(prop, '-')) {
|
||
prop = cssToDOM(prop);
|
||
}
|
||
|
||
if (mStyle.style[prop] !== undefined) {
|
||
|
||
// If value to test has been passed in, do a set-and-check test.
|
||
// 0 (integer) is a valid property value, so check that `value` isn't
|
||
// undefined, rather than just checking it's truthy.
|
||
if (!skipValueTest && !is(value, 'undefined')) {
|
||
|
||
// Needs a try catch block because of old IE. This is slow, but will
|
||
// be avoided in most cases because `skipValueTest` will be used.
|
||
try {
|
||
mStyle.style[prop] = value;
|
||
} catch (e) {}
|
||
|
||
// If the property value has changed, we assume the value used is
|
||
// supported. If `value` is empty string, it'll fail here (because
|
||
// it hasn't changed), which matches how browsers have implemented
|
||
// CSS.supports()
|
||
if (mStyle.style[prop] !== before) {
|
||
cleanElems();
|
||
return prefixed === 'pfx' ? prop : true;
|
||
}
|
||
}
|
||
// Otherwise just return true, or the property name if this is a
|
||
// `prefixed()` call
|
||
else {
|
||
cleanElems();
|
||
return prefixed === 'pfx' ? prop : true;
|
||
}
|
||
}
|
||
}
|
||
cleanElems();
|
||
return false;
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* List of JavaScript DOM values used for tests
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr._domPrefixes
|
||
* @optionName Modernizr._domPrefixes
|
||
* @optionProp domPrefixes
|
||
* @access public
|
||
* @example
|
||
*
|
||
* Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
|
||
* than hyphen-case properties, all properties are their Capitalized variant
|
||
*
|
||
* ```js
|
||
* Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
|
||
* ```
|
||
*/
|
||
var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
|
||
ModernizrProto._domPrefixes = domPrefixes;
|
||
|
||
|
||
/**
|
||
* fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
|
||
*
|
||
* @access private
|
||
* @function fnBind
|
||
* @param {Function} fn - a function you want to change `this` reference to
|
||
* @param {object} that - the `this` you want to call the function with
|
||
* @returns {Function} The wrapped version of the supplied function
|
||
*/
|
||
function fnBind(fn, that) {
|
||
return function() {
|
||
return fn.apply(that, arguments);
|
||
};
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* testDOMProps is a generic DOM property test; if a browser supports
|
||
* a certain property, it won't return undefined for it.
|
||
*
|
||
* @access private
|
||
* @function testDOMProps
|
||
* @param {Array<string>} props - An array of properties to test for
|
||
* @param {object} obj - An object or Element you want to use to test the parameters again
|
||
* @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
|
||
* @returns {boolean|*} returns `false` if the prop is unsupported, otherwise the value that is supported
|
||
*/
|
||
function testDOMProps(props, obj, elem) {
|
||
var item;
|
||
|
||
for (var i in props) {
|
||
if (props[i] in obj) {
|
||
|
||
// return the property name as a string
|
||
if (elem === false) {
|
||
return props[i];
|
||
}
|
||
|
||
item = obj[props[i]];
|
||
|
||
// let's bind a function
|
||
if (is(item, 'function')) {
|
||
// bind to obj unless overridden
|
||
return fnBind(item, elem || obj);
|
||
}
|
||
|
||
// return the unbound function or obj or value
|
||
return item;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
;
|
||
|
||
/**
|
||
* testPropsAll tests a list of DOM properties we want to check against.
|
||
* We specify literally ALL possible (known and/or likely) properties on
|
||
* the element including the non-vendor prefixed one, for forward-
|
||
* compatibility.
|
||
*
|
||
* @access private
|
||
* @function testPropsAll
|
||
* @param {string} prop - A string of the property to test for
|
||
* @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
|
||
* @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
|
||
* @param {string} [value] - A string of a css value
|
||
* @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
|
||
* @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
|
||
*/
|
||
function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
|
||
|
||
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
|
||
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
|
||
|
||
// did they call .prefixed('boxSizing') or are we just testing a prop?
|
||
if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
|
||
return testProps(props, prefixed, value, skipValueTest);
|
||
|
||
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
|
||
} else {
|
||
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
|
||
return testDOMProps(props, prefixed, elem);
|
||
}
|
||
}
|
||
|
||
// Modernizr.testAllProps() investigates whether a given style property,
|
||
// or any of its vendor-prefixed variants, is recognized
|
||
//
|
||
// Note that the property names must be provided in the camelCase variant.
|
||
// Modernizr.testAllProps('boxSizing')
|
||
ModernizrProto.testAllProps = testPropsAll;
|
||
|
||
|
||
|
||
/**
|
||
* testAllProps determines whether a given CSS property is supported in the browser
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.testAllProps
|
||
* @optionName Modernizr.testAllProps()
|
||
* @optionProp testAllProps
|
||
* @access public
|
||
* @function testAllProps
|
||
* @param {string} prop - String naming the property to test (either camelCase or hyphen-case)
|
||
* @param {string} [value] - String of the value to test
|
||
* @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
|
||
* @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
|
||
* @example
|
||
*
|
||
* testAllProps determines whether a given CSS property, in some prefixed form,
|
||
* is supported by the browser.
|
||
*
|
||
* ```js
|
||
* testAllProps('boxSizing') // true
|
||
* ```
|
||
*
|
||
* It can optionally be given a CSS value in string form to test if a property
|
||
* value is valid
|
||
*
|
||
* ```js
|
||
* testAllProps('display', 'block') // true
|
||
* testAllProps('display', 'penguin') // false
|
||
* ```
|
||
*
|
||
* A boolean can be passed as a third parameter to skip the value check when
|
||
* native detection (@supports) isn't available.
|
||
*
|
||
* ```js
|
||
* testAllProps('shapeOutside', 'content-box', true);
|
||
* ```
|
||
*/
|
||
function testAllProps(prop, value, skipValueTest) {
|
||
return testPropsAll(prop, undefined, undefined, value, skipValueTest);
|
||
}
|
||
|
||
ModernizrProto.testAllProps = testAllProps;
|
||
|
||
|
||
/*!
|
||
{
|
||
"name": "CSS Animations",
|
||
"property": "cssanimations",
|
||
"caniuse": "css-animation",
|
||
"polyfills": ["transformie", "csssandpaper"],
|
||
"tags": ["css"],
|
||
"warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
|
||
"notes": [{
|
||
"name": "Article: 'Dispelling the Android CSS animation myths'",
|
||
"href": "https://web.archive.org/web/20180602074607/https://daneden.me/2011/12/14/putting-up-with-androids-bullshit/"
|
||
}]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects whether or not elements can be animated using CSS
|
||
*/
|
||
|
||
Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
|
||
|
||
|
||
/**
|
||
* testStyles injects an element with style element and some CSS rules
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.testStyles
|
||
* @optionName Modernizr.testStyles()
|
||
* @optionProp testStyles
|
||
* @access public
|
||
* @function testStyles
|
||
* @param {string} rule - String representing a css rule
|
||
* @param {Function} callback - A function that is used to test the injected element
|
||
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
|
||
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
|
||
* @returns {boolean}
|
||
* @example
|
||
*
|
||
* `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
|
||
* along with (possibly multiple) DOM elements. This lets you check for features
|
||
* 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).
|
||
*
|
||
* ```js
|
||
* Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
|
||
* // elem is the first DOM node in the page (by default #modernizr)
|
||
* // rule is the first argument you supplied - the CSS rule in string form
|
||
*
|
||
* addTest('widthworks', elem.style.width === '9px')
|
||
* });
|
||
* ```
|
||
*
|
||
* If your test requires multiple nodes, you can include a third argument
|
||
* indicating how many additional div elements to include on the page. The
|
||
* additional nodes are injected as children of the `elem` that is returned as
|
||
* the first argument to the callback.
|
||
*
|
||
* ```js
|
||
* Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
|
||
* document.getElementById('modernizr').style.width === '1px'; // true
|
||
* document.getElementById('modernizr2').style.width === '2px'; // true
|
||
* elem.firstChild === document.getElementById('modernizr2'); // true
|
||
* }, 1);
|
||
* ```
|
||
*
|
||
* By default, all of the additional elements have an ID of `modernizr[n]`, where
|
||
* `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
|
||
* the second additional is `#modernizr3`, etc.).
|
||
* If you want to have more meaningful IDs for your function, you can provide
|
||
* them as the fourth argument, as an array of strings
|
||
*
|
||
* ```js
|
||
* Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
|
||
* elem.firstChild === document.getElementById('foo'); // true
|
||
* elem.lastChild === document.getElementById('bar'); // true
|
||
* }, 2, ['foo', 'bar']);
|
||
* ```
|
||
*/
|
||
var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
|
||
|
||
/*!
|
||
{
|
||
"name": "CSS Display table",
|
||
"property": "displaytable",
|
||
"caniuse": "css-table",
|
||
"authors": ["scottjehl"],
|
||
"tags": ["css"],
|
||
"builderAliases": ["css_displaytable"],
|
||
"notes": [{
|
||
"name": "Detects for all additional table display values",
|
||
"href": "https://pastebin.com/Gk9PeVaQ"
|
||
}]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
`display: table` and `table-cell` test. (both are tested under one name `table-cell` )
|
||
*/
|
||
|
||
// If a document is in rtl mode this test will fail so we force ltr mode on the injected
|
||
// element https://github.com/Modernizr/Modernizr/issues/716
|
||
testStyles('#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}', function(elem) {
|
||
var ret;
|
||
var child = elem.childNodes;
|
||
ret = child[0].offsetLeft < child[1].offsetLeft;
|
||
Modernizr.addTest('displaytable', ret, {aliases: ['display-table']});
|
||
}, 2);
|
||
|
||
|
||
/**
|
||
* List of property values to set for css tests. See ticket #21
|
||
* https://github.com/modernizr/modernizr/issues/21
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr._prefixes
|
||
* @optionName Modernizr._prefixes
|
||
* @optionProp prefixes
|
||
* @access public
|
||
* @example
|
||
*
|
||
* Modernizr._prefixes is the internal list of prefixes that we test against
|
||
* inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
|
||
* an array of hyphen-case vendor prefixes you can use within your code.
|
||
*
|
||
* Some common use cases include
|
||
*
|
||
* Generating all possible prefixed version of a CSS property
|
||
* ```js
|
||
* var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
|
||
*
|
||
* rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
|
||
* ```
|
||
*
|
||
* Generating all possible prefixed version of a CSS value
|
||
* ```js
|
||
* rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex';
|
||
*
|
||
* rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
|
||
* ```
|
||
*/
|
||
// we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
|
||
// values in feature detects to continue to work
|
||
var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
|
||
|
||
// expose these for the plugin API. Look in the source for how to join() them against your input
|
||
ModernizrProto._prefixes = prefixes;
|
||
|
||
|
||
/*!
|
||
{
|
||
"name": "CSS Supports",
|
||
"property": "supports",
|
||
"caniuse": "css-featurequeries",
|
||
"tags": ["css"],
|
||
"builderAliases": ["css_supports"],
|
||
"notes": [{
|
||
"name": "W3C Spec (The @supports rule)",
|
||
"href": "https://dev.w3.org/csswg/css3-conditional/#at-supports"
|
||
}, {
|
||
"name": "Related Github Issue",
|
||
"href": "https://github.com/Modernizr/Modernizr/issues/648"
|
||
}, {
|
||
"name": "W3C Spec (The CSSSupportsRule interface)",
|
||
"href": "https://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
var newSyntax = 'CSS' in window && 'supports' in window.CSS;
|
||
var oldSyntax = 'supportsCSS' in window;
|
||
Modernizr.addTest('supports', newSyntax || oldSyntax);
|
||
|
||
/*!
|
||
{
|
||
"name": "CSS Filters",
|
||
"property": "cssfilters",
|
||
"caniuse": "css-filters",
|
||
"polyfills": ["polyfilter"],
|
||
"tags": ["css"],
|
||
"builderAliases": ["css_filters"],
|
||
"notes": [{
|
||
"name": "MDN Docs",
|
||
"href": "https://developer.mozilla.org/en-US/docs/Web/CSS/filter"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
Modernizr.addTest('cssfilters', function() {
|
||
if (Modernizr.supports) {
|
||
return testAllProps('filter', 'blur(2px)');
|
||
} else {
|
||
var el = createElement('a');
|
||
el.style.cssText = prefixes.join('filter:blur(2px); ');
|
||
// https://github.com/Modernizr/Modernizr/issues/615
|
||
// documentMode is needed for false positives in oldIE, please see issue above
|
||
return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
|
||
}
|
||
});
|
||
|
||
|
||
/*!
|
||
{
|
||
"name": "Flexbox",
|
||
"property": "flexbox",
|
||
"caniuse": "flexbox",
|
||
"tags": ["css"],
|
||
"notes": [{
|
||
"name": "The _new_ flexbox",
|
||
"href": "https://www.w3.org/TR/css-flexbox-1/"
|
||
}],
|
||
"warnings": [
|
||
"A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
|
||
]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
|
||
*/
|
||
|
||
Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
|
||
|
||
|
||
/**
|
||
* atRule returns a given CSS property at-rule (eg @keyframes), possibly in
|
||
* some prefixed form, or false, in the case of an unsupported rule
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.atRule
|
||
* @optionName Modernizr.atRule()
|
||
* @optionProp atRule
|
||
* @access public
|
||
* @function atRule
|
||
* @param {string} prop - String name of the @-rule to test for
|
||
* @returns {string|boolean} The string representing the (possibly prefixed)
|
||
* valid version of the @-rule, or `false` when it is unsupported.
|
||
* @example
|
||
* ```js
|
||
* var keyframes = Modernizr.atRule('@keyframes');
|
||
*
|
||
* if (keyframes) {
|
||
* // keyframes are supported
|
||
* // could be `@-webkit-keyframes` or `@keyframes`
|
||
* } else {
|
||
* // keyframes === `false`
|
||
* }
|
||
* ```
|
||
*/
|
||
var atRule = function(prop) {
|
||
var length = prefixes.length;
|
||
var cssrule = window.CSSRule;
|
||
var rule;
|
||
|
||
if (typeof cssrule === 'undefined') {
|
||
return undefined;
|
||
}
|
||
|
||
if (!prop) {
|
||
return false;
|
||
}
|
||
|
||
// remove literal @ from beginning of provided property
|
||
prop = prop.replace(/^@/, '');
|
||
|
||
// CSSRules use underscores instead of dashes
|
||
rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
|
||
|
||
if (rule in cssrule) {
|
||
return '@' + prop;
|
||
}
|
||
|
||
for (var i = 0; i < length; i++) {
|
||
// prefixes gives us something like -o-, and we want O_
|
||
var prefix = prefixes[i];
|
||
var thisRule = prefix.toUpperCase() + '_' + rule;
|
||
|
||
if (thisRule in cssrule) {
|
||
return '@-' + prefix.toLowerCase() + '-' + prop;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
ModernizrProto.atRule = atRule;
|
||
|
||
|
||
|
||
/**
|
||
* prefixed returns the prefixed or nonprefixed property name variant of your input
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.prefixed
|
||
* @optionName Modernizr.prefixed()
|
||
* @optionProp prefixed
|
||
* @access public
|
||
* @function prefixed
|
||
* @param {string} prop - String name of the property to test for
|
||
* @param {object} [obj] - An object to test for the prefixed properties on
|
||
* @param {HTMLElement} [elem] - An element used to test specific properties against
|
||
* @returns {string|boolean} The string representing the (possibly prefixed) valid
|
||
* version of the property, or `false` when it is unsupported.
|
||
* @example
|
||
*
|
||
* Modernizr.prefixed takes a string css value in the DOM style camelCase (as
|
||
* opposed to the css style hyphen-case) form and returns the (possibly prefixed)
|
||
* version of that property that the browser actually supports.
|
||
*
|
||
* For example, in older Firefox...
|
||
* ```js
|
||
* prefixed('boxSizing')
|
||
* ```
|
||
* returns 'MozBoxSizing'
|
||
*
|
||
* In newer Firefox, as well as any other browser that support the unprefixed
|
||
* version would simply return `boxSizing`. Any browser that does not support
|
||
* the property at all, it will return `false`.
|
||
*
|
||
* By default, prefixed is checked against a DOM element. If you want to check
|
||
* for a property on another object, just pass it as a second argument
|
||
*
|
||
* ```js
|
||
* var rAF = prefixed('requestAnimationFrame', window);
|
||
*
|
||
* raf(function() {
|
||
* renderFunction();
|
||
* })
|
||
* ```
|
||
*
|
||
* Note that this will return _the actual function_ - not the name of the function.
|
||
* If you need the actual name of the property, pass in `false` as a third argument
|
||
*
|
||
* ```js
|
||
* var rAFProp = prefixed('requestAnimationFrame', window, false);
|
||
*
|
||
* rafProp === 'WebkitRequestAnimationFrame' // in older webkit
|
||
* ```
|
||
*
|
||
* One common use case for prefixed is if you're trying to determine which transition
|
||
* end event to bind to, you might do something like...
|
||
* ```js
|
||
* var transEndEventNames = {
|
||
* 'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
|
||
* 'MozTransition' : 'transitionend', * only for FF < 15
|
||
* 'transition' : 'transitionend' * IE10, Opera, Chrome, FF 15+, Saf 7+
|
||
* };
|
||
*
|
||
* var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
|
||
* ```
|
||
*
|
||
* If you want a similar lookup, but in hyphen-case, you can use [prefixedCSS](#modernizr-prefixedcss).
|
||
*/
|
||
var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
|
||
if (prop.indexOf('@') === 0) {
|
||
return atRule(prop);
|
||
}
|
||
|
||
if (prop.indexOf('-') !== -1) {
|
||
// Convert hyphen-case to camelCase
|
||
prop = cssToDOM(prop);
|
||
}
|
||
if (!obj) {
|
||
return testPropsAll(prop, 'pfx');
|
||
} else {
|
||
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
|
||
return testPropsAll(prop, obj, elem);
|
||
}
|
||
};
|
||
|
||
|
||
/*!
|
||
{
|
||
"name": "CSS Object Fit",
|
||
"caniuse": "object-fit",
|
||
"property": "objectfit",
|
||
"tags": ["css"],
|
||
"builderAliases": ["css_objectfit"],
|
||
"notes": [{
|
||
"name": "Opera Article on Object Fit",
|
||
"href": "https://dev.opera.com/articles/css3-object-fit-object-position/"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
Modernizr.addTest('objectfit', !!prefixed('objectFit'), {aliases: ['object-fit']});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES5 Date",
|
||
"property": "es5date",
|
||
"notes": [{
|
||
"name": "ECMAScript 5.1 Language Specification",
|
||
"href": "https://www.ecma-international.org/ecma-262/5.1/"
|
||
}],
|
||
"polyfills": ["es5shim"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"tags": ["es5"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 5 Date per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('es5date', function() {
|
||
var isoDate = '2013-04-12T06:06:37.307Z',
|
||
canParseISODate = false;
|
||
try {
|
||
canParseISODate = !!Date.parse(isoDate);
|
||
} catch (e) {
|
||
// no ISO date parsing yet
|
||
}
|
||
return !!(Date.now &&
|
||
Date.prototype &&
|
||
Date.prototype.toISOString &&
|
||
Date.prototype.toJSON &&
|
||
canParseISODate);
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES5 Function",
|
||
"property": "es5function",
|
||
"notes": [{
|
||
"name": "ECMAScript 5.1 Language Specification",
|
||
"href": "https://www.ecma-international.org/ecma-262/5.1/"
|
||
}],
|
||
"polyfills": ["es5shim"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"tags": ["es5"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 5 Function per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('es5function', function() {
|
||
return !!(Function.prototype && Function.prototype.bind);
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES5 Object",
|
||
"property": "es5object",
|
||
"notes": [{
|
||
"name": "ECMAScript 5.1 Language Specification",
|
||
"href": "https://www.ecma-international.org/ecma-262/5.1/"
|
||
}],
|
||
"polyfills": ["es5shim", "es5sham"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"tags": ["es5"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 5 Object per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('es5object', function() {
|
||
return !!(Object.keys &&
|
||
Object.create &&
|
||
Object.getPrototypeOf &&
|
||
Object.getOwnPropertyNames &&
|
||
Object.isSealed &&
|
||
Object.isFrozen &&
|
||
Object.isExtensible &&
|
||
Object.getOwnPropertyDescriptor &&
|
||
Object.defineProperty &&
|
||
Object.defineProperties &&
|
||
Object.seal &&
|
||
Object.freeze &&
|
||
Object.preventExtensions);
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES5 Immutable Undefined",
|
||
"property": "es5undefined",
|
||
"notes": [{
|
||
"name": "ECMAScript 5.1 Language Specification",
|
||
"href": "https://www.ecma-international.org/ecma-262/5.1/"
|
||
}, {
|
||
"name": "original implementation of detect code",
|
||
"href": "https://kangax.github.io/compat-table/es5/"
|
||
}],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"tags": ["es5"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser prevents assignment to global `undefined` per ECMAScript 5.
|
||
*/
|
||
|
||
Modernizr.addTest('es5undefined', function() {
|
||
var result, originalUndefined;
|
||
try {
|
||
originalUndefined = window.undefined;
|
||
window.undefined = 12345;
|
||
result = typeof window.undefined === 'undefined';
|
||
window.undefined = originalUndefined;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
return result;
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES6 Array",
|
||
"property": "es6array",
|
||
"notes": [{
|
||
"name": "unofficial ECMAScript 6 draft specification",
|
||
"href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
|
||
}],
|
||
"polyfills": ["es6shim"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
|
||
"tags": ["es6"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 6 Array per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('es6array', !!(Array.prototype &&
|
||
Array.prototype.copyWithin &&
|
||
Array.prototype.fill &&
|
||
Array.prototype.find &&
|
||
Array.prototype.findIndex &&
|
||
Array.prototype.keys &&
|
||
Array.prototype.entries &&
|
||
Array.prototype.values &&
|
||
Array.from &&
|
||
Array.of));
|
||
|
||
/*!
|
||
{
|
||
"name": "ES6 Collections",
|
||
"property": "es6collections",
|
||
"notes": [{
|
||
"name": "unofficial ECMAScript 6 draft specification",
|
||
"href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
|
||
}],
|
||
"polyfills": ["es6shim", "weakmap"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
|
||
"tags": ["es6"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 6 Map, Set, WeakMap and WeakSet
|
||
*/
|
||
|
||
Modernizr.addTest('es6collections', !!(
|
||
window.Map && window.Set && window.WeakMap && window.WeakSet
|
||
));
|
||
|
||
/*!
|
||
{
|
||
"name": "ES6 Promises",
|
||
"property": "promises",
|
||
"caniuse": "promises",
|
||
"polyfills": ["es6promises"],
|
||
"authors": ["Krister Kari", "Jake Archibald"],
|
||
"tags": ["es6"],
|
||
"notes": [{
|
||
"name": "The ES6 promises spec",
|
||
"href": "https://github.com/domenic/promises-unwrapping"
|
||
}, {
|
||
"name": "Chromium dashboard - ES6 Promises",
|
||
"href": "https://www.chromestatus.com/features/5681726336532480"
|
||
}, {
|
||
"name": "JavaScript Promises: an Introduction",
|
||
"href": "https://developers.google.com/web/fundamentals/primers/promises/"
|
||
}]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 6 Promises per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('promises', function() {
|
||
return 'Promise' in window &&
|
||
// Some of these methods are missing from
|
||
// Firefox/Chrome experimental implementations
|
||
'resolve' in window.Promise &&
|
||
'reject' in window.Promise &&
|
||
'all' in window.Promise &&
|
||
'race' in window.Promise &&
|
||
// Older version of the spec had a resolver object
|
||
// as the arg rather than a function
|
||
(function() {
|
||
var resolve;
|
||
new window.Promise(function(r) { resolve = r; });
|
||
return typeof resolve === 'function';
|
||
}());
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ES6 String",
|
||
"property": "es6string",
|
||
"notes": [{
|
||
"name": "unofficial ECMAScript 6 draft specification",
|
||
"href": "https://web.archive.org/web/20180825202128/https://tc39.github.io/ecma262/"
|
||
}],
|
||
"polyfills": ["es6shim"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"warnings": ["ECMAScript 6 is still a only a draft, so this detect may not match the final specification or implementations."],
|
||
"tags": ["es6"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements ECMAScript 6 String per specification.
|
||
*/
|
||
|
||
Modernizr.addTest('es6string', !!(String.fromCodePoint &&
|
||
String.raw &&
|
||
String.prototype.codePointAt &&
|
||
String.prototype.repeat &&
|
||
String.prototype.startsWith &&
|
||
String.prototype.endsWith &&
|
||
String.prototype.includes));
|
||
|
||
/*!
|
||
{
|
||
"name": "SVG",
|
||
"property": "svg",
|
||
"caniuse": "svg",
|
||
"tags": ["svg"],
|
||
"authors": ["Erik Dahlstrom"],
|
||
"polyfills": [
|
||
"svgweb",
|
||
"raphael",
|
||
"amplesdk",
|
||
"canvg",
|
||
"svg-boilerplate",
|
||
"sie",
|
||
"dojogfx",
|
||
"fabricjs"
|
||
]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects support for SVG in `<embed>` or `<object>` elements.
|
||
*/
|
||
|
||
Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
|
||
|
||
|
||
/**
|
||
* hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
|
||
*
|
||
* @author kangax
|
||
* @access private
|
||
* @function hasOwnProp
|
||
* @param {object} object - The object to check for a property
|
||
* @param {string} property - The property to check for
|
||
* @returns {boolean}
|
||
*/
|
||
|
||
// hasOwnProperty shim by kangax needed for Safari 2.0 support
|
||
var hasOwnProp;
|
||
|
||
(function() {
|
||
var _hasOwnProperty = ({}).hasOwnProperty;
|
||
/* istanbul ignore else */
|
||
/* we have no way of testing IE 5.5 or safari 2,
|
||
* so just assume the else gets hit */
|
||
if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
|
||
hasOwnProp = function(object, property) {
|
||
return _hasOwnProperty.call(object, property);
|
||
};
|
||
}
|
||
else {
|
||
hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
|
||
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
|
||
};
|
||
}
|
||
})();
|
||
|
||
|
||
|
||
/**
|
||
* 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;
|
||
}
|
||
}
|
||
}
|
||
|
||
;
|
||
|
||
|
||
// _l tracks listeners for async tests, as well as tests that execute after the initial run
|
||
ModernizrProto._l = {};
|
||
|
||
/**
|
||
* Modernizr.on is a way to listen for the completion of async tests. Being
|
||
* asynchronous, they may not finish before your scripts run. As a result you
|
||
* will get a possibly false negative `undefined` value.
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.on
|
||
* @access public
|
||
* @function on
|
||
* @param {string} feature - String name of the feature detect
|
||
* @param {Function} cb - Callback function returning a Boolean - true if feature is supported, false if not
|
||
* @returns {void}
|
||
* @example
|
||
*
|
||
* ```js
|
||
* Modernizr.on('flash', function( result ) {
|
||
* if (result) {
|
||
* // the browser has flash
|
||
* } else {
|
||
* // the browser does not have flash
|
||
* }
|
||
* });
|
||
* ```
|
||
*/
|
||
ModernizrProto.on = function(feature, cb) {
|
||
// Create the list of listeners if it doesn't exist
|
||
if (!this._l[feature]) {
|
||
this._l[feature] = [];
|
||
}
|
||
|
||
// Push this test on to the listener list
|
||
this._l[feature].push(cb);
|
||
|
||
// If it's already been resolved, trigger it on next tick
|
||
if (Modernizr.hasOwnProperty(feature)) {
|
||
// Next Tick
|
||
setTimeout(function() {
|
||
Modernizr._trigger(feature, Modernizr[feature]);
|
||
}, 0);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* _trigger is the private function used to signal test completion and run any
|
||
* callbacks registered through [Modernizr.on](#modernizr-on)
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr._trigger
|
||
* @access private
|
||
* @function _trigger
|
||
* @param {string} feature - string name of the feature detect
|
||
* @param {Function|boolean} [res] - A feature detection function, or the boolean =
|
||
* result of a feature detection function
|
||
* @returns {void}
|
||
*/
|
||
ModernizrProto._trigger = function(feature, res) {
|
||
if (!this._l[feature]) {
|
||
return;
|
||
}
|
||
|
||
var cbs = this._l[feature];
|
||
|
||
// Force async
|
||
setTimeout(function() {
|
||
var i, cb;
|
||
for (i = 0; i < cbs.length; i++) {
|
||
cb = cbs[i];
|
||
cb(res);
|
||
}
|
||
}, 0);
|
||
|
||
// Don't trigger these again
|
||
delete this._l[feature];
|
||
};
|
||
|
||
/**
|
||
* addTest allows you to define your own feature detects that are not currently
|
||
* included in Modernizr (under the covers it's the exact same code Modernizr
|
||
* uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)).
|
||
* Just like the official detects, the result
|
||
* will be added onto the Modernizr object, as well as an appropriate className set on
|
||
* the html element when configured to do so
|
||
*
|
||
* @memberOf Modernizr
|
||
* @name Modernizr.addTest
|
||
* @optionName Modernizr.addTest()
|
||
* @optionProp addTest
|
||
* @access public
|
||
* @function addTest
|
||
* @param {string|object} feature - The string name of the feature detect, or an
|
||
* object of feature detect names and test
|
||
* @param {Function|boolean} test - Function returning true if feature is supported,
|
||
* false if not. Otherwise a boolean representing the results of a feature detection
|
||
* @returns {object} the Modernizr object to allow chaining
|
||
* @example
|
||
*
|
||
* The most common way of creating your own feature detects is by calling
|
||
* `Modernizr.addTest` with a string (preferably just lowercase, without any
|
||
* punctuation), and a function you want executed that will return a boolean result
|
||
*
|
||
* ```js
|
||
* Modernizr.addTest('itsTuesday', function() {
|
||
* var d = new Date();
|
||
* return d.getDay() === 2;
|
||
* });
|
||
* ```
|
||
*
|
||
* When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
|
||
* and to `false` every other day of the week. One thing to notice is that the names of
|
||
* feature detect functions are always lowercased when added to the Modernizr object. That
|
||
* means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
|
||
*
|
||
*
|
||
* Since we only look at the returned value from any feature detection function,
|
||
* you do not need to actually use a function. For simple detections, just passing
|
||
* in a statement that will return a boolean value works just fine.
|
||
*
|
||
* ```js
|
||
* Modernizr.addTest('hasjquery', 'jQuery' in window);
|
||
* ```
|
||
*
|
||
* Just like before, when the above runs `Modernizr.hasjquery` will be true if
|
||
* jQuery has been included on the page. Not using a function saves a small amount
|
||
* of overhead for the browser, as well as making your code much more readable.
|
||
*
|
||
* Finally, you also have the ability to pass in an object of feature names and
|
||
* their tests. This is handy if you want to add multiple detections in one go.
|
||
* The keys should always be a string, and the value can be either a boolean or
|
||
* function that returns a boolean.
|
||
*
|
||
* ```js
|
||
* var detects = {
|
||
* 'hasjquery': 'jQuery' in window,
|
||
* 'itstuesday': function() {
|
||
* var d = new Date();
|
||
* return d.getDay() === 2;
|
||
* }
|
||
* }
|
||
*
|
||
* Modernizr.addTest(detects);
|
||
* ```
|
||
*
|
||
* There is really no difference between the first methods and this one, it is
|
||
* just a convenience to let you write more readable code.
|
||
*/
|
||
function addTest(feature, test) {
|
||
|
||
if (typeof feature === 'object') {
|
||
for (var key in feature) {
|
||
if (hasOwnProp(feature, key)) {
|
||
addTest(key, feature[ key ]);
|
||
}
|
||
}
|
||
} else {
|
||
|
||
feature = feature.toLowerCase();
|
||
var featureNameSplit = feature.split('.');
|
||
var last = Modernizr[featureNameSplit[0]];
|
||
|
||
// Again, we don't check for parent test existence. Get that right, though.
|
||
if (featureNameSplit.length === 2) {
|
||
last = last[featureNameSplit[1]];
|
||
}
|
||
|
||
if (typeof last !== 'undefined') {
|
||
// we're going to quit if you're trying to overwrite an existing test
|
||
// if we were to allow it, we'd do this:
|
||
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
|
||
// docElement.className = docElement.className.replace( re, '' );
|
||
// but, no rly, stuff 'em.
|
||
return Modernizr;
|
||
}
|
||
|
||
test = typeof test === 'function' ? test() : test;
|
||
|
||
// Set the value (this is the magic, right here).
|
||
if (featureNameSplit.length === 1) {
|
||
Modernizr[featureNameSplit[0]] = test;
|
||
} 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]] = test;
|
||
}
|
||
|
||
// Set a single class (either `feature` or `no-feature`)
|
||
setClasses([(!!test && test !== false ? '' : 'no-') + featureNameSplit.join('-')]);
|
||
|
||
// Trigger the event
|
||
Modernizr._trigger(feature, test);
|
||
}
|
||
|
||
return Modernizr; // allow chaining.
|
||
}
|
||
|
||
// After all the tests are run, add self to the Modernizr prototype
|
||
Modernizr._q.push(function() {
|
||
ModernizrProto.addTest = addTest;
|
||
});
|
||
|
||
|
||
|
||
/*!
|
||
{
|
||
"name": "SVG as an <img> tag source",
|
||
"property": "svgasimg",
|
||
"caniuse": "svg-img",
|
||
"tags": ["svg"],
|
||
"aliases": ["svgincss"],
|
||
"authors": ["Chris Coyier"],
|
||
"notes": [{
|
||
"name": "HTML5 Spec",
|
||
"href": "https://www.w3.org/TR/html5/embedded-content-0.html#the-img-element"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
|
||
// Original Async test by Stu Cox
|
||
// https://gist.github.com/chriscoyier/8774501
|
||
|
||
// Now a Sync test based on good results here
|
||
// https://codepen.io/chriscoyier/pen/bADFx
|
||
|
||
// Note http://www.w3.org/TR/SVG11/feature#Image is *supposed* to represent
|
||
// support for the `<image>` tag in SVG, not an SVG file linked from an `<img>`
|
||
// tag in HTML – but it’s a heuristic which works
|
||
Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1'));
|
||
|
||
/*!
|
||
{
|
||
"name": "SVG filters",
|
||
"property": "svgfilters",
|
||
"caniuse": "svg-filters",
|
||
"tags": ["svg"],
|
||
"builderAliases": ["svg_filters"],
|
||
"authors": ["Erik Dahlstrom"],
|
||
"notes": [{
|
||
"name": "W3C Spec",
|
||
"href": "https://www.w3.org/TR/SVG11/filters.html"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
// Should fail in Safari: https://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters.
|
||
Modernizr.addTest('svgfilters', function() {
|
||
var result = false;
|
||
try {
|
||
result = 'SVGFEColorMatrixElement' in window &&
|
||
SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE === 2;
|
||
}
|
||
catch (e) {}
|
||
return result;
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "URL parser",
|
||
"property": "urlparser",
|
||
"notes": [{
|
||
"name": "WHATWG Spec",
|
||
"href": "https://url.spec.whatwg.org/"
|
||
}],
|
||
"polyfills": ["urlparser"],
|
||
"authors": ["Ron Waldon (@jokeyrhyme)"],
|
||
"tags": ["url"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Check if browser implements the URL constructor for parsing URLs.
|
||
*/
|
||
|
||
Modernizr.addTest('urlparser', function() {
|
||
var url;
|
||
try {
|
||
// have to actually try use it, because Safari defines a dud constructor
|
||
url = new URL('http://modernizr.com/');
|
||
return url.href === 'http://modernizr.com/';
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"property": "urlsearchparams",
|
||
"caniuse": "urlsearchparams",
|
||
"tags": ["querystring", "url"],
|
||
"authors": ["Cătălin Mariș"],
|
||
"name": "URLSearchParams API",
|
||
"notes": [{
|
||
"name": "WHATWG Spec",
|
||
"href": "https://url.spec.whatwg.org/#interface-urlsearchparams"
|
||
}, {
|
||
"name": "MDN Docs",
|
||
"href": "https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"
|
||
}]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects support for an API that provides utility methods for working with the query string of a URL.
|
||
*/
|
||
|
||
Modernizr.addTest('urlsearchparams', 'URLSearchParams' in window);
|
||
|
||
/*!
|
||
{
|
||
"name": "Cross-Origin Resource Sharing",
|
||
"property": "cors",
|
||
"caniuse": "cors",
|
||
"authors": ["Theodoor van Donge"],
|
||
"notes": [{
|
||
"name": "MDN Docs",
|
||
"href": "https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS"
|
||
}],
|
||
"polyfills": ["pmxdr", "ppx", "flxhr"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects support for Cross-Origin Resource Sharing: method of performing XMLHttpRequests across domains.
|
||
*/
|
||
|
||
Modernizr.addTest('cors', 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest());
|
||
|
||
/*!
|
||
{
|
||
"name": "Web Cryptography",
|
||
"property": "cryptography",
|
||
"caniuse": "cryptography",
|
||
"tags": ["crypto"],
|
||
"authors": ["roblarsen"],
|
||
"notes": [{
|
||
"name": "W3C Editor's Draft Spec",
|
||
"href": "https://www.w3.org/TR/WebCryptoAPI/"
|
||
}],
|
||
"polyfills": ["polycrypt"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects support for the cryptographic functionality available under window.crypto.subtle
|
||
*/
|
||
|
||
var crypto = prefixed('crypto', window);
|
||
Modernizr.addTest('crypto', !!prefixed('subtle', crypto));
|
||
|
||
/*!
|
||
{
|
||
"name": "iframe[sandbox] Attribute",
|
||
"property": "sandbox",
|
||
"caniuse": "iframe-sandbox",
|
||
"tags": ["iframe"],
|
||
"builderAliases": ["iframe_sandbox"],
|
||
"notes": [
|
||
{
|
||
"name": "WHATWG Spec",
|
||
"href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox"
|
||
}],
|
||
"knownBugs": ["False-positive on Firefox < 29"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Test for `sandbox` attribute in iframes.
|
||
*/
|
||
|
||
Modernizr.addTest('sandbox', 'sandbox' in createElement('iframe'));
|
||
|
||
/*!
|
||
{
|
||
"name": "JSON",
|
||
"property": "json",
|
||
"caniuse": "json",
|
||
"notes": [{
|
||
"name": "MDN Docs",
|
||
"href": "https://developer.mozilla.org/en-US/docs/Glossary/JSON"
|
||
}],
|
||
"polyfills": ["json2"]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects native support for JSON handling functions.
|
||
*/
|
||
|
||
// this will also succeed if you've loaded the JSON2.js polyfill ahead of time
|
||
// ... but that should be obvious. :)
|
||
|
||
Modernizr.addTest('json', 'JSON' in window && 'parse' in JSON && 'stringify' in JSON);
|
||
|
||
/*!
|
||
{
|
||
"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);
|
||
|
||
/*!
|
||
{
|
||
"name": "Local Storage",
|
||
"property": "localstorage",
|
||
"caniuse": "namevalue-storage",
|
||
"tags": ["storage"],
|
||
"polyfills": [
|
||
"joshuabell-polyfill",
|
||
"cupcake",
|
||
"storagepolyfill",
|
||
"amplifyjs",
|
||
"yui-cacheoffline"
|
||
]
|
||
}
|
||
!*/
|
||
|
||
// In FF4, if disabled, window.localStorage should === null.
|
||
|
||
// Normally, we could not test that directly and need to do a
|
||
// `('localStorage' in window)` test first because otherwise Firefox will
|
||
// throw bugzil.la/365772 if cookies are disabled
|
||
|
||
// Similarly, in Chrome with "Block third-party cookies and site data" enabled,
|
||
// attempting to access `window.sessionStorage` will throw an exception. crbug.com/357625
|
||
|
||
// Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
|
||
// will throw the exception:
|
||
// QUOTA_EXCEEDED_ERROR DOM Exception 22.
|
||
// Peculiarly, getItem and removeItem calls do not throw.
|
||
|
||
// Because we are forced to try/catch this, we'll go aggressive.
|
||
|
||
// Just FWIW: IE8 Compat mode supports these features completely:
|
||
// www.quirksmode.org/dom/html5.html
|
||
// But IE8 doesn't support either with local files
|
||
|
||
Modernizr.addTest('localstorage', function() {
|
||
var mod = 'modernizr';
|
||
try {
|
||
localStorage.setItem(mod, mod);
|
||
localStorage.removeItem(mod);
|
||
return true;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
});
|
||
|
||
/*!
|
||
{
|
||
"name": "ResizeObserver",
|
||
"property": "resizeobserver",
|
||
"caniuse": "resizeobserver",
|
||
"tags": ["ResizeObserver"],
|
||
"authors": ["Christian Andersson"],
|
||
"notes": [{
|
||
"name": "W3C Spec",
|
||
"href": "https://www.w3.org/TR/resize-observer/"
|
||
}, {
|
||
"name": "MDN Docs",
|
||
"href": "https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver"
|
||
}, {
|
||
"name": "Web.dev Article",
|
||
"href": "https://web.dev/resize-observer/"
|
||
}, {
|
||
"name": "Digital Ocean tutorial",
|
||
"href": "https://www.digitalocean.com/community/tutorials/js-resize-observer"
|
||
}]
|
||
}
|
||
!*/
|
||
|
||
/* DOC
|
||
Detects support for ResizeObserver.
|
||
*/
|
||
|
||
Modernizr.addTest('resizeobserver', 'ResizeObserver' in window);
|
||
|
||
/*!
|
||
{
|
||
"name": "Web Audio API",
|
||
"property": "webaudio",
|
||
"caniuse": "audio-api",
|
||
"polyfills": ["xaudiojs", "dynamicaudiojs", "audiolibjs"],
|
||
"tags": ["audio", "media"],
|
||
"builderAliases": ["audio_webaudio_api"],
|
||
"authors": ["Addy Osmani"],
|
||
"notes": [{
|
||
"name": "W3C Spec",
|
||
"href": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html"
|
||
}]
|
||
}
|
||
!*/
|
||
/* DOC
|
||
Detects the older non standard webaudio API, (as opposed to the standards based AudioContext API)
|
||
*/
|
||
|
||
Modernizr.addTest('webaudio', function() {
|
||
var prefixed = 'webkitAudioContext' in window;
|
||
var unprefixed = 'AudioContext' in window;
|
||
|
||
if (Modernizr._config.usePrefixes) {
|
||
return prefixed || unprefixed;
|
||
}
|
||
return unprefixed;
|
||
});
|
||
|
||
|
||
// 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
|
||
scriptGlobalObject.Modernizr = Modernizr;
|
||
|
||
|
||
;
|
||
|
||
})(window, window, document);
|