blob: 76c811597b58d8eec37e3773e8260a5c3ec4a8ed [file] [log] [blame]
/*!
* modernizr v3.5.0
* Build https://modernizr.com/download?-classlist-datalistelem-es5-eventlistener-framed-hidden-history-postmessage-queryselector-dontmin
*
* Copyright (c)
* Faruk Ates
* Paul Irish
* Alex Sexton
* Ryan Seddon
* Patrick Kettner
* Stu Cox
* Richard Herrera
* 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.5.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}
*/
function is(obj, type) {
return typeof obj === type;
}
;
/**
* Run through all tests and detect their support in the current UA.
*
* @access private
*/
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
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
*
* @access private
* @returns {HTMLElement|SVGElement} The root element of the document
*/
var docElement = document.documentElement;
/*!
{
"name": "classList",
"caniuse": "classlist",
"property": "classlist",
"tags": ["dom"],
"builderAliases": ["dataview_api"],
"notes": [{
"name": "MDN Docs",
"href": "https://developer.mozilla.org/en/DOM/element.classList"
}]
}
!*/
Modernizr.addTest('classlist', 'classList' in docElement);
/**
* 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);
}
}
;
/*!
{
"name": "[hidden] Attribute",
"property": "hidden",
"tags": ["dom"],
"notes": [{
"name": "WHATWG: The hidden attribute",
"href": "https://developers.whatwg.org/editing.html#the-hidden-attribute"
}, {
"name": "original implementation of detect code",
"href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L38"
}],
"polyfills": ["html5shiv"],
"authors": ["Ron Waldon (@jokeyrhyme)"]
}
!*/
/* DOC
Does the browser support the HTML5 [hidden] attribute?
*/
Modernizr.addTest('hidden', 'hidden' in createElement('a'));
/**
* 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": "Input attributes",
"property": "input",
"tags": ["forms"],
"authors": ["Mike Taylor"],
"notes": [{
"name": "WHATWG spec",
"href": "https://html.spec.whatwg.org/multipage/forms.html#input-type-attr-summary"
}],
"knownBugs": ["Some blackberry devices report false positive for input.multiple"]
}
!*/
/* DOC
Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results:
```javascript
Modernizr.input.autocomplete
Modernizr.input.autofocus
Modernizr.input.list
Modernizr.input.max
Modernizr.input.min
Modernizr.input.multiple
Modernizr.input.pattern
Modernizr.input.placeholder
Modernizr.input.required
Modernizr.input.step
```
*/
// Run through HTML5's new input attributes to see if the UA understands any.
// Mike Taylr has created a comprehensive resource for testing these attributes
// when applied to all input types:
// miketaylr.com/code/input-type-attr.html
// Only input placeholder is tested while textarea's placeholder is not.
// Currently Safari 4 and Opera 11 have support only for the input placeholder
// Both tests are available in feature-detects/forms-placeholder.js
var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ');
var attrs = {};
Modernizr.input = (function(props) {
for (var i = 0, len = props.length; i < len; i++) {
attrs[ props[i] ] = !!(props[i] in inputElem);
}
if (attrs.list) {
// safari false positive's on datalist: webk.it/74252
// see also github.com/Modernizr/Modernizr/issues/146
attrs.list = !!(createElement('datalist') && window.HTMLDataListElement);
}
return attrs;
})(inputattrs);
/*!
{
"name": "datalist Element",
"caniuse": "datalist",
"property": "datalistelem",
"tags": ["elem"],
"builderAliases": ["elem_datalist"],
"warnings": ["This test is a dupe of Modernizr.input.list. Only around for legacy reasons."],
"notes": [{
"name": "CSS Tricks Article",
"href": "https://css-tricks.com/15346-relevant-dropdowns-polyfill-for-datalist/"
},{
"name": "Mike Taylor Code",
"href": "https://miketaylr.com/code/datalist.html"
}]
}
!*/
// lol. we already have a test for datalist built in! silly you.
// Leaving it around in case anyone's using it
Modernizr.addTest('datalistelem', Modernizr.input.list);
/*!
{
"name": "ES5 Array",
"property": "es5array",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}],
"polyfills": ["es5shim"],
"authors": ["Ron Waldon (@jokeyrhyme)"],
"tags": ["es5"]
}
!*/
/* DOC
Check if browser implements ECMAScript 5 Array per specification.
*/
Modernizr.addTest('es5array', function() {
return !!(Array.prototype &&
Array.prototype.every &&
Array.prototype.filter &&
Array.prototype.forEach &&
Array.prototype.indexOf &&
Array.prototype.lastIndexOf &&
Array.prototype.map &&
Array.prototype.some &&
Array.prototype.reduce &&
Array.prototype.reduceRight &&
Array.isArray);
});
/*!
{
"name": "ES5 Date",
"property": "es5date",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://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": "http://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": "http://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 Strict Mode",
"property": "strictmode",
"caniuse": "sctrict-mode",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}],
"authors": ["@kangax"],
"tags": ["es5"],
"builderAliases": ["es5_strictmode"]
}
!*/
/* DOC
Check if browser implements ECMAScript 5 Object strict mode.
*/
Modernizr.addTest('strictmode', (function() {'use strict'; return !this; })());
/*!
{
"name": "ES5 String",
"property": "es5string",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}],
"polyfills": ["es5shim"],
"authors": ["Ron Waldon (@jokeyrhyme)"],
"tags": ["es5"]
}
!*/
/* DOC
Check if browser implements ECMAScript 5 String per specification.
*/
Modernizr.addTest('es5string', function() {
return !!(String.prototype && String.prototype.trim);
});
/*!
{
"name": "JSON",
"property": "json",
"caniuse": "json",
"notes": [{
"name": "MDN documentation",
"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": "ES5 Syntax",
"property": "es5syntax",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}, {
"name": "original implementation of detect code",
"href": "http://kangax.github.io/es5-compat-table/"
}],
"authors": ["Ron Waldon (@jokeyrhyme)"],
"warnings": ["This detect uses `eval()`, so CSP may be a problem."],
"tags": ["es5"]
}
!*/
/* DOC
Check if browser accepts ECMAScript 5 syntax.
*/
Modernizr.addTest('es5syntax', function() {
var value, obj, stringAccess, getter, setter, reservedWords, zeroWidthChars;
try {
/* eslint no-eval: "off" */
// Property access on strings
stringAccess = eval('"foobar"[3] === "b"');
// Getter in property initializer
getter = eval('({ get x(){ return 1 } }).x === 1');
eval('({ set x(v){ value = v; } }).x = 1');
// Setter in property initializer
setter = value === 1;
// Reserved words as property names
eval('obj = ({ if: 1 })');
reservedWords = obj['if'] === 1;
// Zero-width characters in identifiers
zeroWidthChars = eval('_\u200c\u200d = true');
return stringAccess && getter && setter && reservedWords && zeroWidthChars;
} catch (ignore) {
return false;
}
});
/*!
{
"name": "ES5 Immutable Undefined",
"property": "es5undefined",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}, {
"name": "original implementation of detect code",
"href": "http://kangax.github.io/es5-compat-table/"
}],
"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": "ES5",
"property": "es5",
"notes": [{
"name": "ECMAScript 5.1 Language Specification",
"href": "http://www.ecma-international.org/ecma-262/5.1/"
}],
"polyfills": ["es5shim", "es5sham"],
"authors": ["Ron Waldon (@jokeyrhyme)"],
"tags": ["es5"]
}
!*/
/* DOC
Check if browser implements everything as specified in ECMAScript 5.
*/
Modernizr.addTest('es5', function() {
return !!(
Modernizr.es5array &&
Modernizr.es5date &&
Modernizr.es5function &&
Modernizr.es5object &&
Modernizr.strictmode &&
Modernizr.es5string &&
Modernizr.json &&
Modernizr.es5syntax &&
Modernizr.es5undefined
);
});
/*!
{
"name": "Event Listener",
"property": "eventlistener",
"authors": ["Andrew Betts (@triblondon)"],
"notes": [{
"name": "W3C Spec",
"href": "https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces"
}],
"polyfills": ["eventlistener"]
}
!*/
/* DOC
Detects native support for addEventListener
*/
Modernizr.addTest('eventlistener', 'addEventListener' in window);
/*!
{
"name": "History API",
"property": "history",
"caniuse": "history",
"tags": ["history"],
"authors": ["Hay Kranen", "Alexander Farkas"],
"notes": [{
"name": "W3C Spec",
"href": "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
}, {
"name": "MDN documentation",
"href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
}],
"polyfills": ["historyjs", "html5historyapi"]
}
!*/
/* DOC
Detects support for the History API for manipulating the browser session history.
*/
Modernizr.addTest('history', function() {
// Issue #733
// The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
// Unfortunately support is really buggy and there is no clean way to detect
// these bugs, so we fall back to a user agent sniff :(
var ua = navigator.userAgent;
// We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
// itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
if ((ua.indexOf('Android 2.') !== -1 ||
(ua.indexOf('Android 4.0') !== -1)) &&
ua.indexOf('Mobile Safari') !== -1 &&
ua.indexOf('Chrome') === -1 &&
ua.indexOf('Windows Phone') === -1 &&
// Since all documents on file:// share an origin, the History apis are
// blocked there as well
location.protocol !== 'file:'
) {
return false;
}
// Return the regular check
return (window.history && 'pushState' in window.history);
});
/*!
{
"name": "postMessage",
"property": "postmessage",
"caniuse": "x-doc-messaging",
"notes": [{
"name": "W3C Spec",
"href": "http://www.w3.org/TR/html5/comms.html#posting-messages"
}],
"polyfills": ["easyxdm", "postmessage-jquery"]
}
!*/
/* DOC
Detects support for the `window.postMessage` protocol for cross-document messaging.
*/
Modernizr.addTest('postmessage', 'postMessage' in window);
/*!
{
"name": "QuerySelector",
"property": "queryselector",
"caniuse": "queryselector",
"tags": ["queryselector"],
"authors": ["Andrew Betts (@triblondon)"],
"notes": [{
"name" : "W3C Selectors reference",
"href": "https://www.w3.org/TR/selectors-api/#queryselectorall"
}],
"polyfills": ["css-selector-engine"]
}
!*/
/* DOC
Detects support for querySelector.
*/
Modernizr.addTest('queryselector', 'querySelector' in document && 'querySelectorAll' in document);
/*!
{
"name": "Framed window",
"property": "framed",
"tags": ["window"],
"builderAliases": ["window_framed"]
}
!*/
/* DOC
Tests if page is iframed.
*/
// github.com/Modernizr/Modernizr/issues/242
Modernizr.addTest('framed', window.location != top.location);
// 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);