/*!
* modernizr v3.3.1
* Build https://modernizr.com/download?-adownload-ambientlight-animation-apng-appearance-applicationcache-atobbtoa-audio-audioloop-audiopreload-backdropfilter-backgroundblendmode-backgroundcliptext-backgroundsize-batteryapi-bdi-beacon-bgpositionshorthand-bgpositionxy-bgrepeatspace_bgrepeatround-bgsizecover-blobconstructor-bloburls-blobworkers-borderimage-borderradius-boxshadow-boxsizing-canvas-canvasblending-canvastext-canvaswinding-capture-checked-classlist-contains-contenteditable-contextmenu-cookies-cors-createelementattrs_createelement_attrs-cryptography-cssall-cssanimations-csscalc-csschunit-csscolumns-cssescape-cssexunit-cssfilters-cssgradients-csshairline-csshyphens_softhyphens_softhyphensfind-cssinvalid-cssmask-csspointerevents-csspositionsticky-csspseudoanimations-csspseudotransitions-cssreflections-cssremunit-cssresize-cssscrollbar-csstransforms-csstransforms3d-csstransitions-cssvalid-cssvhunit-cssvmaxunit-cssvminunit-cssvwunit-cubicbezierrange-customevent-customprotocolhandler-dart-datachannel-datalistelem-dataset-datauri-dataview-dataworkers-details-devicemotion_deviceorientation-directory-display_runin-displaytable-documentfragment-ellipsis-emoji-es5-es5array-es5date-es5function-es5object-es5string-es5syntax-es5undefined-es6array-es6collections-es6math-es6number-es6object-es6string-eventlistener-eventsource-exiforientation-fetch-fileinput-filereader-filesystem-flash-flexbox-flexboxlegacy-flexboxtweener-flexwrap-fontface-forcetouch-formattribute-formvalidation-framed-fullscreen-gamepads-generatedcontent-generators-geolocation-getrandomvalues-getusermedia-hashchange-hidden-hiddenscroll-history-hsla-htmlimports-ie8compat-imgcrossorigin-indexeddb-indexeddbblob-inlinesvg-input-inputformaction-inputformenctype-inputformmethod-inputformtarget-inputtypes-intl-jpeg2000-jpegxr-json-lastchild-ligatures-localizednumber-localstorage-lowbandwidth-lowbattery-matchmedia-mathml-mediaqueries-microdata-multiplebgs-mutationobserver-notification-nthchild-objectfit-olreversed-oninput-opacity-outputelem-overflowscrolling-pagevisibility-peerconnection-performance-picture-placeholder-pointerevents-pointerlock-postmessage-preserve3d-progressbar_meter-promises-proximity-queryselector-quotamanagement-regions-requestanimationframe-requestautocomplete-rgba-ruby-sandbox-scriptasync-scriptdefer-scrollsnappoints-seamless-search-serviceworker-sessionstorage-shapes-sharedworkers-siblinggeneral-sizes-smil-speechrecognition-speechsynthesis-srcdoc-srcset-strictmode-stylescoped-subpixelfont-supports-svg-svgasimg-svgclippaths-svgfilters-svgforeignobject-target-template-templatestrings-textalignlast-textareamaxlength-textshadow-texttrackapi_track-time-todataurljpeg_todataurlpng_todataurlwebp-touchevents-transferables-typedarrays-unicode-unicoderange-unknownelements-urlparser-userdata-userselect-vibrate-video-videoautoplay-videoloop-videopreload-vml-webaudio-webgl-webglextensions-webintents-webp-webpalpha-webpanimation-webplossless_webp_lossless-websockets-websocketsbinary-websqldatabase-webworkers-willchange-wrapflow-xdomainrequest-xhr2-xhrresponsetype-xhrresponsetypearraybuffer-xhrresponsetypeblob-xhrresponsetypedocument-xhrresponsetypejson-xhrresponsetypetext-addtest-atrule-domprefixes-hasevent-mq-prefixed-prefixedcss-prefixedcssvalue-prefixes-printshiv-setclasses-testallprops-testprop-teststyles-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 `` element. This
* information allows you to progressively enhance your pages with a granular level
* of control over the experience.
*/
;(function(window, document, undefined){
/**
* 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;
/**
* 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;
/*!
{
"name": "Context menus",
"property": "contextmenu",
"caniuse": "menu",
"notes": [{
"name": "W3C spec",
"href": "http://www.w3.org/TR/html5/interactive-elements.html#context-menus"
},{
"name": "thewebrocks.com Demo",
"href": "http://thewebrocks.com/demos/context-menu/"
}],
"polyfills": ["jquery-contextmenu"]
}
!*/
/* DOC
Detects support for custom context menus.
*/
Modernizr.addTest(
'contextmenu',
('contextMenu' in docElement && 'HTMLMenuItemElement' in window)
);
/*!
{
"name": "cssall",
"property": "cssall",
"notes": [{
"name": "Spec",
"href": "https://drafts.csswg.org/css-cascade/#all-shorthand"
}]
}
!*/
/* DOC
Detects support for the `all` css property, which is a shorthand to reset all css properties (except direction and unicode-bidi) to their original value
*/
Modernizr.addTest('cssall', 'all' in docElement.style);
/*!
{
"name": "will-change",
"property": "willchange",
"notes": [{
"name": "Spec",
"href": "https://drafts.csswg.org/css-will-change/"
}]
}
!*/
/* DOC
Detects support for the `will-change` css property, which formally signals to the
browser that an element will be animating.
*/
Modernizr.addTest('willchange', 'willChange' in docElement.style);
/*!
{
"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);
/*!
{
"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;
});
/**
* 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);
isSVG ? docElement.className.baseVal = className : 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
* @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
*/
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 offical 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
* @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
/* jshint -W053 */
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`)
/* jshint -W041 */
setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
/* jshint +W041 */
// 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": "EXIF Orientation",
"property": "exiforientation",
"tags": ["image"],
"builderAliases": ["exif_orientation"],
"async": true,
"authors": ["Paul Sayre"],
"notes": [{
"name": "Article by Dave Perrett",
"href": "http://recursive-design.com/blog/2012/07/28/exif-orientation-handling-is-a-ghetto/"
},{
"name": "Article by Calvin Hass",
"href": "http://www.impulseadventure.com/photo/exif-orientation.html"
}]
}
!*/
/* DOC
Detects support for EXIF Orientation in JPEG images.
iOS looks at the EXIF Orientation flag in JPEGs and rotates the image accordingly. Most desktop browsers just ignore this data.
*/
// Bug trackers:
// bugzil.la/298619 (unimplemented)
// crbug.com/56845 (looks incomplete)
// webk.it/19688 (available upstream but its up all ports to turn on individually)
Modernizr.addAsyncTest(function() {
var img = new Image();
img.onerror = function() {
addTest('exiforientation', false, {aliases: ['exif-orientation']});
};
img.onload = function() {
addTest('exiforientation', img.width !== 2, {aliases: ['exif-orientation']});
};
// There may be a way to shrink this more, it's a 1x2 white jpg with the orientation flag set to 6
img.src = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAAAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigD/2Q==';
});
/*!
{
"authors": ["Cătălin Mariș"],
"caniuse": "proximity",
"name": "Proximity API",
"notes": [{
"name": "MDN documentation",
"href": "https://developer.mozilla.org/en-US/docs/Web/API/Proximity_Events"
},{
"name": "W3C specification",
"href": "https://www.w3.org/TR/proximity/"
}],
"property": "proximity",
"tags": ["events", "proximity"]
}
!*/
/* DOC
Detects support for an API that allows users to get proximity related information from the device's proximity sensor.
*/
Modernizr.addAsyncTest(function() {
var timeout;
var timeoutTime = 300;
function advertiseSupport() {
// Clean up after ourselves
clearTimeout(timeout);
window.removeEventListener('deviceproximity', advertiseSupport);
// Advertise support as the browser supports
// the API and the device has a proximity sensor
addTest('proximity', true);
}
// Check if the browser has support for the API
if ('ondeviceproximity' in window && 'onuserproximity' in window) {
// Check if the device has a proximity sensor
// ( devices without such a sensor support the events but
// will never fire them resulting in a false positive )
window.addEventListener('deviceproximity', advertiseSupport);
// If the event doesn't fire in a reasonable amount of time,
// it means that the device doesn't have a proximity sensor,
// thus, we can advertise the "lack" of support
timeout = setTimeout(function() {
window.removeEventListener('deviceproximity', advertiseSupport);
addTest('proximity', false);
}, timeoutTime);
} else {
addTest('proximity', false);
}
});
/*!
{
"name": "JPEG XR (extended range)",
"async": true,
"aliases": ["jpeg-xr"],
"property": "jpegxr",
"tags": ["image"],
"notes": [{
"name": "Wikipedia Article",
"href": "https://en.wikipedia.org/wiki/JPEG_XR"
}]
}
!*/
/* DOC
Test for JPEG XR support
*/
Modernizr.addAsyncTest(function() {
var image = new Image();
image.onload = image.onerror = function() {
addTest('jpegxr', image.width == 1, {aliases: ['jpeg-xr']});
};
image.src = 'data:image/vnd.ms-photo;base64,SUm8AQgAAAAFAAG8AQAQAAAASgAAAIC8BAABAAAAAQAAAIG8BAABAAAAAQAAAMC8BAABAAAAWgAAAMG8BAABAAAAHwAAAAAAAAAkw91vA07+S7GFPXd2jckNV01QSE9UTwAZAYBxAAAAABP/gAAEb/8AAQAAAQAAAA==';
});
/*!
{
"name": "JPEG 2000",
"async": true,
"aliases": ["jpeg-2000", "jpg2"],
"property": "jpeg2000",
"tags": ["image"],
"authors": ["@eric_wvgg"],
"notes": [{
"name": "Wikipedia Article",
"href": "https://en.wikipedia.org/wiki/JPEG_2000"
}]
}
!*/
/* DOC
Test for JPEG 2000 support
*/
Modernizr.addAsyncTest(function() {
var image = new Image();
image.onload = image.onerror = function() {
addTest('jpeg2000', image.width == 1);
};
image.src = 'data:image/jp2;base64,/0//UQAyAAAAAAABAAAAAgAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAEBwEBBwEBBwEBBwEB/1IADAAAAAEAAAQEAAH/XAAEQED/ZAAlAAFDcmVhdGVkIGJ5IE9wZW5KUEVHIHZlcnNpb24gMi4wLjD/kAAKAAAAAABYAAH/UwAJAQAABAQAAf9dAAUBQED/UwAJAgAABAQAAf9dAAUCQED/UwAJAwAABAQAAf9dAAUDQED/k8+kEAGvz6QQAa/PpBABr994EAk//9k=';
});
/*!
{
"name": "Webp Alpha",
"async": true,
"property": "webpalpha",
"aliases": ["webp-alpha"],
"tags": ["image"],
"authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
"notes": [{
"name": "WebP Info",
"href": "https://developers.google.com/speed/webp/"
},{
"name": "Article about WebP support on Android browsers",
"href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/"
},{
"name": "Chromium WebP announcement",
"href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
}]
}
!*/
/* DOC
Tests for transparent webp support.
*/
Modernizr.addAsyncTest(function() {
var image = new Image();
image.onerror = function() {
addTest('webpalpha', false, {aliases: ['webp-alpha']});
};
image.onload = function() {
addTest('webpalpha', image.width == 1, {aliases: ['webp-alpha']});
};
image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==';
});
/*!
{
"name": "Webp Animation",
"async": true,
"property": "webpanimation",
"aliases": ["webp-animation"],
"tags": ["image"],
"authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
"notes": [{
"name": "WebP Info",
"href": "https://developers.google.com/speed/webp/"
},{
"name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
"href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
}]
}
!*/
/* DOC
Tests for animated webp support.
*/
Modernizr.addAsyncTest(function() {
var image = new Image();
image.onerror = function() {
addTest('webpanimation', false, {aliases: ['webp-animation']});
};
image.onload = function() {
addTest('webpanimation', image.width == 1, {aliases: ['webp-animation']});
};
image.src = 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';
});
/*!
{
"name": "Webp Lossless",
"async": true,
"property": ["webplossless", "webp-lossless"],
"tags": ["image"],
"authors": ["@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
"notes": [{
"name": "Webp Info",
"href": "https://developers.google.com/speed/webp/"
},{
"name": "Webp Lossless Spec",
"href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
}]
}
!*/
/* DOC
Tests for non-alpha lossless webp support.
*/
Modernizr.addAsyncTest(function() {
var image = new Image();
image.onerror = function() {
addTest('webplossless', false, {aliases: ['webp-lossless']});
};
image.onload = function() {
addTest('webplossless', image.width == 1, {aliases: ['webp-lossless']});
};
image.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
});
/*!
{
"name": "Webp",
"async": true,
"property": "webp",
"tags": ["image"],
"builderAliases": ["img_webp"],
"authors": ["Krister Kari", "@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
"notes": [{
"name": "Webp Info",
"href": "https://developers.google.com/speed/webp/"
}, {
"name": "Chormium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
"href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
}, {
"name": "Webp Lossless Spec",
"href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
}, {
"name": "Article about WebP support on Android browsers",
"href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/"
}, {
"name": "Chormium WebP announcement",
"href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
}]
}
!*/
/* DOC
Tests for lossy, non-alpha webp support.
Tests for all forms of webp support (lossless, lossy, alpha, and animated)..
Modernizr.webp // Basic support (lossy)
Modernizr.webp.lossless // Lossless
Modernizr.webp.alpha // Alpha (both lossy and lossless)
Modernizr.webp.animation // Animated WebP
*/
Modernizr.addAsyncTest(function() {
var webpTests = [{
'uri': 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=',
'name': 'webp'
}, {
'uri': 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==',
'name': 'webp.alpha'
}, {
'uri': 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA',
'name': 'webp.animation'
}, {
'uri': 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=',
'name': 'webp.lossless'
}];
var webp = webpTests.shift();
function test(name, uri, cb) {
var image = new Image();
function addResult(event) {
// if the event is from 'onload', check the see if the image's width is
// 1 pixel (which indiciates support). otherwise, it fails
var result = event && event.type === 'load' ? image.width == 1 : false;
var baseTest = name === 'webp';
/* jshint -W053 */
addTest(name, baseTest ? new Boolean(result) : result);
if (cb) {
cb(event);
}
}
image.onerror = addResult;
image.onload = addResult;
image.src = uri;
}
// test for webp support in general
test(webp.name, webp.uri, function(e) {
// if the webp test loaded, test everything else.
if (e && e.type === 'load') {
for (var i = 0; i < webpTests.length; i++) {
test(webpTests[i].name, webpTests[i].uri);
}
}
});
});
/*!
{
"name": "SVG as an tag source",
"property": "svgasimg",
"caniuse" : "svg-img",
"tags": ["svg"],
"authors": ["Chris Coyier"],
"notes": [{
"name": "HTML5 Spec",
"href": "http://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
// http://codepen.io/chriscoyier/pen/bADFx
// Note http://www.w3.org/TR/SVG11/feature#Image is *supposed* to represent
// support for the `` tag in SVG, not an SVG file linked from an ``
// 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": "Data URI",
"property": "datauri",
"caniuse": "datauri",
"tags": ["url"],
"builderAliases": ["url_data_uri"],
"async": true,
"notes": [{
"name": "Wikipedia article",
"href": "https://en.wikipedia.org/wiki/Data_URI_scheme"
}],
"warnings": ["Support in Internet Explorer 8 is limited to images and linked resources like CSS files, not HTML files"]
}
!*/
/* DOC
Detects support for data URIs. Provides a subproperty to report support for data URIs over 32kb in size:
```javascript
Modernizr.datauri // true
Modernizr.datauri.over32kb // false in IE8
```
*/
// https://github.com/Modernizr/Modernizr/issues/14
Modernizr.addAsyncTest(function() {
/* jshint -W053 */
// IE7 throw a mixed content warning on HTTPS for this test, so we'll
// just blacklist it (we know it doesn't support data URIs anyway)
// https://github.com/Modernizr/Modernizr/issues/362
if (navigator.userAgent.indexOf('MSIE 7.') !== -1) {
// Keep the test async
setTimeout(function() {
addTest('datauri', false);
}, 10);
}
var datauri = new Image();
datauri.onerror = function() {
addTest('datauri', false);
};
datauri.onload = function() {
if (datauri.width == 1 && datauri.height == 1) {
testOver32kb();
}
else {
addTest('datauri', false);
}
};
datauri.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
// Once we have datauri, let's check to see if we can use data URIs over
// 32kb (IE8 can't). https://github.com/Modernizr/Modernizr/issues/321
function testOver32kb() {
var datauriBig = new Image();
datauriBig.onerror = function() {
addTest('datauri', true);
Modernizr.datauri = new Boolean(true);
Modernizr.datauri.over32kb = false;
};
datauriBig.onload = function() {
addTest('datauri', true);
Modernizr.datauri = new Boolean(true);
Modernizr.datauri.over32kb = (datauriBig.width == 1 && datauriBig.height == 1);
};
var base64str = 'R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
while (base64str.length < 33000) {
base64str = '\r\n' + base64str;
}
datauriBig.src = 'data:image/gif;base64,' + base64str;
}
});
/*!
{
"name": "Workers from Blob URIs",
"property": "blobworkers",
"tags": ["performance", "workers"],
"builderAliases": ["workers_blobworkers"],
"notes": [{
"name": "W3C Reference",
"href": "https://www.w3.org/TR/workers/"
}],
"knownBugs": ["This test may output garbage to console."],
"authors": ["Jussi Kalliokoski"],
"async": true
}
!*/
/* DOC
Detects support for creating Web Workers from Blob URIs.
*/
Modernizr.addAsyncTest(function() {
try {
// we're avoiding using Modernizr._domPrefixes as the prefix capitalization on
// these guys are notoriously peculiar.
var BlobBuilder = window.BlobBuilder;
var URL = window.URL;
if (Modernizr._config.usePrefix) {
BlobBuilder = BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || window.OBlobBuilder;
URL = URL || window.MozURL || window.webkitURL || window.MSURL || window.OURL;
}
var data = 'Modernizr',
blob,
bb,
worker,
url,
timeout,
scriptText = 'this.onmessage=function(e){postMessage(e.data)}';
try {
blob = new Blob([scriptText], {type: 'text/javascript'});
} catch (e) {
// we'll fall back to the deprecated BlobBuilder
}
if (!blob) {
bb = new BlobBuilder();
bb.append(scriptText);
blob = bb.getBlob();
}
url = URL.createObjectURL(blob);
worker = new Worker(url);
worker.onmessage = function(e) {
addTest('blobworkers', data === e.data);
cleanup();
};
// Just in case...
worker.onerror = fail;
timeout = setTimeout(fail, 200);
worker.postMessage(data);
} catch (e) {
fail();
}
function fail() {
addTest('blobworkers', false);
cleanup();
}
function cleanup() {
if (url) {
URL.revokeObjectURL(url);
}
if (worker) {
worker.terminate();
}
if (timeout) {
clearTimeout(timeout);
}
}
});
/*!
{
"name": "Workers from Data URIs",
"property": "dataworkers",
"tags": ["performance", "workers"],
"builderAliases": ["workers_dataworkers"],
"notes": [{
"name": "W3C Reference",
"href": "https://www.w3.org/TR/workers/"
}],
"knownBugs": ["This test may output garbage to console."],
"authors": ["Jussi Kalliokoski"],
"async": true
}
!*/
/* DOC
Detects support for creating Web Workers from Data URIs.
*/
Modernizr.addAsyncTest(function() {
try {
var data = 'Modernizr',
worker = new Worker('data:text/javascript;base64,dGhpcy5vbm1lc3NhZ2U9ZnVuY3Rpb24oZSl7cG9zdE1lc3NhZ2UoZS5kYXRhKX0=');
worker.onmessage = function(e) {
worker.terminate();
addTest('dataworkers', data === e.data);
worker = null;
};
// Just in case...
worker.onerror = function() {
addTest('dataworkers', false);
worker = null;
};
setTimeout(function() {
addTest('dataworkers', false);
}, 200);
worker.postMessage(data);
} catch (e) {
setTimeout(function() {
addTest('dataworkers', false);
}, 0);
}
});
/**
* @optionName html5printshiv
* @optionProp html5printshiv
*/
// Take the html5 variable out of the html5shiv scope so we can return it.
var html5;
if (!isSVG) {
/**
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
;(function(window, document) {
/*jshint evil:true */
/** version */
var version = '3.7.3';
/** Preset options */
var options = window.html5 || {};
/** Used to skip problem elements */
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
/** Not all elements can be cloned in IE **/
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
/** Detect whether the browser supports default html5 styles */
var supportsHtml5Styles;
/** Name of the expando, to work with multiple documents or to re-shiv one document */
var expando = '_html5shiv';
/** The id for the the documents expando */
var expanID = 0;
/** Cached data for each document */
var expandoData = {};
/** Detect whether the browser supports unknown elements */
var supportsUnknownElements;
(function() {
try {
var a = document.createElement('a');
a.innerHTML = '';
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
supportsHtml5Styles = ('hidden' in a);
supportsUnknownElements = a.childNodes.length == 1 || (function() {
// assign a false positive if unable to shiv
(document.createElement)('a');
var frag = document.createDocumentFragment();
return (
typeof frag.cloneNode == 'undefined' ||
typeof frag.createDocumentFragment == 'undefined' ||
typeof frag.createElement == 'undefined'
);
}());
} catch(e) {
// assign a false positive if detection fails => unable to shiv
supportsHtml5Styles = true;
supportsUnknownElements = true;
}
}());
/*--------------------------------------------------------------------------*/
/**
* Creates a style sheet with the given CSS text and adds it to the document.
* @private
* @param {Document} ownerDocument The document.
* @param {String} cssText The CSS text.
* @returns {StyleSheet} The style element.
*/
function addStyleSheet(ownerDocument, cssText) {
var p = ownerDocument.createElement('p'),
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
p.innerHTML = 'x';
return parent.insertBefore(p.lastChild, parent.firstChild);
}
/**
* Returns the value of `html5.elements` as an array.
* @private
* @returns {Array} An array of shived element node names.
*/
function getElements() {
var elements = html5.elements;
return typeof elements == 'string' ? elements.split(' ') : elements;
}
/**
* Extends the built-in list of html5 elements
* @memberOf html5
* @param {String|Array} newElements whitespace separated list or array of new element names to shiv
* @param {Document} ownerDocument The context document.
*/
function addElements(newElements, ownerDocument) {
var elements = html5.elements;
if(typeof elements != 'string'){
elements = elements.join(' ');
}
if(typeof newElements != 'string'){
newElements = newElements.join(' ');
}
html5.elements = elements +' '+ newElements;
shivDocument(ownerDocument);
}
/**
* Returns the data associated to the given document
* @private
* @param {Document} ownerDocument The document.
* @returns {Object} An object of data.
*/
function getExpandoData(ownerDocument) {
var data = expandoData[ownerDocument[expando]];
if (!data) {
data = {};
expanID++;
ownerDocument[expando] = expanID;
expandoData[expanID] = data;
}
return data;
}
/**
* returns a shived element for the given nodeName and document
* @memberOf html5
* @param {String} nodeName name of the element
* @param {Document} ownerDocument The context document.
* @returns {Object} The shived element.
*/
function createElement(nodeName, ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createElement(nodeName);
}
if (!data) {
data = getExpandoData(ownerDocument);
}
var node;
if (data.cache[nodeName]) {
node = data.cache[nodeName].cloneNode();
} else if (saveClones.test(nodeName)) {
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
} else {
node = data.createElem(nodeName);
}
// Avoid adding some elements to fragments in IE < 9 because
// * Attributes like `name` or `type` cannot be set/changed once an element
// is inserted into a document/fragment
// * Link elements with `src` attributes that are inaccessible, as with
// a 403 response, will cause the tab/window to crash
// * Script elements appended to fragments will execute when their `src`
// or `text` property is set
return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
}
/**
* returns a shived DocumentFragment for the given document
* @memberOf html5
* @param {Document} ownerDocument The context document.
* @returns {Object} The shived DocumentFragment.
*/
function createDocumentFragment(ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createDocumentFragment();
}
data = data || getExpandoData(ownerDocument);
var clone = data.frag.cloneNode(),
i = 0,
elems = getElements(),
l = elems.length;
for(;i+~])(' + getElements().join('|') + ')(?=[[\\s,>+~#.:]|$)', 'gi'),
replacement = '$1' + shivNamespace + '\\:$2';
while (index--) {
pair = parts[index] = parts[index].split('}');
pair[pair.length - 1] = pair[pair.length - 1].replace(reElements, replacement);
parts[index] = pair.join('}');
}
return parts.join('{');
}
/**
* Removes the given wrappers, leaving the original elements.
* @private
* @params {Array} wrappers An array of printable wrappers.
*/
function removeWrappers(wrappers) {
var index = wrappers.length;
while (index--) {
wrappers[index].removeNode();
}
}
/*--------------------------------------------------------------------------*/
/**
* Shivs the given document for print.
* @memberOf html5
* @param {Document} ownerDocument The document to shiv.
* @returns {Document} The shived document.
*/
function shivPrint(ownerDocument) {
var shivedSheet,
wrappers,
data = getExpandoData(ownerDocument),
namespaces = ownerDocument.namespaces,
ownerWindow = ownerDocument.parentWindow;
if (!supportsShivableSheets || ownerDocument.printShived) {
return ownerDocument;
}
if (typeof namespaces[shivNamespace] == 'undefined') {
namespaces.add(shivNamespace);
}
function removeSheet() {
clearTimeout(data._removeSheetTimer);
if (shivedSheet) {
shivedSheet.removeNode(true);
}
shivedSheet= null;
}
ownerWindow.attachEvent('onbeforeprint', function() {
removeSheet();
var imports,
length,
sheet,
collection = ownerDocument.styleSheets,
cssText = [],
index = collection.length,
sheets = Array(index);
// convert styleSheets collection to an array
while (index--) {
sheets[index] = collection[index];
}
// concat all style sheet CSS text
while ((sheet = sheets.pop())) {
// IE does not enforce a same origin policy for external style sheets...
// but has trouble with some dynamically created stylesheets
if (!sheet.disabled && reMedia.test(sheet.media)) {
try {
imports = sheet.imports;
length = imports.length;
} catch(er){
length = 0;
}
for (index = 0; index < length; index++) {
sheets.push(imports[index]);
}
try {
cssText.push(sheet.cssText);
} catch(er){}
}
}
// wrap all HTML5 elements with printable elements and add the shived style sheet
cssText = shivCssText(cssText.reverse().join(''));
wrappers = addWrappers(ownerDocument);
shivedSheet = addStyleSheet(ownerDocument, cssText);
});
ownerWindow.attachEvent('onafterprint', function() {
// remove wrappers, leaving the original elements, and remove the shived style sheet
removeWrappers(wrappers);
clearTimeout(data._removeSheetTimer);
data._removeSheetTimer = setTimeout(removeSheet, 500);
});
ownerDocument.printShived = true;
return ownerDocument;
}
/*--------------------------------------------------------------------------*/
// expose API
html5.type += ' print';
html5.shivPrint = shivPrint;
// shiv for print
shivPrint(document);
if(typeof module == 'object' && module.exports){
module.exports = html5;
}
}(typeof window !== "undefined" ? window : this, document));
}
;
/**
* Modernizr.hasEvent() detects support for a given event
*
* @memberof Modernizr
* @name Modernizr.hasEvent
* @optionName Modernizr.hasEvent()
* @optionProp hasEvent
* @access public
* @function hasEvent
* @param {string|*} eventName - the name of an event to test for (e.g. "resize")
* @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
* @returns {boolean}
* @example
* `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
* By default, it does this detection on a div element
*
* ```js
* hasEvent('blur') // true;
* ```
*
* However, you are able to give an object as a second argument to hasEvent to
* detect an event on something other than a div.
*
* ```js
* hasEvent('devicelight', window) // true;
* ```
*
*/
var hasEvent = (function() {
// Detect whether event support can be detected via `in`. Test on a DOM element
// using the "blur" event b/c it should always exist. bit.ly/event-detection
var needsFallback = !('onblur' in document.documentElement);
function inner(eventName, element) {
var isSupported;
if (!eventName) { return false; }
if (!element || typeof element === 'string') {
element = createElement(element || 'div');
}
// Testing via the `in` operator is sufficient for modern browsers and IE.
// When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
// "resize", whereas `in` "catches" those.
eventName = 'on' + eventName;
isSupported = eventName in element;
// Fallback technique for old Firefox - bit.ly/event-detection
if (!isSupported && needsFallback) {
if (!element.setAttribute) {
// Switch to generic element if it lacks `setAttribute`.
// It could be the `document`, `window`, or something else.
element = createElement('div');
}
element.setAttribute(eventName, '');
isSupported = typeof element[eventName] === 'function';
if (element[eventName] !== undefined) {
// If property was created, "remove it" by setting value to `undefined`.
element[eventName] = undefined;
}
element.removeAttribute(eventName);
}
return isSupported;
}
return inner;
})();
ModernizrProto.hasEvent = hasEvent;
/*!
{
"name": "Ambient Light Events",
"property": "ambientlight",
"notes": [{
"name": "W3C Ambient Light Events",
"href": "https://www.w3.org/TR/ambient-light/"
}]
}
!*/
/* DOC
Detects support for the API that provides information about the ambient light levels, as detected by the device's light detector, in terms of lux units.
*/
Modernizr.addTest('ambientlight', hasEvent('devicelight', window));
/*!
{
"name": "Hashchange event",
"property": "hashchange",
"caniuse": "hashchange",
"tags": ["history"],
"notes": [{
"name": "MDN documentation",
"href": "https://developer.mozilla.org/en-US/docs/Web/API/window.onhashchange"
}],
"polyfills": [
"jquery-hashchange",
"moo-historymanager",
"jquery-ajaxy",
"hasher",
"shistory"
]
}
!*/
/* DOC
Detects support for the `hashchange` event, fired when the current location fragment changes.
*/
Modernizr.addTest('hashchange', function() {
if (hasEvent('hashchange', window) === false) {
return false;
}
// documentMode logic from YUI to filter out IE8 Compat Mode
// which false positives.
return (document.documentMode === undefined || document.documentMode > 7);
});
/*!
{
"name": "input[search] search event",
"property": "search",
"tags": ["input","search"],
"authors": ["Calvin Webster"],
"notes": [{
"name": "Wufoo demo",
"href": "https://www.wufoo.com/html5/types/5-search.html?"
}, {
"name": "CSS Tricks",
"href": "https://css-tricks.com/webkit-html5-search-inputs/"
}]
}
!*/
/* DOC
There is a custom `search` event implemented in webkit browsers when using an `input[search]` element.
*/
Modernizr.addTest('inputsearchevent', hasEvent('search'));
/*!
{
"name": "DOM Pointer Events API",
"property": "pointerevents",
"tags": ["input"],
"authors": ["Stu Cox"],
"notes": [
{
"name": "W3C spec",
"href": "https://www.w3.org/TR/pointerevents/"
}
],
"warnings": ["This property name now refers to W3C DOM PointerEvents: https://github.com/Modernizr/Modernizr/issues/548#issuecomment-12812099"],
"polyfills": ["handjs"]
}
!*/
/* DOC
Detects support for the DOM Pointer Events API, which provides a unified event interface for pointing input devices, as implemented in IE10+.
*/
// **Test name hijacked!**
// Now refers to W3C DOM PointerEvents spec rather than the CSS pointer-events property.
Modernizr.addTest('pointerevents', function() {
// Cannot use `.prefixed()` for events, so test each prefix
var bool = false,
i = domPrefixes.length;
// Don't forget un-prefixed...
bool = Modernizr.hasEvent('pointerdown');
while (i-- && !bool) {
if (hasEvent(domPrefixes[i] + 'pointerdown')) {
bool = true;
}
}
return bool;
});
/**
* prefixedCSSValue is a way test for prefixed css properties (e.g. display: -webkit-flex)
*
* @memberof Modernizr
* @name Modernizr.prefixedCSSValue
* @optionName Modernizr.prefixedCSSValue()
* @optionProp prefixedCSSValue
* @access public
* @function prefixedCSSValue
* @param {string} prop - String name of the property to test for
* @param {string} value - String value of the non prefixed version of the value you want to test for
* @returns {string|false} The string representing the (possibly prefixed)
* valid version of the property, or `false` when it is unsupported.
* @example
*
* `Modernizr.prefixedCSSValue` is a way test for prefixed css properties (e.g. display: -webkit-flex)
*
* ```js
* Modernizr.prefixedCSSValue('background', 'linear-gradient(left, red, red)')
* ```
*
*/
var prefixedCSSValue = function(prop, value) {
var result = false;
var elem = createElement('div');
var style = elem.style;
if (prop in style) {
var i = domPrefixes.length;
style[prop] = value;
result = style[prop];
while (i-- && !result) {
style[prop] = '-' + domPrefixes[i] + '-' + value;
result = style[prop];
}
}
if (result === '') {
result = false;
}
return result;
};
ModernizrProto.prefixedCSSValue = prefixedCSSValue;
/*!
{
"name" : "HTML5 Audio Element",
"property": "audio",
"tags" : ["html5", "audio", "media"]
}
!*/
/* DOC
Detects the audio element
*/
// This tests evaluates support of the audio element, as well as
// testing what types of content it supports.
//
// We're using the Boolean constructor here, so that we can extend the value
// e.g. Modernizr.audio // true
// Modernizr.audio.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('audio', function() {
/* jshint -W053 */
var elem = createElement('audio');
var bool = false;
try {
if (bool = !!elem.canPlayType) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"') .replace(/^no$/, '');
bool.mp3 = elem.canPlayType('audio/mpeg; codecs="mp3"') .replace(/^no$/, '');
bool.opus = elem.canPlayType('audio/ogg; codecs="opus"') ||
elem.canPlayType('audio/webm; codecs="opus"') .replace(/^no$/, '');
// Mimetypes accepted:
// developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
// bit.ly/iphoneoscodecs
bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/, '');
bool.m4a = (elem.canPlayType('audio/x-m4a;') ||
elem.canPlayType('audio/aac;')) .replace(/^no$/, '');
}
} catch (e) { }
return bool;
});
/*!
{
"name": "Canvas",
"property": "canvas",
"caniuse": "canvas",
"tags": ["canvas", "graphics"],
"polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
}
!*/
/* DOC
Detects support for the `