/*!
* modernizr v3.0.0pre
* modernizr.com
*
* Copyright (c) Faruk Ates, Paul Irish, Alex Sexton, Ryan Seddon, Alexander Farkas, Ben Alman, Stu Cox
* 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.
*
* Modernizr has an optional (*not included*) conditional resource loader called
* `Modernizr.load()`, based on [Yepnope.js](http://yepnopejs.com). You can get a
* build that includes `Modernizr.load()`, as well as choosing which feature tests
* to include on the [Download page](http://www.modernizr.com/download/).
*/
;(function(window, document, undefined){
var tests = [];
var ModernizrProto = {
// The current version, dummy
_version: 'v3.0.0pre',
// Any settings that don't work as separate modules
// can go in here as configuration.
_config: {
classPrefix : '',
enableClasses : 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.
setTimeout(function() {
cb(this[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 for if typeof obj is exactly type.
*/
function is( obj, type ) {
return typeof obj === type;
}
;
// Run through all tests and detect their support in the current UA.
function testRunner() {
var featureNames;
var feature;
var aliasIdx;
var result;
var nameIdx;
var featureName;
var featureNameSplit;
for ( var featureIdx in tests ) {
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 if (featureNameSplit.length === 2) {
Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
}
classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
}
}
}
;
var docElement = document.documentElement;
// 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 || '';
// Change `no-js` to `js` (we do this regardles of the `enableClasses`
// option)
// Handle classPrefix on this too
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);
docElement.className = className;
}
}
;
// hasOwnProperty shim by kangax needed for Safari 2.0 support
var hasOwnProp;
(function() {
var _hasOwnProperty = ({}).hasOwnProperty;
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'));
};
}
})();
// As far as I can think of, we shouldn't need or
// allow 'on' for non-async tests, and you can't do
// async tests without this 'addTest' module.
// Listeners for async or post-run tests
ModernizrProto._l = {};
// 'addTest' implies a test after the core runloop,
// So we'll add in the events
ModernizrProto.on = function( test, cb ) {
// Create the list of listeners if it doesn't exist
if (!this._l[test]) {
this._l[test] = [];
}
// Push this test on to the listener list
this._l[test].push(cb);
// If it's already been resolved, trigger it on next tick
if (Modernizr.hasOwnProperty(test)) {
// Next Tick
setTimeout(function() {
Modernizr._trigger(test, Modernizr[test]);
}, 0);
}
};
ModernizrProto._trigger = function( test, res ) {
if (!this._l[test]) {
return;
}
var cbs = this._l[test];
// 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[test];
};
/**
* addTest allows the user to define their own feature tests
* the result will be added onto the Modernizr object,
* as well as an appropriate className set on the html element
*
* @param feature - String naming the feature
* @param test - Function returning true if feature is supported, false if not
*/
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 featureSplit = feature.split('.');
var last = Modernizr[featureSplit[0]];
// Again, we don't check for parent test existence. Get that right, though.
if (featureSplit.length == 2) {
last = last[featureSplit[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 (featureSplit.length == 1) {
Modernizr[featureSplit[0]] = test;
}
else if (featureSplit.length == 2) {
Modernizr[featureSplit[0]][featureSplit[1]] = test;
}
// Set a single class (either `feature` or `no-feature`)
setClasses([(test ? '' : 'no-') + featureSplit.join('-')]);
// Trigger the event
Modernizr._trigger(feature, test);
}
return Modernizr; // allow chaining.
}
// After all the tests are run, add self
// to the Modernizr prototype
Modernizr._q.push(function() {
ModernizrProto.addTest = addTest;
});
// Take the html5 variable out of the
// html5shiv scope so we can return it.
var html5;
/**
* @preserve HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
;(function(window, document) {
/*jshint evil:true */
/** version */
var version = '3.6.2';
/** 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;
}
/**
* 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) ? 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);
}(this, document));
// yepnope.js
// Version - 1.5.4pre
//
// by
// Alex Sexton - @SlexAxton - AlexSexton[at]gmail.com
// Ralph Holzmann - @ralphholzmann - ralphholzmann[at]gmail.com
//
// http://yepnopejs.com/
// https://github.com/SlexAxton/yepnope.js/
//
// Tri-license - WTFPL | MIT | BSD
//
// Please minify before use.
// Also available as Modernizr.load via the Modernizr Project
//
( function ( window, doc, undef ) {
var docElement = doc.documentElement,
sTimeout = window.setTimeout,
firstScript = doc.getElementsByTagName( "script" )[ 0 ],
toString = {}.toString,
execStack = [],
started = 0,
noop = function () {},
// Before you get mad about browser sniffs, please read:
// https://github.com/Modernizr/Modernizr/wiki/Undetectables
// If you have a better solution, we are actively looking to solve the problem
isGecko = ( "MozAppearance" in docElement.style ),
isGeckoLTE18 = isGecko && !! doc.createRange().compareNode,
insBeforeObj = isGeckoLTE18 ? docElement : firstScript.parentNode,
// Thanks to @jdalton for showing us this opera detection (by way of @kangax) (and probably @miketaylr too, or whatever...)
isOpera = window.opera && toString.call( window.opera ) == "[object Opera]",
isIE = !! doc.attachEvent && !isOpera,
strJsElem = isGecko ? "object" : isIE ? "script" : "img",
strCssElem = isIE ? "script" : strJsElem,
isArray = Array.isArray || function ( obj ) {
return toString.call( obj ) == "[object Array]";
},
isObject = function ( obj ) {
return Object(obj) === obj;
},
isString = function ( s ) {
return typeof s == "string";
},
isFunction = function ( fn ) {
return toString.call( fn ) == "[object Function]";
},
readFirstScript = function() {
if (!firstScript || !firstScript.parentNode) {
firstScript = doc.getElementsByTagName( "script" )[ 0 ];
}
},
globalFilters = [],
scriptCache = {},
prefixes = {
// key value pair timeout options
timeout : function( resourceObj, prefix_parts ) {
if ( prefix_parts.length ) {
resourceObj['timeout'] = prefix_parts[ 0 ];
}
return resourceObj;
}
},
handler,
yepnope;
/* Loader helper functions */
function isFileReady ( readyState ) {
// Check to see if any of the ways a file can be ready are available as properties on the file's element
return ( ! readyState || readyState == "loaded" || readyState == "complete" || readyState == "uninitialized" );
}
// Takes a preloaded js obj (changes in different browsers) and injects it into the head
// in the appropriate order
function injectJs ( src, cb, attrs, timeout, /* internal use */ err, internal ) {
var script = doc.createElement( "script" ),
done, i;
timeout = timeout || yepnope['errorTimeout'];
script.src = src;
// Add our extra attributes to the script element
for ( i in attrs ) {
script.setAttribute( i, attrs[ i ] );
}
cb = internal ? executeStack : ( cb || noop );
// Bind to load events
script.onreadystatechange = script.onload = function () {
if ( ! done && isFileReady( script.readyState ) ) {
// Set done to prevent this function from being called twice.
done = 1;
cb();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
}
};
// 404 Fallback
sTimeout(function () {
if ( ! done ) {
done = 1;
// Might as well pass in an error-state if we fire the 404 fallback
cb(1);
}
}, timeout );
// Inject script into to document
// or immediately callback if we know there
// was previously a timeout error
readFirstScript();
err ? script.onload() : firstScript.parentNode.insertBefore( script, firstScript );
}
// Takes a preloaded css obj (changes in different browsers) and injects it into the head
function injectCss ( href, cb, attrs, timeout, /* Internal use */ err, internal ) {
// Create stylesheet link
var link = doc.createElement( "link" ),
done, i;
timeout = timeout || yepnope['errorTimeout'];
cb = internal ? executeStack : ( cb || noop );
// Add attributes
link.href = href;
link.rel = "stylesheet";
link.type = "text/css";
// Add our extra attributes to the link element
for ( i in attrs ) {
link.setAttribute( i, attrs[ i ] );
}
if ( ! err ) {
readFirstScript();
firstScript.parentNode.insertBefore( link, firstScript );
sTimeout(cb, 0);
}
}
function executeStack ( ) {
// shift an element off of the stack
var i = execStack.shift();
started = 1;
// if a is truthy and the first item in the stack has an src
if ( i ) {
// if it's a script, inject it into the head with no type attribute
if ( i['t'] ) {
// Inject after a timeout so FF has time to be a jerk about it and
// not double load (ignore the cache)
sTimeout( function () {
(i['t'] == "c" ? yepnope['injectCss'] : yepnope['injectJs'])( i['s'], 0, i['a'], i['x'], i['e'], 1 );
}, 0 );
}
// Otherwise, just call the function and potentially run the stack
else {
i();
executeStack();
}
}
else {
// just reset out of recursive mode
started = 0;
}
}
function preloadFile ( elem, url, type, splicePoint, dontExec, attrObj, timeout ) {
timeout = timeout || yepnope['errorTimeout'];
// Create appropriate element for browser and type
var preloadElem = doc.createElement( elem ),
done = 0,
firstFlag = 0,
stackObject = {
"t": type, // type
"s": url, // src
//r: 0, // ready
"e": dontExec,// set to true if we don't want to reinject
"a": attrObj,
"x": timeout
};
// The first time (common-case)
if ( scriptCache[ url ] === 1 ) {
firstFlag = 1;
scriptCache[ url ] = [];
}
function onload ( first ) {
// If the script/css file is loaded
if ( ! done && isFileReady( preloadElem.readyState ) ) {
// Set done to prevent this function from being called twice.
stackObject['r'] = done = 1;
! started && executeStack();
if ( first ) {
if ( elem != "img" ) {
sTimeout( function () {
insBeforeObj.removeChild( preloadElem );
}, 50);
}
for ( var i in scriptCache[ url ] ) {
if ( scriptCache[ url ].hasOwnProperty( i ) ) {
scriptCache[ url ][ i ].onload();
}
}
// Handle memory leak in IE
preloadElem.onload = preloadElem.onreadystatechange = null;
}
}
}
// Setting url to data for objects or src for img/scripts
if ( elem == "object" ) {
preloadElem.data = url;
// Setting the type attribute to stop Firefox complaining about the mimetype when running locally.
// The type doesn't matter as long as it's real, thus text/css instead of text/javascript.
preloadElem.setAttribute("type", "text/css");
} else {
preloadElem.src = url;
// Setting bogus script type to allow the script to be cached
preloadElem.type = elem;
}
// Don't let it show up visually
preloadElem.width = preloadElem.height = "0";
// Attach handlers for all browsers
preloadElem.onerror = preloadElem.onload = preloadElem.onreadystatechange = function(){
onload.call(this, firstFlag);
};
// inject the element into the stack depending on if it's
// in the middle of other scripts or not
execStack.splice( splicePoint, 0, stackObject );
// The only place these can't go is in the element, since objects won't load in there
// so we have two options - insert before the head element (which is hard to assume) - or
// insertBefore technically takes null/undefined as a second param and it will insert the element into
// the parent last. We try the head, and it automatically falls back to undefined.
if ( elem != "img" ) {
// If it's the first time, or we've already loaded it all the way through
if ( firstFlag || scriptCache[ url ] === 2 ) {
readFirstScript();
insBeforeObj.insertBefore( preloadElem, isGeckoLTE18 ? null : firstScript );
// If something fails, and onerror doesn't fire,
// continue after a timeout.
sTimeout( onload, timeout );
}
else {
// instead of injecting, just hold on to it
scriptCache[ url ].push( preloadElem );
}
}
}
function load ( resource, type, dontExec, attrObj, timeout ) {
// If this method gets hit multiple times, we should flag
// that the execution of other threads should halt.
started = 0;
// We'll do 'j' for js and 'c' for css, yay for unreadable minification tactics
type = type || "j";
if ( isString( resource ) ) {
// if the resource passed in here is a string, preload the file
preloadFile( type == "c" ? strCssElem : strJsElem, resource, type, this['i']++, dontExec, attrObj, timeout );
} else {
// Otherwise it's a callback function and we can splice it into the stack to run
execStack.splice( this['i']++, 0, resource );
execStack.length == 1 && executeStack();
}
// OMG is this jQueries? For chaining...
return this;
}
// return the yepnope object with a fresh loader attached
function getYepnope () {
var y = yepnope;
y['loader'] = {
"load": load,
"i" : 0
};
return y;
}
/* End loader helper functions */
// Yepnope Function
yepnope = function ( needs ) {
var i,
need,
// start the chain as a plain instance
chain = this['yepnope']['loader'];
function satisfyPrefixes ( url ) {
// split all prefixes out
var parts = url.split( "!" ),
gLen = globalFilters.length,
origUrl = parts.pop(),
pLen = parts.length,
res = {
"url" : origUrl,
// keep this one static for callback variable consistency
"origUrl" : origUrl,
"prefixes" : parts
},
mFunc,
j,
prefix_parts;
// loop through prefixes
// if there are none, this automatically gets skipped
for ( j = 0; j < pLen; j++ ) {
prefix_parts = parts[ j ].split( '=' );
mFunc = prefixes[ prefix_parts.shift() ];
if ( mFunc ) {
res = mFunc( res, prefix_parts );
}
}
// Go through our global filters
for ( j = 0; j < gLen; j++ ) {
res = globalFilters[ j ]( res );
}
// return the final url
return res;
}
function getExtension ( url ) {
//The extension is always the last characters before the ? and after a period.
//The previous method was not accounting for the possibility of a period in the query string.
var b = url.split('?')[0];
return b.substr(b.lastIndexOf('.')+1);
}
function loadScriptOrStyle ( input, callback, chain, index, testResult ) {
// run through our set of prefixes
var resource = satisfyPrefixes( input ),
autoCallback = resource['autoCallback'],
extension = getExtension( resource['url'] );
// if no object is returned or the url is empty/0 just exit the load
if ( resource['bypass'] ) {
return;
}
// Determine callback, if any
if ( callback ) {
callback = isFunction( callback ) ?
callback :
callback[ input ] ||
callback[ index ] ||
callback[ ( input.split( "/" ).pop().split( "?" )[ 0 ] ) ];
}
// if someone is overriding all normal functionality
if ( resource['instead'] ) {
return resource['instead']( input, callback, chain, index, testResult );
}
else {
// Handle if we've already had this url and it's completed loaded already
if ( scriptCache[ resource['url'] ] && resource['reexecute'] !== true) {
// don't let this execute again
resource['noexec'] = true;
}
else {
scriptCache[ resource['url'] ] = 1;
}
// Throw this into the queue
input && chain.load( resource['url'], ( ( resource['forceCSS'] || ( ! resource['forceJS'] && "css" == getExtension( resource['url'] ) ) ) ) ? "c" : undef, resource['noexec'], resource['attrs'], resource['timeout'] );
// If we have a callback, we'll start the chain over
if ( isFunction( callback ) || isFunction( autoCallback ) ) {
// Call getJS with our current stack of things
chain['load']( function () {
// Hijack yepnope and restart index counter
getYepnope();
// Call our callbacks with this set of data
callback && callback( resource['origUrl'], testResult, index );
autoCallback && autoCallback( resource['origUrl'], testResult, index );
// Override this to just a boolean positive
scriptCache[ resource['url'] ] = 2;
} );
}
}
}
function loadFromTestObject ( testObject, chain ) {
var testResult = !! testObject['test'],
group = testResult ? testObject['yep'] : testObject['nope'],
always = testObject['load'] || testObject['both'],
callback = testObject['callback'] || noop,
cbRef = callback,
complete = testObject['complete'] || noop,
needGroupSize;
// Reusable function for dealing with the different input types
// NOTE:: relies on closures to keep 'chain' up to date, a bit confusing, but
// much smaller than the functional equivalent in this case.
function handleGroup ( needGroup, moreToCome ) {
/* jshint -W083 */
if ( '' !== needGroup && ! needGroup ) {
// Call the complete callback when there's nothing to load.
! moreToCome && complete();
}
// If it's a string
else if ( isString( needGroup ) ) {
// if it's a string, it's the last
if ( !moreToCome ) {
// Add in the complete callback to go at the end
callback = function () {
var args = [].slice.call( arguments );
cbRef.apply( this, args );
complete();
};
}
// Just load the script of style
loadScriptOrStyle( needGroup, callback, chain, 0, testResult );
}
// See if we have an object. Doesn't matter if it's an array or a key/val hash
// Note:: order cannot be guaranteed on an key value object with multiple elements
// since the for-in does not preserve order. Arrays _should_ go in order though.
else if ( isObject( needGroup ) ) {
// I hate this, but idk another way for objects.
needGroupSize = (function(){
var count = 0, i;
for (i in needGroup ) {
if ( needGroup.hasOwnProperty( i ) ) {
count++;
}
}
return count;
})();
for ( var callbackKey in needGroup ) {
// Safari 2 does not have hasOwnProperty, but not worth the bytes for a shim
// patch if needed. Kangax has a nice shim for it. Or just remove the check
// and promise not to extend the object prototype.
if ( needGroup.hasOwnProperty( callbackKey ) ) {
// Find the last added resource, and append to it's callback.
if ( ! moreToCome && ! ( --needGroupSize ) ) {
// If this is an object full of callbacks
if ( ! isFunction( callback ) ) {
// Add in the complete callback to go at the end
callback[ callbackKey ] = (function( innerCb ) {
return function () {
var args = [].slice.call( arguments );
innerCb && innerCb.apply( this, args );
complete();
};
})( cbRef[ callbackKey ] );
}
// If this is just a single callback
else {
callback = function () {
var args = [].slice.call( arguments );
cbRef.apply( this, args );
complete();
};
}
}
loadScriptOrStyle( needGroup[ callbackKey ], callback, chain, callbackKey, testResult );
}
}
}
}
// figure out what this group should do
handleGroup( group, !!always || !!testObject['complete']);
// Run our loader on the load/both group too
// the always stuff always loads second.
always && handleGroup( always );
// If complete callback is used without loading anything
!always && !!testObject['complete'] && handleGroup('');
}
// Someone just decides to load a single script or css file as a string
if ( isString( needs ) ) {
loadScriptOrStyle( needs, 0, chain, 0 );
}
// Normal case is likely an array of different types of loading options
else if ( isArray( needs ) ) {
// go through the list of needs
for( i = 0; i < needs.length; i++ ) {
need = needs[ i ];
// if it's a string, just load it
if ( isString( need ) ) {
loadScriptOrStyle( need, 0, chain, 0 );
}
// if it's an array, call our function recursively
else if ( isArray( need ) ) {
yepnope( need );
}
// if it's an object, use our modernizr logic to win
else if ( isObject( need ) ) {
loadFromTestObject( need, chain );
}
}
}
// Allow a single object to be passed in
else if ( isObject( needs ) ) {
loadFromTestObject( needs, chain );
}
};
// This publicly exposed function is for allowing
// you to add functionality based on prefixes on the
// string files you add. 'css!' is a builtin prefix
//
// The arguments are the prefix (not including the !) as a string
// and
// A callback function. This function is passed a resource object
// that can be manipulated and then returned. (like middleware. har.)
//
// Examples of this can be seen in the officially supported ie prefix
yepnope['addPrefix'] = function ( prefix, callback ) {
prefixes[ prefix ] = callback;
};
// A filter is a global function that every resource
// object that passes through yepnope will see. You can
// of course conditionally choose to modify the resource objects
// or just pass them along. The filter function takes the resource
// object and is expected to return one.
//
// The best example of a filter is the 'autoprotocol' officially
// supported filter
yepnope['addFilter'] = function ( filter ) {
globalFilters.push( filter );
};
// Default error timeout to 10sec - modify to alter
yepnope['errorTimeout'] = 1e4;
// Webreflection readystate hack
// safe for jQuery 1.4+ ( i.e. don't use yepnope with jQuery 1.3.2 )
// if the readyState is null and we have a listener
if ( doc.readyState == null && doc.addEventListener ) {
// set the ready state to loading
doc.readyState = "loading";
// call the listener
doc.addEventListener( "DOMContentLoaded", handler = function () {
// Remove the listener
doc.removeEventListener( "DOMContentLoaded", handler, 0 );
// Set it to ready
doc.readyState = "complete";
}, 0 );
}
// Attach loader &
// Leak it
window['yepnope'] = getYepnope();
// Exposing executeStack to better facilitate plugins
window['yepnope']['executeStack'] = executeStack;
window['yepnope']['injectJs'] = injectJs;
window['yepnope']['injectCss'] = injectCss;
})( window, document );
// Reappropriate
ModernizrProto['load'] = function() {
window['yepnope'].apply(window, [].slice.call(arguments,0));
};
/**
* contains returns a boolean for if substr is found within str.
*/
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
;
var createElement = function() {
return document.createElement.apply(document, arguments);
};
/**
* Create our "modernizr" element that we do most feature tests on.
*/
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;
});
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('body');
body.fake = true;
}
return body;
}
;
// Inject element with style element and some CSS rules
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);
}
}
// '].join('');
div.id = 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).innerHTML += style;
body.appendChild(div);
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;
}
;
// Helper function for e.g. boxSizing -> box-sizing
function domToHyphenated( name ) {
return name.replace(/([A-Z])/g, function(str, m1) {
return '-' + m1.toLowerCase();
}).replace(/^ms-/, '-ms-');
}
;
// Function to allow us to use native feature detection functionality if available.
// 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(domToHyphenated(props[i]), value)) {
return true;
}
}
return false;
}
// Otherwise fall back to at-rule (for FF 17 and Opera 12.x)
else if ('CSSSupportsRule' in window) {
// Build a condition string for every prefixed variant
var conditionText = [];
while (i--) {
conditionText.push('(' + domToHyphenated(props[i]) + ':' + value + ')');
}
conditionText = conditionText.join(' or ');
return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function( node ) {
return (window.getComputedStyle ?
getComputedStyle(node, null) :
node.currentStyle)['position'] == 'absolute';
});
}
return undefined;
}
;
// testProps is a generic CSS / DOM property test.
// In testing support for a given CSS property, it's legit to test:
// `elem.style[styleName] !== undefined`
// If the property is supported it will return an empty string,
// if unsupported it will return undefined.
// We'll take advantage of this quick test and skip setting a style
// on our modernizr element, but instead just testing undefined vs
// empty string.
// Because the testing of the CSS property names (with "-", as
// opposed to the camelCase DOM properties) is non-portable and
// non-standard but works in WebKit and IE (but not Gecko or Opera),
// we explicitly reject properties with dashes so that authors
// developing in WebKit or IE first don't end up with
// browser-specific content by accident.
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, 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
if ( !mStyle.style ) {
afterInit = true;
mStyle.modElem = createElement('modernizr');
mStyle.style = mStyle.modElem.style;
}
// Delete the objects if we
// we created them.
function cleanElems() {
if (afterInit) {
delete mStyle.style;
delete mStyle.modElem;
}
}
for ( i in props ) {
prop = props[i];
before = mStyle.style[prop];
if ( !contains(prop, '-') && 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;
}
;
// Modernizr.testProp() investigates whether a given style property is recognized
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testProp('pointerEvents')
// Also accepts optional 2nd arg, of a value to use for native feature detection, e.g.:
// Modernizr.testProp('pointerEvents', 'none')
var testProp = ModernizrProto.testProp = function( prop, value, useValue ) {
return testProps([prop], undefined, value, useValue);
};
var slice = classes.slice;
// Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
// es5.github.com/#x15.3.4.5
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != 'function') {
throw new TypeError();
}
var args = slice.call(arguments, 1);
var bound = function() {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F();
var result = target.apply(
self,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return self;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
return bound;
};
}
;
/*!
{
"name": "a[download] Attribute",
"property": "adownload",
"caniuse" : "download",
"tags": ["media", "attribute"],
"notes": [{
"name": "WhatWG Reference",
"href": "http://developers.whatwg.org/links.html#downloading-resources"
}]
}
!*/
/* DOC
When used on an ``, this attribute signifies that the resource it points to should be downloaded by the browser rather than navigating to it.
*/
Modernizr.addTest('adownload', !window.externalHost && 'download' in createElement('a'));
/*!
{
"name": "Application Cache",
"property": "applicationcache",
"caniuse": "offline-apps",
"tags": ["storage", "offline"],
"notes": [{
"name": "MDN documentation",
"href": "https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache"
}],
"polyfills": ["html5gears"]
}
!*/
/* DOC
Detects support for the Application Cache, for storing data to enable web-based applications run offline.
The API has been [heavily criticized](http://alistapart.com/article/application-cache-is-a-douchebag) and discussions are underway to address this.
*/
Modernizr.addTest('applicationcache', 'applicationCache' in window);
/*!
{
"name": "Audio Loop Attribute",
"property": "audioloop",
"tags": ["audio", "media"]
}
!*/
Modernizr.addTest('audioloop', 'loop' in createElement('audio'));
/*!
{
"name": "Audio Preload Attribute",
"property": "audiopreload",
"tags": ["audio", "media"]
}
!*/
Modernizr.addTest('audiopreload', 'preload' in createElement('audio'));
/*!
{
"name" : "HTML5 Audio Element",
"property": "audio",
"aliases" : [],
"tags" : ["html5", "audio", "media"],
"doc" : "/docs/#audio",
"knownBugs": [],
"authors" : []
}
!*/
// 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;') .replace(/^no$/,'');
bool.opus = elem.canPlayType('audio/ogg; 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 `