2016-02-05 17:35:15 +03:00
/ * !
* 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 */
/ * w e h a v e n o w a y o f t e s t i n g I E 5 . 5 o r s a f a r i 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/"
} ]
}
! * /
/ * D O C
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"
]
}
! * /
/ * D O C
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" ]
}
! * /
/ * D O C
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." ]
}
! * /
/ * D O C
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" ]
}
! * /
/ * D O C
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 = '­<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 ) ;