mkdocs-material/material/assets/javascripts/modernizr.js
2016-02-09 12:58:55 +01:00

2208 lines
71 KiB
JavaScript

/*!
* modernizr v3.3.0
* Build http://modernizr.com/download?-checked-contains-csstransforms3d-fontface-json-search-svg-target-addtest-fnbind-printshiv-setclasses-testprop-dontmin
*
* Copyright (c)
* Faruk Ates
* Paul Irish
* Alex Sexton
* Ryan Seddon
* Patrick Kettner
* Stu Cox
* Richard Herrera
* MIT License
*/
/*
* Modernizr tests which native CSS3 and HTML5 features are available in the
* current UA and makes the results available to you in two ways: as properties on
* a global `Modernizr` object, and as classes on the `<html>` element. This
* information allows you to progressively enhance your pages with a granular level
* of control over the experience.
*/
;(function(window, document, undefined){
var tests = [];
/**
*
* ModernizrProto is the constructor for Modernizr
*
* @class
* @access public
*/
var ModernizrProto = {
// The current version, dummy
_version: '3.3.0',
// Any settings that don't work as separate modules
// can go in here as configuration.
_config: {
'classPrefix': '',
'enableClasses': true,
'enableJSClass': true,
'usePrefixes': true
},
// Queue of tests
_q: [],
// Stub these for people who are listening
on: function(test, cb) {
// I don't really think people should do this, but we can
// safe guard it a bit.
// -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
// This is in case people listen to synchronous tests. I would leave it out,
// but the code to *disallow* sync tests in the real version of this
// function is actually larger than this.
var self = this;
setTimeout(function() {
cb(self[test]);
}, 0);
},
addTest: function(name, fn, options) {
tests.push({name: name, fn: fn, options: options});
},
addAsyncTest: function(fn) {
tests.push({name: null, fn: fn});
}
};
// Fake some of Object.create so we can force non test results to be non "own" properties.
var Modernizr = function() {};
Modernizr.prototype = ModernizrProto;
// Leak modernizr globally when you `require` it rather than force it here.
// Overwrite name so constructor name is nicer :D
Modernizr = new Modernizr();
var classes = [];
/**
* is returns a boolean if the typeof an obj is exactly type.
*
* @access private
* @function is
* @param {*} obj - A thing we want to check the type of
* @param {string} type - A string to compare the typeof against
* @returns {boolean}
*/
function is(obj, type) {
return typeof obj === type;
}
;
/**
* Run through all tests and detect their support in the current UA.
*
* @access private
*/
function testRunner() {
var featureNames;
var feature;
var aliasIdx;
var result;
var nameIdx;
var featureName;
var featureNameSplit;
for (var featureIdx in tests) {
if (tests.hasOwnProperty(featureIdx)) {
featureNames = [];
feature = tests[featureIdx];
// run the test, throw the return value into the Modernizr,
// then based on that boolean, define an appropriate className
// and push it into an array of classes we'll join later.
//
// If there is no name, it's an 'async' test that is run,
// but not directly added to the object. That should
// be done with a post-run addTest call.
if (feature.name) {
featureNames.push(feature.name.toLowerCase());
if (feature.options && feature.options.aliases && feature.options.aliases.length) {
// Add all the aliases into the names list
for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
}
}
}
// Run the test, or use the raw value if it's not a function
result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
// Set each of the names on the Modernizr object
for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
featureName = featureNames[nameIdx];
// Support dot properties as sub tests. We don't do checking to make sure
// that the implied parent tests have been added. You must call them in
// order (either in the test, or make the parent test a dependency).
//
// Cap it to TWO to make the logic simple and because who needs that kind of subtesting
// hashtag famous last words
featureNameSplit = featureName.split('.');
if (featureNameSplit.length === 1) {
Modernizr[featureNameSplit[0]] = result;
} else {
// cast to a Boolean, if not one already
/* jshint -W053 */
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;
/**
* 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);
isSVG ? docElement.className.baseVal = className : docElement.className = className;
}
}
;
/**
* hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
*
* @author kangax
* @access private
* @function hasOwnProp
* @param {object} object - The object to check for a property
* @param {string} property - The property to check for
* @returns {boolean}
*/
// hasOwnProperty shim by kangax needed for Safari 2.0 support
var hasOwnProp;
(function() {
var _hasOwnProperty = ({}).hasOwnProperty;
/* istanbul ignore else */
/* we have no way of testing IE 5.5 or safari 2,
* so just assume the else gets hit */
if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
hasOwnProp = function(object, property) {
return _hasOwnProperty.call(object, property);
};
}
else {
hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
};
}
})();
// _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;
});
/**
* 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);
};
}
;
/**
* @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 = '<xyz></xyz>';
//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<style>' + cssText + '</style>';
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<l;i++){
clone.createElement(elems[i]);
}
return clone;
}
/**
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
* @private
* @param {Document|DocumentFragment} ownerDocument The document.
* @param {Object} data of the document.
*/
function shivMethods(ownerDocument, data) {
if (!data.cache) {
data.cache = {};
data.createElem = ownerDocument.createElement;
data.createFrag = ownerDocument.createDocumentFragment;
data.frag = data.createFrag();
}
ownerDocument.createElement = function(nodeName) {
//abort shiv
if (!html5.shivMethods) {
return data.createElem(nodeName);
}
return createElement(nodeName, ownerDocument, data);
};
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
'var n=f.cloneNode(),c=n.createElement;' +
'h.shivMethods&&(' +
// unroll the `createElement` calls
getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
data.createElem(nodeName);
data.frag.createElement(nodeName);
return 'c("' + nodeName + '")';
}) +
');return n}'
)(html5, data.frag);
}
/*--------------------------------------------------------------------------*/
/**
* Shivs the given document.
* @memberOf html5
* @param {Document} ownerDocument The document to shiv.
* @returns {Document} The shived document.
*/
function shivDocument(ownerDocument) {
if (!ownerDocument) {
ownerDocument = document;
}
var data = getExpandoData(ownerDocument);
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
data.hasCSS = !!addStyleSheet(ownerDocument,
// corrects block display not defined in IE6/7/8/9
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
// adds styling not present in IE6/7/8/9
'mark{background:#FF0;color:#000}' +
// hides non-rendered elements
'template{display:none}'
);
}
if (!supportsUnknownElements) {
shivMethods(ownerDocument, data);
}
return ownerDocument;
}
/*--------------------------------------------------------------------------*/
/**
* The `html5` object is exposed so that more elements can be shived and
* existing shiving can be detected on iframes.
* @type Object
* @example
*
* // options can be changed before the script is included
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
*/
var html5 = {
/**
* An array or space separated string of node names of the elements to shiv.
* @memberOf html5
* @type Array|String
*/
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
/**
* current version of html5shiv
*/
'version': version,
/**
* A flag to indicate that the HTML5 style sheet should be inserted.
* @memberOf html5
* @type Boolean
*/
'shivCSS': (options.shivCSS !== false),
/**
* Is equal to true if a browser supports creating unknown/HTML5 elements
* @memberOf html5
* @type boolean
*/
'supportsUnknownElements': supportsUnknownElements,
/**
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
* methods should be overwritten.
* @memberOf html5
* @type Boolean
*/
'shivMethods': (options.shivMethods !== false),
/**
* A string to describe the type of `html5` object ("default" or "default print").
* @memberOf html5
* @type String
*/
'type': 'default',
// shivs the document according to the specified `html5` object options
'shivDocument': shivDocument,
//creates a shived element
createElement: createElement,
//creates a shived documentFragment
createDocumentFragment: createDocumentFragment,
//extends list of elements
addElements: addElements
};
/*--------------------------------------------------------------------------*/
// expose html5
window.html5 = html5;
// shiv the document
shivDocument(document);
/*------------------------------- Print Shiv -------------------------------*/
/** Used to filter media types */
var reMedia = /^$|\b(?:all|print)\b/;
/** Used to namespace printable elements */
var shivNamespace = 'html5shiv';
/** Detect whether the browser supports shivable style sheets */
var supportsShivableSheets = !supportsUnknownElements && (function() {
// assign a false negative if unable to shiv
var docEl = document.documentElement;
return !(
typeof document.namespaces == 'undefined' ||
typeof document.parentWindow == 'undefined' ||
typeof docEl.applyElement == 'undefined' ||
typeof docEl.removeNode == 'undefined' ||
typeof window.attachEvent == 'undefined'
);
}());
/*--------------------------------------------------------------------------*/
/**
* Wraps all HTML5 elements in the given document with printable elements.
* (eg. the "header" element is wrapped with the "html5shiv:header" element)
* @private
* @param {Document} ownerDocument The document.
* @returns {Array} An array wrappers added.
*/
function addWrappers(ownerDocument) {
var node,
nodes = ownerDocument.getElementsByTagName('*'),
index = nodes.length,
reElements = RegExp('^(?:' + getElements().join('|') + ')$', 'i'),
result = [];
while (index--) {
node = nodes[index];
if (reElements.test(node.nodeName)) {
result.push(node.applyElement(createWrapper(node)));
}
}
return result;
}
/**
* Creates a printable wrapper for the given element.
* @private
* @param {Element} element The element.
* @returns {Element} The wrapper.
*/
function createWrapper(element) {
var node,
nodes = element.attributes,
index = nodes.length,
wrapper = element.ownerDocument.createElement(shivNamespace + ':' + element.nodeName);
// copy element attributes to the wrapper
while (index--) {
node = nodes[index];
node.specified && wrapper.setAttribute(node.nodeName, node.nodeValue);
}
// copy element styles to the wrapper
wrapper.style.cssText = element.style.cssText;
return wrapper;
}
/**
* Shivs the given CSS text.
* (eg. header{} becomes html5shiv\:header{})
* @private
* @param {String} cssText The CSS text to shiv.
* @returns {String} The shived CSS text.
*/
function shivCssText(cssText) {
var pair,
parts = cssText.split('{'),
index = parts.length,
reElements = RegExp('(^|[\\s,>+~])(' + 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));
}
;
/**
* 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);
}
;
/**
* createElement is a convenience wrapper around document.createElement. Since we
* use createElement all over the place, this allows for (slightly) smaller code
* as well as abstracting away issues with creating elements in contexts other than
* HTML documents (e.g. SVG documents).
*
* @access private
* @function createElement
* @returns {HTMLElement|SVGElement} An HTML or SVG element
*/
function createElement() {
if (typeof document.createElement !== 'function') {
// This is the case in IE7, where the type of createElement is "object".
// For this reason, we cannot call apply() as Object is not a Function.
return document.createElement(arguments[0]);
} else if (isSVG) {
return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
} else {
return document.createElement.apply(document, arguments);
}
}
;
/**
* Create our "modernizr" element that we do most feature tests on.
*
* @access private
*/
var modElem = {
elem: createElement('modernizr')
};
// Clean up this element
Modernizr._q.push(function() {
delete modElem.elem;
});
var mStyle = {
style: modElem.elem.style
};
// kill ref for gc, must happen before mod.elem is removed, so we unshift on to
// the front of the queue.
Modernizr._q.unshift(function() {
delete mStyle.style;
});
/**
* getBody returns the body of a document, or an element that can stand in for
* the body if a real body does not exist
*
* @access private
* @function getBody
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
* artificially created element that stands in for the body
*/
function getBody() {
// After page load injecting a fake body doesn't work so check if body exists
var body = document.body;
if (!body) {
// Can't use the real body create a fake one.
body = createElement(isSVG ? 'svg' : 'body');
body.fake = true;
}
return body;
}
;
/**
* injectElementWithStyles injects an element with style element and some CSS rules
*
* @access private
* @function injectElementWithStyles
* @param {string} rule - String representing a css rule
* @param {function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
* @returns {boolean}
*/
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+
docElement.offsetHeight;
} else {
div.parentNode.removeChild(div);
}
return !!ret;
}
;
/**
* 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-');
}
;
/**
* 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 getComputedStyle(node, null).position == 'absolute';
});
}
return undefined;
}
;
/**
* 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(/^-/, '');
}
;
// 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.
var elems = ['modernizr', 'tspan'];
while (!mStyle.style) {
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;
}
;
/**
* testProp() investigates whether a given style property is recognized
* Property names can be provided in either camelCase or kebab-case.
*
* @memberof Modernizr
* @name Modernizr.testProp
* @access public
* @optionName Modernizr.testProp()
* @optionProp testProp
* @function testProp
* @param {string} prop - Name of the CSS property to check
* @param {string} [value] - Name of the CSS value to check
* @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
* @returns {boolean}
* @example
*
* Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
* version of the string.
*
* Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
*
* ```js
* Modernizr.testProp('pointerEvents') // true
* ```
*
* You can also provide a value as an optional second argument to check if a
* specific value is supported
*
* ```js
* Modernizr.testProp('pointerEvents', 'none') // true
* Modernizr.testProp('pointerEvents', 'penguin') // false
* ```
*/
var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
return testProps([prop], undefined, value, useValue);
};
/**
* 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": "input[search] search event",
"property": "search",
"tags": ["input","search"],
"authors": ["Calvin Webster"],
"notes": [{
"name": "Wufoo demo",
"href": "http://www.wufoo.com/html5/types/5-search.html?"
}, {
"name": "CSS Tricks",
"href": "http://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": "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);
/**
* testStyles injects an element with style element and some CSS rules
*
* @memberof Modernizr
* @name Modernizr.testStyles
* @optionName Modernizr.testStyles()
* @optionProp testStyles
* @access public
* @function testStyles
* @param {string} rule - String representing a css rule
* @param {function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
* @returns {boolean}
* @example
*
* `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
* along with (possibly multiple) DOM elements. This lets you check for features
* that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
*
* ```js
* Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
* // elem is the first DOM node in the page (by default #modernizr)
* // rule is the first argument you supplied - the CSS rule in string form
*
* addTest('widthworks', elem.style.width === '9px')
* });
* ```
*
* If your test requires multiple nodes, you can include a third argument
* indicating how many additional div elements to include on the page. The
* additional nodes are injected as children of the `elem` that is returned as
* the first argument to the callback.
*
* ```js
* Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
* document.getElementById('modernizr').style.width === '1px'; // true
* document.getElementById('modernizr2').style.width === '2px'; // true
* elem.firstChild === document.getElementById('modernizr2'); // true
* }, 1);
* ```
*
* By default, all of the additional elements have an ID of `modernizr[n]`, where
* `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
* the second additional is `#modernizr3`, etc.).
* If you want to have more meaningful IDs for your function, you can provide
* them as the fourth argument, as an array of strings
*
* ```js
* Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
* elem.firstChild === document.getElementById('foo'); // true
* elem.lastChild === document.getElementById('bar'); // true
* }, 2, ['foo', 'bar']);
* ```
*
*/
var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
/*!
{
"name": "@font-face",
"property": "fontface",
"authors": ["Diego Perini", "Mat Marquis"],
"tags": ["css"],
"knownBugs": [
"False Positive: WebOS http://github.com/Modernizr/Modernizr/issues/342",
"False Postive: WP7 http://github.com/Modernizr/Modernizr/issues/538"
],
"notes": [{
"name": "@font-face detection routine by Diego Perini",
"href": "http://javascript.nwbox.com/CSSSupport/"
},{
"name": "Filament Group @font-face compatibility research",
"href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
},{
"name": "Filament Grunticon/@font-face device testing results",
"href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
},{
"name": "CSS fonts on Android",
"href": "http://stackoverflow.com/questions/3200069/css-fonts-on-android"
},{
"name": "@font-face and Android",
"href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
}]
}
!*/
var blacklist = (function() {
var ua = navigator.userAgent;
var wkvers = ua.match(/applewebkit\/([0-9]+)/gi) && parseFloat(RegExp.$1);
var webos = ua.match(/w(eb)?osbrowser/gi);
var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
var oldandroid = wkvers < 533 && ua.match(/android/gi);
return webos || oldandroid || wppre8;
}());
if (blacklist) {
Modernizr.addTest('fontface', false);
} else {
testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
var style = document.getElementById('smodernizr');
var sheet = style.sheet || style.styleSheet;
var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
Modernizr.addTest('fontface', bool);
});
}
;
/**
* If the browsers follow the spec, then they would expose vendor-specific style as:
* elem.style.WebkitBorderRadius
* instead of something like the following, which would be 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;
/**
* 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;
/**
* 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
*/
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;
}
;
/**
* 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
*/
function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
// did they call .prefixed('boxSizing') or are we just testing a prop?
if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
return testProps(props, prefixed, value, skipValueTest);
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed, elem);
}
}
// Modernizr.testAllProps() investigates whether a given style property,
// or any of its vendor-prefixed variants, is recognized
//
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testAllProps('boxSizing')
ModernizrProto.testAllProps = testPropsAll;
/**
* testAllProps determines whether a given CSS property is supported in the browser
*
* @memberof Modernizr
* @name Modernizr.testAllProps
* @optionName Modernizr.testAllProps()
* @optionProp testAllProps
* @access public
* @function testAllProps
* @param {string} prop - String naming the property to test (either camelCase or 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 Supports",
"property": "supports",
"caniuse": "css-featurequeries",
"tags": ["css"],
"builderAliases": ["css_supports"],
"notes": [{
"name": "W3 Spec",
"href": "http://dev.w3.org/csswg/css3-conditional/#at-supports"
},{
"name": "Related Github Issue",
"href": "github.com/Modernizr/Modernizr/issues/648"
},{
"name": "W3 Info",
"href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
}]
}
!*/
var newSyntax = 'CSS' in window && 'supports' in window.CSS;
var oldSyntax = 'supportsCSS' in window;
Modernizr.addTest('supports', newSyntax || oldSyntax);
/*!
{
"name": "CSS Transforms 3D",
"property": "csstransforms3d",
"caniuse": "transforms3d",
"tags": ["css"],
"warnings": [
"Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004"
]
}
!*/
Modernizr.addTest('csstransforms3d', function() {
var ret = !!testAllProps('perspective', '1px', true);
var usePrefix = Modernizr._config.usePrefixes;
// Webkit's 3D transforms are passed off to the browser's own graphics renderer.
// It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
// some conditions. As a result, Webkit typically recognizes the syntax but
// will sometimes throw a false positive, thus we must do a more thorough check:
if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) {
var mq;
var defaultStyle = '#modernizr{width:0;height:0}';
// Use CSS Conditional Rules if available
if (Modernizr.supports) {
mq = '@supports (perspective: 1px)';
} else {
// Otherwise, Webkit allows this media query to succeed only if the feature is enabled.
// `@media (transform-3d),(-webkit-transform-3d){ ... }`
mq = '@media (transform-3d)';
if (usePrefix) {
mq += ',(-webkit-transform-3d)';
}
}
mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}';
testStyles(defaultStyle + mq, function(elem) {
ret = elem.offsetWidth === 7 && elem.offsetHeight === 18;
});
}
return ret;
});
/*!
{
"name": "JSON",
"property": "json",
"caniuse": "json",
"notes": [{
"name": "MDN documentation",
"href": "http://developer.mozilla.org/en/JSON"
}],
"polyfills": ["json2"]
}
!*/
/* DOC
Detects native support for JSON handling functions.
*/
// this will also succeed if you've loaded the JSON2.js polyfill ahead of time
// ... but that should be obvious. :)
Modernizr.addTest('json', 'JSON' in window && 'parse' in JSON && 'stringify' in JSON);
/*!
{
"name": "CSS :checked pseudo-selector",
"caniuse": "css-sel3",
"property": "checked",
"tags": ["css"],
"notes": [{
"name": "Related Github Issue",
"href": "https://github.com/Modernizr/Modernizr/pull/879"
}]
}
!*/
Modernizr.addTest('checked', function() {
return testStyles('#modernizr {position:absolute} #modernizr input {margin-left:10px} #modernizr :checked {margin-left:20px;display:block}', function(elem) {
var cb = createElement('input');
cb.setAttribute('type', 'checkbox');
cb.setAttribute('checked', 'checked');
elem.appendChild(cb);
return cb.offsetLeft === 20;
});
});
/*!
{
"name": "CSS :target pseudo-class",
"caniuse": "css-sel3",
"property": "target",
"tags": ["css"],
"notes": [{
"name": "MDN documentation",
"href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:target"
}],
"authors": ["@zachleat"],
"warnings": ["Opera Mini supports :target but doesn't update the hash for anchor links."]
}
!*/
/* DOC
Detects support for the ':target' CSS pseudo-class.
*/
// querySelector
Modernizr.addTest('target', function() {
var doc = window.document;
if (!('querySelectorAll' in doc)) {
return false;
}
try {
doc.querySelectorAll(':target');
return true;
} catch (e) {
return false;
}
});
/*!
{
"name": "ES5 String.prototype.contains",
"property": "contains",
"authors": ["Robert Kowalski"],
"tags": ["es6"]
}
!*/
/* DOC
Check if browser implements ECMAScript 6 `String.prototype.contains` per specification.
*/
Modernizr.addTest('contains', is(String.prototype.contains, 'function'));
// 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);
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
(function(w) {
"use strict";
w.matchMedia = w.matchMedia || function(doc, undefined) {
var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
div.id = "mq-test-1";
div.style.cssText = "position:absolute;top:-100em";
fakeBody.style.background = "none";
fakeBody.appendChild(div);
return function(q) {
div.innerHTML = '&shy;<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
docElem.insertBefore(fakeBody, refNode);
bool = div.offsetWidth === 42;
docElem.removeChild(fakeBody);
return {
matches: bool,
media: q
};
};
}(w.document);
})(this);
/*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */
(function(w) {
"use strict";
var respond = {};
w.respond = respond;
respond.update = function() {};
var requestQueue = [], xmlHttp = function() {
var xmlhttpmethod = false;
try {
xmlhttpmethod = new w.XMLHttpRequest();
} catch (e) {
xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
}
return function() {
return xmlhttpmethod;
};
}(), ajax = function(url, callback) {
var req = xmlHttp();
if (!req) {
return;
}
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
return;
}
callback(req.responseText);
};
if (req.readyState === 4) {
return;
}
req.send(null);
};
respond.ajax = ajax;
respond.queue = requestQueue;
respond.regex = {
media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
only: /(only\s+)?([a-zA-Z]+)\s?/,
minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,
maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/
};
respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
if (respond.mediaQueriesSupported) {
return;
}
var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
div.style.cssText = "position:absolute;font-size:1em;width:1em";
if (!body) {
body = fakeUsed = doc.createElement("body");
body.style.background = "none";
}
docElem.style.fontSize = "100%";
body.style.fontSize = "100%";
body.appendChild(div);
if (fakeUsed) {
docElem.insertBefore(body, docElem.firstChild);
}
ret = div.offsetWidth;
if (fakeUsed) {
docElem.removeChild(body);
} else {
body.removeChild(div);
}
docElem.style.fontSize = originalHTMLFontSize;
if (originalBodyFontSize) {
body.style.fontSize = originalBodyFontSize;
}
ret = eminpx = parseFloat(ret);
return ret;
}, applyMedia = function(fromResize) {
var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
w.clearTimeout(resizeDefer);
resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
return;
} else {
lastCall = now;
}
for (var i in mediastyles) {
if (mediastyles.hasOwnProperty(i)) {
var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
if (!!min) {
min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
}
if (!!max) {
max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
}
if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
if (!styleBlocks[thisstyle.media]) {
styleBlocks[thisstyle.media] = [];
}
styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
for (var j in appendedEls) {
if (appendedEls.hasOwnProperty(j)) {
if (appendedEls[j] && appendedEls[j].parentNode === head) {
head.removeChild(appendedEls[j]);
}
}
}
appendedEls.length = 0;
for (var k in styleBlocks) {
if (styleBlocks.hasOwnProperty(k)) {
var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
ss.type = "text/css";
ss.media = k;
head.insertBefore(ss, lastLink.nextSibling);
if (ss.styleSheet) {
ss.styleSheet.cssText = css;
} else {
ss.appendChild(doc.createTextNode(css));
}
appendedEls.push(ss);
}
}
}, translate = function(styles, href, media) {
var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
href = href.substring(0, href.lastIndexOf("/"));
var repUrls = function(css) {
return css.replace(respond.regex.urls, "$1" + href + "$2$3");
}, useMedia = !ql && media;
if (href.length) {
href += "/";
}
if (useMedia) {
ql = 1;
}
for (var i = 0; i < ql; i++) {
var fullq, thisq, eachq, eql;
if (useMedia) {
fullq = media;
rules.push(repUrls(styles));
} else {
fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
rules.push(RegExp.$2 && repUrls(RegExp.$2));
}
eachq = fullq.split(",");
eql = eachq.length;
for (var j = 0; j < eql; j++) {
thisq = eachq[j];
mediastyles.push({
media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
rules: rules.length - 1,
hasquery: thisq.indexOf("(") > -1,
minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
});
}
}
applyMedia();
}, makeRequests = function() {
if (requestQueue.length) {
var thisRequest = requestQueue.shift();
ajax(thisRequest.href, function(styles) {
translate(styles, thisRequest.href, thisRequest.media);
parsedSheets[thisRequest.href] = true;
w.setTimeout(function() {
makeRequests();
}, 0);
});
}
}, ripCSS = function() {
for (var i = 0; i < links.length; i++) {
var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
if (!!href && isCSS && !parsedSheets[href]) {
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
translate(sheet.styleSheet.rawCssText, href, media);
parsedSheets[href] = true;
} else {
if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
if (href.substring(0, 2) === "//") {
href = w.location.protocol + href;
}
requestQueue.push({
href: href,
media: media
});
}
}
}
}
makeRequests();
};
ripCSS();
respond.update = ripCSS;
respond.getEmValue = getEmValue;
function callMedia() {
applyMedia(true);
}
if (w.addEventListener) {
w.addEventListener("resize", callMedia, false);
} else if (w.attachEvent) {
w.attachEvent("onresize", callMedia);
}
})(this);