|
@@ -0,0 +1,1321 @@
|
|
|
+/*!
|
|
|
+ * modernizr v3.5.0
|
|
|
+ * Build https://modernizr.com/download?-adownload-canvas-cssanimations-csstransforms-documentfragment-fullscreen-localstorage-svg-texttrackapi_track-todataurljpeg_todataurlpng_todataurlwebp-video-websockets-setclasses-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 classes = [];
|
|
|
+
|
|
|
+
|
|
|
+ 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();
|
|
|
+
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "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);
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "WebSockets Support",
|
|
|
+ "property": "websockets",
|
|
|
+ "authors": ["Phread [fearphage]", "Mike Sherov [mikesherov]", "Burak Yigit Kaya [BYK]"],
|
|
|
+ "caniuse": "websockets",
|
|
|
+ "tags": ["html5"],
|
|
|
+ "warnings": [
|
|
|
+ "This test will reject any old version of WebSockets even if it is not prefixed such as in Safari 5.1"
|
|
|
+ ],
|
|
|
+ "notes": [{
|
|
|
+ "name": "CLOSING State and Spec",
|
|
|
+ "href": "https://www.w3.org/TR/websockets/#the-websocket-interface"
|
|
|
+ }],
|
|
|
+ "polyfills": [
|
|
|
+ "sockjs",
|
|
|
+ "socketio",
|
|
|
+ "kaazing-websocket-gateway",
|
|
|
+ "websocketjs",
|
|
|
+ "atmosphere",
|
|
|
+ "graceful-websocket",
|
|
|
+ "portal",
|
|
|
+ "datachannel"
|
|
|
+ ]
|
|
|
+}
|
|
|
+!*/
|
|
|
+
|
|
|
+ var supports = false;
|
|
|
+ try {
|
|
|
+ supports = 'WebSocket' in window && window.WebSocket.CLOSING === 2;
|
|
|
+ } catch (e) {}
|
|
|
+ Modernizr.addTest('websockets', supports);
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "Local Storage",
|
|
|
+ "property": "localstorage",
|
|
|
+ "caniuse": "namevalue-storage",
|
|
|
+ "tags": ["storage"],
|
|
|
+ "knownBugs": [],
|
|
|
+ "notes": [],
|
|
|
+ "warnings": [],
|
|
|
+ "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;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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": "Document Fragment",
|
|
|
+ "property": "documentfragment",
|
|
|
+ "notes": [{
|
|
|
+ "name": "W3C DOM Level 1 Reference",
|
|
|
+ "href": "https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3"
|
|
|
+ }, {
|
|
|
+ "name": "SitePoint Reference",
|
|
|
+ "href": "http://reference.sitepoint.com/javascript/DocumentFragment"
|
|
|
+ }, {
|
|
|
+ "name": "QuirksMode Compatibility Tables",
|
|
|
+ "href": "http://www.quirksmode.org/m/w3c_core.html#t112"
|
|
|
+ }],
|
|
|
+ "authors": ["Ron Waldon (@jokeyrhyme)"],
|
|
|
+ "knownBugs": ["false-positive on Blackberry 9500, see QuirksMode note"],
|
|
|
+ "tags": []
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+Append multiple elements to the DOM within a single insertion.
|
|
|
+*/
|
|
|
+
|
|
|
+ Modernizr.addTest('documentfragment', function() {
|
|
|
+ return 'createDocumentFragment' in document &&
|
|
|
+ 'appendChild' 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';
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "Canvas",
|
|
|
+ "property": "canvas",
|
|
|
+ "caniuse": "canvas",
|
|
|
+ "tags": ["canvas", "graphics"],
|
|
|
+ "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+Detects support for the `<canvas>` element for 2D drawing.
|
|
|
+*/
|
|
|
+
|
|
|
+ // On the S60 and BB Storm, getContext exists, but always returns undefined
|
|
|
+ // so we actually have to call getContext() to verify
|
|
|
+ // github.com/Modernizr/Modernizr/issues/issue/97/
|
|
|
+ Modernizr.addTest('canvas', function() {
|
|
|
+ var elem = createElement('canvas');
|
|
|
+ return !!(elem.getContext && elem.getContext('2d'));
|
|
|
+ });
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "HTML5 Video",
|
|
|
+ "property": "video",
|
|
|
+ "caniuse": "video",
|
|
|
+ "tags": ["html5"],
|
|
|
+ "knownBugs": [
|
|
|
+ "Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546"
|
|
|
+ ],
|
|
|
+ "polyfills": [
|
|
|
+ "html5media",
|
|
|
+ "mediaelementjs",
|
|
|
+ "sublimevideo",
|
|
|
+ "videojs",
|
|
|
+ "leanbackplayer",
|
|
|
+ "videoforeverybody"
|
|
|
+ ]
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+Detects support for the video element, as well as testing what types of content it supports.
|
|
|
+
|
|
|
+Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.:
|
|
|
+
|
|
|
+```javascript
|
|
|
+Modernizr.video // true
|
|
|
+Modernizr.video.ogg // 'probably'
|
|
|
+```
|
|
|
+*/
|
|
|
+
|
|
|
+ // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
|
|
|
+ // thx to NielsLeenheer and zcorpan
|
|
|
+
|
|
|
+ // Note: in some older browsers, "no" was a return value instead of empty string.
|
|
|
+ // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
|
|
|
+ // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
|
|
|
+
|
|
|
+ Modernizr.addTest('video', function() {
|
|
|
+ var elem = createElement('video');
|
|
|
+ var bool = false;
|
|
|
+
|
|
|
+ // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
|
|
|
+ try {
|
|
|
+ bool = !!elem.canPlayType
|
|
|
+ if (bool) {
|
|
|
+ bool = new Boolean(bool);
|
|
|
+ bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');
|
|
|
+
|
|
|
+ // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
|
|
|
+ bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');
|
|
|
+
|
|
|
+ bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
|
|
|
+
|
|
|
+ bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, '');
|
|
|
+
|
|
|
+ bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, '');
|
|
|
+ }
|
|
|
+ } catch (e) {}
|
|
|
+
|
|
|
+ return bool;
|
|
|
+ });
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "a[download] Attribute",
|
|
|
+ "property": "adownload",
|
|
|
+ "caniuse" : "download",
|
|
|
+ "tags": ["media", "attribute"],
|
|
|
+ "builderAliases": ["a_download"],
|
|
|
+ "notes": [{
|
|
|
+ "name": "WhatWG Reference",
|
|
|
+ "href": "https://developers.whatwg.org/links.html#downloading-resources"
|
|
|
+ }]
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+When used on an `<a>`, this attribute signifies that the resource it points to should be downloaded by the browser rather than navigating to it.
|
|
|
+*/
|
|
|
+
|
|
|
+ Modernizr.addTest('adownload', !window.externalHost && 'download' in createElement('a'));
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "canvas.toDataURL type support",
|
|
|
+ "property": ["todataurljpeg", "todataurlpng", "todataurlwebp"],
|
|
|
+ "tags": ["canvas"],
|
|
|
+ "builderAliases": ["canvas_todataurl_type"],
|
|
|
+ "async" : false,
|
|
|
+ "notes": [{
|
|
|
+ "name": "MDN article",
|
|
|
+ "href": "https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement.toDataURL"
|
|
|
+ }]
|
|
|
+}
|
|
|
+!*/
|
|
|
+
|
|
|
+
|
|
|
+ var canvas = createElement('canvas');
|
|
|
+
|
|
|
+ Modernizr.addTest('todataurljpeg', function() {
|
|
|
+ return !!Modernizr.canvas && canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
|
|
|
+ });
|
|
|
+ Modernizr.addTest('todataurlpng', function() {
|
|
|
+ return !!Modernizr.canvas && canvas.toDataURL('image/png').indexOf('data:image/png') === 0;
|
|
|
+ });
|
|
|
+ Modernizr.addTest('todataurlwebp', function() {
|
|
|
+ var supports = false;
|
|
|
+
|
|
|
+ // firefox 3 throws an error when you use an "invalid" toDataUrl
|
|
|
+ try {
|
|
|
+ supports = !!Modernizr.canvas && canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
|
|
|
+ } catch (e) {}
|
|
|
+
|
|
|
+ return supports;
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "Track element and Timed Text Track",
|
|
|
+ "property": ["texttrackapi", "track"],
|
|
|
+ "tags": ["elem"],
|
|
|
+ "builderAliases": ["elem_track"],
|
|
|
+ "authors": ["Addy Osmani"],
|
|
|
+ "notes": [{
|
|
|
+ "name": "W3 track Element Spec",
|
|
|
+ "href": "http://www.w3.org/TR/html5/video.html#the-track-element"
|
|
|
+ },{
|
|
|
+ "name": "W3 track API Spec",
|
|
|
+ "href": "http://www.w3.org/TR/html5/media-elements.html#text-track-api"
|
|
|
+ }],
|
|
|
+ "warnings": ["While IE10 has implemented the track element, IE10 does not expose the underlying APIs to create timed text tracks by JS (really sad)"]
|
|
|
+}
|
|
|
+!*/
|
|
|
+
|
|
|
+ Modernizr.addTest('texttrackapi', typeof (createElement('video').addTextTrack) === 'function');
|
|
|
+
|
|
|
+ // a more strict test for track including UI support: document.createElement('track').kind === 'subtitles'
|
|
|
+ Modernizr.addTest('track', 'kind' in createElement('track'));
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * cssToDOM takes a kebab-case string and converts it to camelCase
|
|
|
+ * e.g. box-sizing -> boxSizing
|
|
|
+ *
|
|
|
+ * @access private
|
|
|
+ * @function cssToDOM
|
|
|
+ * @param {string} name - String name of kebab-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(/^-/, '');
|
|
|
+ }
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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 kebab-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;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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}
|
|
|
+ */
|
|
|
+
|
|
|
+ function contains(str, substr) {
|
|
|
+ return !!~('' + str).indexOf(substr);
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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 {false|*} 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 overriden
|
|
|
+ return fnBind(item, elem || obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return the unbound function or obj or value
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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;
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * domToCSS takes a camelCase string and converts it to kebab-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 kebab-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} - The element we want to find the computed styles of
|
|
|
+ * @param {string|null} [pseudoSelector]- An optional pseudo element selector (e.g. :before), of null if none
|
|
|
+ * @returns {CSSStyleDeclaration}
|
|
|
+ */
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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}
|
|
|
+ */
|
|
|
+
|
|
|
+ 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.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;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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: http://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;
|
|
|
+ }
|
|
|
+ ;
|
|
|
+
|
|
|
+ // 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 kebab-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;
|
|
|
+ }
|
|
|
+
|
|
|
+ ;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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 {false|string} 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;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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|false} 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 kebab-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 kebab-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 kebab-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": "Fullscreen API",
|
|
|
+ "property": "fullscreen",
|
|
|
+ "caniuse": "fullscreen",
|
|
|
+ "notes": [{
|
|
|
+ "name": "MDN documentation",
|
|
|
+ "href": "https://developer.mozilla.org/en/API/Fullscreen"
|
|
|
+ }],
|
|
|
+ "polyfills": ["screenfulljs"],
|
|
|
+ "builderAliases": ["fullscreen_api"]
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+Detects support for the ability to make the current website take over the user's entire screen
|
|
|
+*/
|
|
|
+
|
|
|
+ // github.com/Modernizr/Modernizr/issues/739
|
|
|
+ Modernizr.addTest('fullscreen', !!(prefixed('exitFullscreen', document, false) || prefixed('cancelFullScreen', document, false)));
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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 kebab-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
|
|
|
+ * @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://goo.gl/OGw5Gm"
|
|
|
+ }]
|
|
|
+}
|
|
|
+!*/
|
|
|
+/* DOC
|
|
|
+Detects whether or not elements can be animated using CSS
|
|
|
+*/
|
|
|
+
|
|
|
+ Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
|
|
|
+
|
|
|
+/*!
|
|
|
+{
|
|
|
+ "name": "CSS Transforms",
|
|
|
+ "property": "csstransforms",
|
|
|
+ "caniuse": "transforms2d",
|
|
|
+ "tags": ["css"]
|
|
|
+}
|
|
|
+!*/
|
|
|
+
|
|
|
+ Modernizr.addTest('csstransforms', function() {
|
|
|
+ // Android < 3.0 is buggy, so we sniff and blacklist
|
|
|
+ // http://git.io/hHzL7w
|
|
|
+ return navigator.userAgent.indexOf('Android 2.') === -1 &&
|
|
|
+ testAllProps('transform', 'scale(1)', true);
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ // 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
|
|
|
+ window.Modernizr = Modernizr;
|
|
|
+
|
|
|
+
|
|
|
+;
|
|
|
+
|
|
|
+})(window, document);
|