2011-06-26 13:52:25 +04:00
/ * !
2014-05-28 18:51:50 +04:00
* Modernizr v2 . 8.2
* www . modernizr . com
2011-06-26 13:52:25 +04:00
*
2014-05-28 18:51:50 +04:00
* Copyright ( c ) Faruk Ates , Paul Irish , Alex Sexton
* Available under the BSD and MIT licenses : www . modernizr . com / license /
2011-06-26 13:52:25 +04:00
* /
/ *
* 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 .
*
* Modernizr has an optional ( not included ) conditional resource loader
* called Modernizr . load ( ) , based on Yepnope . js ( yepnopejs . com ) .
* To get a build that includes Modernizr . load ( ) , as well as choosing
* which tests to include , go to www . modernizr . com / download /
*
2014-05-28 18:51:50 +04:00
* Authors Faruk Ates , Paul Irish , Alex Sexton
2011-06-26 13:52:25 +04:00
* Contributors Ryan Seddon , Ben Alman
* /
window . Modernizr = ( function ( window , document , undefined ) {
2014-05-28 18:51:50 +04:00
var version = '2.8.2' ,
2011-06-26 13:52:25 +04:00
Modernizr = { } ,
2014-05-28 18:51:50 +04:00
/*>>cssclasses*/
2011-06-26 13:52:25 +04:00
// option for enabling the HTML classes to be added
enableClasses = true ,
2014-05-28 18:51:50 +04:00
/*>>cssclasses*/
2011-06-26 13:52:25 +04:00
docElement = document . documentElement ,
/ * *
* Create our "modernizr" element that we do most feature tests on .
* /
mod = 'modernizr' ,
modElem = document . createElement ( mod ) ,
mStyle = modElem . style ,
/ * *
* Create the input element for various Web Forms feature tests .
* /
2014-05-28 18:51:50 +04:00
inputElem /*>>inputelem*/ = document . createElement ( 'input' ) /*>>inputelem*/ ,
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>smile*/
2011-06-26 13:52:25 +04:00
smile = ':)' ,
2014-05-28 18:51:50 +04:00
/*>>smile*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
toString = { } . toString ,
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// TODO :: make the prefixes more granular
/*>>prefixes*/
2011-06-26 13:52:25 +04:00
// List of property values to set for css tests. See ticket #21
2014-05-28 18:51:50 +04:00
prefixes = ' -webkit- -moz- -o- -ms- ' . split ( ' ' ) ,
/*>>prefixes*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>domprefixes*/
2011-06-26 13:52:25 +04:00
// Following spec is to expose vendor-specific style properties as:
// elem.style.WebkitBorderRadius
// and the following would be incorrect:
// elem.style.webkitBorderRadius
// Webkit ghosts their properties in lowercase but Opera & Moz do not.
2014-05-28 18:51:50 +04:00
// 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
omPrefixes = 'Webkit Moz O ms' ,
cssomPrefixes = omPrefixes . split ( ' ' ) ,
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
domPrefixes = omPrefixes . toLowerCase ( ) . split ( ' ' ) ,
/*>>domprefixes*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>ns*/
2011-06-26 13:52:25 +04:00
ns = { 'svg' : 'http://www.w3.org/2000/svg' } ,
2014-05-28 18:51:50 +04:00
/*>>ns*/
2011-06-26 13:52:25 +04:00
tests = { } ,
inputs = { } ,
attrs = { } ,
classes = [ ] ,
2014-05-28 18:51:50 +04:00
slice = classes . slice ,
2011-06-26 13:52:25 +04:00
featureName , // used in testing loop
2014-05-28 18:51:50 +04:00
/*>>teststyles*/
2011-06-26 13:52:25 +04:00
// Inject element with style element and some CSS rules
injectElementWithStyles = function ( rule , callback , nodes , testnames ) {
2014-05-28 18:51:50 +04:00
var style , ret , node , docOverflow ,
div = document . createElement ( 'div' ) ,
// After page load injecting a fake body doesn't work so check if body exists
body = document . body ,
// IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
fakeBody = body || document . createElement ( 'body' ) ;
2011-06-26 13:52:25 +04:00
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 = document . createElement ( 'div' ) ;
node . id = testnames ? testnames [ nodes ] : mod + ( nodes + 1 ) ;
div . appendChild ( node ) ;
}
}
// <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
// when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
// with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
2014-05-28 18:51:50 +04:00
// msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
// Documents served as xml will throw if using ­ so use xml friendly encoded version. See issue #277
style = [ '­' , '<style id="s' , mod , '">' , rule , '</style>' ] . join ( '' ) ;
2011-06-26 13:52:25 +04:00
div . id = mod ;
2014-05-28 18:51:50 +04:00
// 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 ? div : fakeBody ) . innerHTML += style ;
fakeBody . appendChild ( div ) ;
if ( ! body ) {
//avoid crashing IE8, if background image is used
fakeBody . style . background = '' ;
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
fakeBody . style . overflow = 'hidden' ;
docOverflow = docElement . style . overflow ;
docElement . style . overflow = 'hidden' ;
docElement . appendChild ( fakeBody ) ;
}
2011-06-26 13:52:25 +04:00
ret = callback ( div , rule ) ;
2014-05-28 18:51:50 +04:00
// If this is done after page load we don't want to remove the body so check if body exists
if ( ! body ) {
fakeBody . parentNode . removeChild ( fakeBody ) ;
docElement . style . overflow = docOverflow ;
} else {
div . parentNode . removeChild ( div ) ;
}
2011-06-26 13:52:25 +04:00
return ! ! ret ;
} ,
2014-05-28 18:51:50 +04:00
/*>>teststyles*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>mq*/
2011-06-26 13:52:25 +04:00
// adapted from matchMedia polyfill
// by Scott Jehl and Paul Irish
// gist.github.com/786768
testMediaQuery = function ( mq ) {
2014-05-28 18:51:50 +04:00
var matchMedia = window . matchMedia || window . msMatchMedia ;
if ( matchMedia ) {
return matchMedia ( mq ) && matchMedia ( mq ) . matches || false ;
2011-06-26 13:52:25 +04:00
}
var bool ;
injectElementWithStyles ( '@media ' + mq + ' { #' + mod + ' { position: absolute; } }' , function ( node ) {
bool = ( window . getComputedStyle ?
getComputedStyle ( node , null ) :
node . currentStyle ) [ 'position' ] == 'absolute' ;
} ) ;
return bool ;
} ,
2014-05-28 18:51:50 +04:00
/*>>mq*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>hasevent*/
//
// isEventSupported determines if a given element supports the given event
// kangax.github.com/iseventsupported/
//
// The following results are known incorrects:
// Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
// Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
// ...
2011-06-26 13:52:25 +04:00
isEventSupported = ( function ( ) {
var TAGNAMES = {
'select' : 'input' , 'change' : 'input' ,
'submit' : 'form' , 'reset' : 'form' ,
'error' : 'img' , 'load' : 'img' , 'abort' : 'img'
} ;
function isEventSupported ( eventName , element ) {
element = element || document . createElement ( TAGNAMES [ eventName ] || 'div' ) ;
eventName = 'on' + eventName ;
// When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
var isSupported = eventName in element ;
if ( ! isSupported ) {
// If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
if ( ! element . setAttribute ) {
element = document . createElement ( 'div' ) ;
}
if ( element . setAttribute && element . removeAttribute ) {
element . setAttribute ( eventName , '' ) ;
isSupported = is ( element [ eventName ] , 'function' ) ;
// If property was created, "remove it" (by setting value to `undefined`)
2014-05-28 18:51:50 +04:00
if ( ! is ( element [ eventName ] , 'undefined' ) ) {
2011-06-26 13:52:25 +04:00
element [ eventName ] = undefined ;
}
element . removeAttribute ( eventName ) ;
}
}
element = null ;
return isSupported ;
}
return isEventSupported ;
2014-05-28 18:51:50 +04:00
} ) ( ) ,
/*>>hasevent*/
// TODO :: Add flag for hasownprop ? didn't last time
2011-06-26 13:52:25 +04:00
// hasOwnProperty shim by kangax needed for Safari 2.0 support
2014-05-28 18:51:50 +04:00
_hasOwnProperty = ( { } ) . hasOwnProperty , hasOwnProp ;
if ( ! is ( _hasOwnProperty , 'undefined' ) && ! is ( _hasOwnProperty . call , 'undefined' ) ) {
hasOwnProp = function ( object , property ) {
2011-06-26 13:52:25 +04:00
return _hasOwnProperty . call ( object , property ) ;
} ;
}
else {
2014-05-28 18:51:50 +04:00
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' ) ) ;
} ;
}
// 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 ) ,
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 ;
2011-06-26 13:52:25 +04:00
} ;
}
/ * *
* setCss applies given styles to the Modernizr DOM node .
* /
function setCss ( str ) {
mStyle . cssText = str ;
}
/ * *
* setCssAll extrapolates all vendor - specific css strings .
* /
function setCssAll ( str1 , str2 ) {
return setCss ( prefixes . join ( str1 + ';' ) + ( str2 || '' ) ) ;
}
/ * *
* is returns a boolean for if typeof obj is exactly type .
* /
function is ( obj , type ) {
return typeof obj === type ;
}
/ * *
* contains returns a boolean for if substr is found within str .
* /
function contains ( str , substr ) {
return ! ! ~ ( '' + str ) . indexOf ( substr ) ;
}
2014-05-28 18:51:50 +04:00
/*>>testprop*/
// 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 ) {
for ( var i in props ) {
var prop = props [ i ] ;
if ( ! contains ( prop , "-" ) && mStyle [ prop ] !== undefined ) {
return prefixed == 'pfx' ? prop : true ;
}
}
return false ;
}
/*>>testprop*/
// TODO :: add testDOMProps
2011-06-26 13:52:25 +04:00
/ * *
2014-05-28 18:51:50 +04:00
* testDOMProps is a generic DOM property test ; if a browser supports
2011-06-26 13:52:25 +04:00
* a certain property , it won ' t return undefined for it .
* /
2014-05-28 18:51:50 +04:00
function testDOMProps ( props , obj , elem ) {
2011-06-26 13:52:25 +04:00
for ( var i in props ) {
2014-05-28 18:51:50 +04:00
var item = obj [ props [ i ] ] ;
if ( item !== undefined ) {
// return the property name as a string
if ( elem === false ) return props [ i ] ;
// let's bind a function
if ( is ( item , 'function' ) ) {
// default to autobind unless override
return item . bind ( elem || obj ) ;
}
// return the unbound function or obj or value
return item ;
2011-06-26 13:52:25 +04:00
}
}
return false ;
}
2014-05-28 18:51:50 +04:00
/*>>testallprops*/
2011-06-26 13:52:25 +04:00
/ * *
* 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 .
* /
2014-05-28 18:51:50 +04:00
function testPropsAll ( prop , prefixed , elem ) {
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
var ucProp = prop . charAt ( 0 ) . toUpperCase ( ) + prop . slice ( 1 ) ,
props = ( prop + ' ' + cssomPrefixes . join ( ucProp + ' ' ) + ucProp ) . split ( ' ' ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// did they call .prefixed('boxSizing') or are we just testing a prop?
if ( is ( prefixed , "string" ) || is ( prefixed , "undefined" ) ) {
return testProps ( props , prefixed ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
} else {
props = ( prop + ' ' + ( domPrefixes ) . join ( ucProp + ' ' ) + ucProp ) . split ( ' ' ) ;
return testDOMProps ( props , prefixed , elem ) ;
}
}
/*>>testallprops*/
2011-06-26 13:52:25 +04:00
/ * *
* Tests
* -- -- -
* /
2014-05-28 18:51:50 +04:00
// The *new* flexbox
// dev.w3.org/csswg/css3-flexbox
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
tests [ 'flexbox' ] = function ( ) {
return testPropsAll ( 'flexWrap' ) ;
} ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// The *old* flexbox
// www.w3.org/TR/2009/WD-css3-flexbox-20090723/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
tests [ 'flexboxlegacy' ] = function ( ) {
return testPropsAll ( 'boxDirection' ) ;
2011-06-26 13:52:25 +04:00
} ;
// On the S60 and BB Storm, getContext exists, but always returns undefined
2014-05-28 18:51:50 +04:00
// so we actually have to call getContext() to verify
// github.com/Modernizr/Modernizr/issues/issue/97/
2011-06-26 13:52:25 +04:00
tests [ 'canvas' ] = function ( ) {
var elem = document . createElement ( 'canvas' ) ;
return ! ! ( elem . getContext && elem . getContext ( '2d' ) ) ;
} ;
tests [ 'canvastext' ] = function ( ) {
return ! ! ( Modernizr [ 'canvas' ] && is ( document . createElement ( 'canvas' ) . getContext ( '2d' ) . fillText , 'function' ) ) ;
} ;
2014-05-28 18:51:50 +04:00
// webk.it/70117 is tracking a legit WebGL feature detect proposal
// We do a soft detect which may false positive in order to avoid
// an expensive context creation: bugzil.la/732441
2011-06-26 13:52:25 +04:00
tests [ 'webgl' ] = function ( ) {
return ! ! window . WebGLRenderingContext ;
} ;
/ *
* The Modernizr . touch test only indicates if the browser supports
* touch events , which does not necessarily reflect a touchscreen
* device , as evidenced by tablets running Windows 7 or , alas ,
* the Palm Pre / WebOS ( touch ) phones .
*
* Additionally , Chrome ( desktop ) used to lie about its support on this ,
2014-05-28 18:51:50 +04:00
* but that has since been rectified : crbug . com / 36415
2011-06-26 13:52:25 +04:00
*
* We also test for Firefox 4 Multitouch Support .
*
2014-05-28 18:51:50 +04:00
* For more info , see : modernizr . github . com / Modernizr / touch . html
2011-06-26 13:52:25 +04:00
* /
tests [ 'touch' ] = function ( ) {
2014-05-28 18:51:50 +04:00
var bool ;
if ( ( 'ontouchstart' in window ) || window . DocumentTouch && document instanceof DocumentTouch ) {
bool = true ;
} else {
injectElementWithStyles ( [ '@media (' , prefixes . join ( 'touch-enabled),(' ) , mod , ')' , '{#modernizr{top:9px;position:absolute}}' ] . join ( '' ) , function ( node ) {
bool = node . offsetTop === 9 ;
} ) ;
}
return bool ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// geolocation is often considered a trivial feature detect...
// Turns out, it's quite tricky to get right:
//
// Using !!navigator.geolocation does two things we don't want. It:
// 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
// 2. Disables page caching in WebKit: webk.it/43956
//
// Meanwhile, in Firefox < 8, an about:config setting could expose
// a false positive that would throw an exception: bugzil.la/688158
2011-06-26 13:52:25 +04:00
tests [ 'geolocation' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return 'geolocation' in navigator ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
tests [ 'postmessage' ] = function ( ) {
return ! ! window . postMessage ;
} ;
2014-05-28 18:51:50 +04:00
// Chrome incognito mode used to throw an exception when using openDatabase
// It doesn't anymore.
2011-06-26 13:52:25 +04:00
tests [ 'websqldatabase' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return ! ! window . openDatabase ;
2011-06-26 13:52:25 +04:00
} ;
// Vendors had inconsistent prefixing with the experimental Indexed DB:
// - Webkit's implementation is accessible through webkitIndexedDB
// - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
// For speed, we don't test the legacy (and beta-only) indexedDB
tests [ 'indexedDB' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return ! ! testPropsAll ( "indexedDB" , window ) ;
2011-06-26 13:52:25 +04:00
} ;
// documentMode logic from YUI to filter out IE8 Compat Mode
// which false positives.
tests [ 'hashchange' ] = function ( ) {
return isEventSupported ( 'hashchange' , window ) && ( document . documentMode === undefined || document . documentMode > 7 ) ;
} ;
// Per 1.6:
// This used to be Modernizr.historymanagement but the longer
// name has been deprecated in favor of a shorter and property-matching one.
// The old API is still available in 1.6, but as of 2.0 will throw a warning,
// and in the first release thereafter disappear entirely.
tests [ 'history' ] = function ( ) {
return ! ! ( window . history && history . pushState ) ;
} ;
tests [ 'draganddrop' ] = function ( ) {
2014-05-28 18:51:50 +04:00
var div = document . createElement ( 'div' ) ;
return ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
// will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
// FF10 still uses prefixes, so check for it until then.
// for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
2011-06-26 13:52:25 +04:00
tests [ 'websockets' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return 'WebSocket' in window || 'MozWebSocket' in window ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// css-tricks.com/rgba-browser-support/
2011-06-26 13:52:25 +04:00
tests [ 'rgba' ] = function ( ) {
// Set an rgba() color and check the returned value
setCss ( 'background-color:rgba(150,255,150,.5)' ) ;
return contains ( mStyle . backgroundColor , 'rgba' ) ;
} ;
tests [ 'hsla' ] = function ( ) {
// Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
// except IE9 who retains it as hsla
setCss ( 'background-color:hsla(120,40%,100%,.5)' ) ;
return contains ( mStyle . backgroundColor , 'rgba' ) || contains ( mStyle . backgroundColor , 'hsla' ) ;
} ;
tests [ 'multiplebgs' ] = function ( ) {
// Setting multiple images AND a color on the background shorthand property
// and then querying the style.background property value for the number of
// occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
setCss ( 'background:url(https://),url(https://),red url(https://)' ) ;
// If the UA supports multiple backgrounds, there should be three occurrences
// of the string "url(" in the return value for elemStyle.background
2014-05-28 18:51:50 +04:00
return ( /(url\s*\(.*?){3}/ ) . test ( mStyle . background ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// this will false positive in Opera Mini
// github.com/Modernizr/Modernizr/issues/396
2011-06-26 13:52:25 +04:00
tests [ 'backgroundsize' ] = function ( ) {
return testPropsAll ( 'backgroundSize' ) ;
} ;
tests [ 'borderimage' ] = function ( ) {
return testPropsAll ( 'borderImage' ) ;
} ;
// Super comprehensive table about all the unique implementations of
2014-05-28 18:51:50 +04:00
// border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
2011-06-26 13:52:25 +04:00
tests [ 'borderradius' ] = function ( ) {
return testPropsAll ( 'borderRadius' ) ;
} ;
// WebOS unfortunately false positives on this test.
tests [ 'boxshadow' ] = function ( ) {
return testPropsAll ( 'boxShadow' ) ;
} ;
// FF3.0 will false positive on this test
tests [ 'textshadow' ] = function ( ) {
return document . createElement ( 'div' ) . style . textShadow === '' ;
} ;
tests [ 'opacity' ] = function ( ) {
// Browsers that actually have CSS Opacity implemented have done so
// according to spec, which means their return values are within the
// range of [0.0,1.0] - including the leading zero.
setCssAll ( 'opacity:.55' ) ;
// The non-literal . in this regex is intentional:
// German Chrome returns this value as 0,55
2014-05-28 18:51:50 +04:00
// github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
return ( /^0.55$/ ) . test ( mStyle . opacity ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// Note, Android < 4 will pass this test, but can only animate
// a single property at a time
// goo.gl/v3V4Gp
2011-06-26 13:52:25 +04:00
tests [ 'cssanimations' ] = function ( ) {
return testPropsAll ( 'animationName' ) ;
} ;
tests [ 'csscolumns' ] = function ( ) {
return testPropsAll ( 'columnCount' ) ;
} ;
tests [ 'cssgradients' ] = function ( ) {
/ * *
* For CSS Gradients syntax , please see :
2014-05-28 18:51:50 +04:00
* webkit . org / blog / 175 / introducing - css - gradients /
* developer . mozilla . org / en / CSS / - moz - linear - gradient
* developer . mozilla . org / en / CSS / - moz - radial - gradient
* dev . w3 . org / csswg / css3 - images / # gradients -
2011-06-26 13:52:25 +04:00
* /
var str1 = 'background-image:' ,
str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));' ,
str3 = 'linear-gradient(left top,#9f9, white);' ;
setCss (
2014-05-28 18:51:50 +04:00
// legacy webkit syntax (FIXME: remove when syntax not in use anymore)
( str1 + '-webkit- ' . split ( ' ' ) . join ( str2 + str1 ) +
// standard syntax // trailing 'background-image:'
prefixes . join ( str3 + str1 ) ) . slice ( 0 , - str1 . length )
2011-06-26 13:52:25 +04:00
) ;
return contains ( mStyle . backgroundImage , 'gradient' ) ;
} ;
tests [ 'cssreflections' ] = function ( ) {
return testPropsAll ( 'boxReflect' ) ;
} ;
tests [ 'csstransforms' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return ! ! testPropsAll ( 'transform' ) ;
2011-06-26 13:52:25 +04:00
} ;
tests [ 'csstransforms3d' ] = function ( ) {
2014-05-28 18:51:50 +04:00
var ret = ! ! testPropsAll ( 'perspective' ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// Webkit's 3D transforms are passed off to the browser's own graphics renderer.
2011-06-26 13:52:25 +04:00
// 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 && 'webkitPerspective' in docElement . style ) {
// Webkit allows this media query to succeed only if the feature is enabled.
2014-05-28 18:51:50 +04:00
// `@media (transform-3d),(-webkit-transform-3d){ ... }`
injectElementWithStyles ( '@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}' , function ( node , rule ) {
ret = node . offsetLeft === 9 && node . offsetHeight === 3 ;
} ) ;
2011-06-26 13:52:25 +04:00
}
return ret ;
} ;
tests [ 'csstransitions' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return testPropsAll ( 'transition' ) ;
2011-06-26 13:52:25 +04:00
} ;
/*>>fontface*/
// @font-face detection routine by Diego Perini
2014-05-28 18:51:50 +04:00
// javascript.nwbox.com/CSSSupport/
// false positives:
// WebOS github.com/Modernizr/Modernizr/issues/342
// WP7 github.com/Modernizr/Modernizr/issues/538
2011-06-26 13:52:25 +04:00
tests [ 'fontface' ] = function ( ) {
2014-05-28 18:51:50 +04:00
var bool ;
injectElementWithStyles ( '@font-face {font-family:"font";src:url("https://")}' , function ( node , rule ) {
var style = document . getElementById ( 'smodernizr' ) ,
sheet = style . sheet || style . styleSheet ,
cssText = sheet ? ( sheet . cssRules && sheet . cssRules [ 0 ] ? sheet . cssRules [ 0 ] . cssText : sheet . cssText || '' ) : '' ;
bool = /src/i . test ( cssText ) && cssText . indexOf ( rule . split ( ' ' ) [ 0 ] ) === 0 ;
} ) ;
return bool ;
2011-06-26 13:52:25 +04:00
} ;
/*>>fontface*/
// CSS generated content detection
tests [ 'generatedcontent' ] = function ( ) {
2014-05-28 18:51:50 +04:00
var bool ;
injectElementWithStyles ( [ '#' , mod , '{font:0/0 a}#' , mod , ':after{content:"' , smile , '";visibility:hidden;font:3px/1 a}' ] . join ( '' ) , function ( node ) {
bool = node . offsetHeight >= 3 ;
} ) ;
return bool ;
2011-06-26 13:52:25 +04:00
} ;
// These tests evaluate support of the video/audio elements, as well as
// testing what types of content they support.
//
// We're using the Boolean constructor here, so that we can extend the value
// e.g. Modernizr.video // true
// Modernizr.video.ogg // 'probably'
//
2014-05-28 18:51:50 +04:00
// Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
2011-06-26 13:52:25 +04:00
// thx to NielsLeenheer and zcorpan
2014-05-28 18:51:50 +04:00
// 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
2011-06-26 13:52:25 +04:00
tests [ 'video' ] = function ( ) {
var elem = document . createElement ( 'video' ) ,
bool = false ;
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
// IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
try {
if ( bool = ! ! elem . canPlayType ) {
bool = new Boolean ( bool ) ;
2014-05-28 18:51:50 +04:00
bool . ogg = elem . canPlayType ( 'video/ogg; codecs="theora"' ) . replace ( /^no$/ , '' ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
bool . h264 = elem . canPlayType ( 'video/mp4; codecs="avc1.42E01E"' ) . replace ( /^no$/ , '' ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
bool . webm = elem . canPlayType ( 'video/webm; codecs="vp8, vorbis"' ) . replace ( /^no$/ , '' ) ;
2011-06-26 13:52:25 +04:00
}
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
} catch ( e ) { }
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
return bool ;
} ;
tests [ 'audio' ] = function ( ) {
var elem = document . createElement ( 'audio' ) ,
bool = false ;
2014-05-28 18:51:50 +04:00
try {
2011-06-26 13:52:25 +04:00
if ( bool = ! ! elem . canPlayType ) {
bool = new Boolean ( bool ) ;
2014-05-28 18:51:50 +04:00
bool . ogg = elem . canPlayType ( 'audio/ogg; codecs="vorbis"' ) . replace ( /^no$/ , '' ) ;
bool . mp3 = elem . canPlayType ( 'audio/mpeg;' ) . replace ( /^no$/ , '' ) ;
2011-06-26 13:52:25 +04:00
// Mimetypes accepted:
2014-05-28 18:51:50 +04:00
// 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$/ , '' ) ;
2011-06-26 13:52:25 +04:00
}
} catch ( e ) { }
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
return bool ;
} ;
// In FF4, if disabled, window.localStorage should === null.
// Normally, we could not test that directly and need to do a
// `('localStorage' in window) && ` test first because otherwise Firefox will
2014-05-28 18:51:50 +04:00
// throw bugzil.la/365772 if cookies are disabled
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
// will throw the exception:
// QUOTA_EXCEEDED_ERRROR DOM Exception 22.
// Peculiarly, getItem and removeItem calls do not throw.
2011-06-26 13:52:25 +04:00
// Because we are forced to try/catch this, we'll go aggressive.
2014-05-28 18:51:50 +04:00
// Just FWIW: IE8 Compat mode supports these features completely:
// www.quirksmode.org/dom/html5.html
2011-06-26 13:52:25 +04:00
// But IE8 doesn't support either with local files
tests [ 'localstorage' ] = function ( ) {
try {
2014-05-28 18:51:50 +04:00
localStorage . setItem ( mod , mod ) ;
localStorage . removeItem ( mod ) ;
return true ;
2011-06-26 13:52:25 +04:00
} catch ( e ) {
return false ;
}
} ;
tests [ 'sessionstorage' ] = function ( ) {
try {
2014-05-28 18:51:50 +04:00
sessionStorage . setItem ( mod , mod ) ;
sessionStorage . removeItem ( mod ) ;
return true ;
} catch ( e ) {
2011-06-26 13:52:25 +04:00
return false ;
}
} ;
tests [ 'webworkers' ] = function ( ) {
return ! ! window . Worker ;
} ;
tests [ 'applicationcache' ] = function ( ) {
return ! ! window . applicationCache ;
} ;
// Thanks to Erik Dahlstrom
tests [ 'svg' ] = function ( ) {
return ! ! document . createElementNS && ! ! document . createElementNS ( ns . svg , 'svg' ) . createSVGRect ;
} ;
// specifically for SVG inline in HTML, not within XHTML
// test page: paulirish.com/demo/inline-svg
tests [ 'inlinesvg' ] = function ( ) {
var div = document . createElement ( 'div' ) ;
div . innerHTML = '<svg/>' ;
return ( div . firstChild && div . firstChild . namespaceURI ) == ns . svg ;
} ;
2014-05-28 18:51:50 +04:00
// SVG SMIL animation
2011-06-26 13:52:25 +04:00
tests [ 'smil' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return ! ! document . createElementNS && /SVGAnimate/ . test ( toString . call ( document . createElementNS ( ns . svg , 'animate' ) ) ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
// This test is only for clip paths in SVG proper, not clip paths on HTML content
// demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
// However read the comments to dig into applying SVG clippaths to HTML content here:
// github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
2011-06-26 13:52:25 +04:00
tests [ 'svgclippaths' ] = function ( ) {
2014-05-28 18:51:50 +04:00
return ! ! document . createElementNS && /SVGClipPath/ . test ( toString . call ( document . createElementNS ( ns . svg , 'clipPath' ) ) ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
/*>>webforms*/
2011-06-26 13:52:25 +04:00
// input features and input types go directly onto the ret object, bypassing the tests loop.
// Hold this guy to execute in a moment.
function webforms ( ) {
2014-05-28 18:51:50 +04:00
/*>>input*/
2011-06-26 13:52:25 +04:00
// Run through HTML5's new input attributes to see if the UA understands any.
// We're using f which is the <input> element created early on
// Mike Taylr has created a comprehensive resource for testing these attributes
// when applied to all input types:
2014-05-28 18:51:50 +04:00
// miketaylr.com/code/input-type-attr.html
// spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
// Only input placeholder is tested while textarea's placeholder is not.
2011-06-26 13:52:25 +04:00
// Currently Safari 4 and Opera 11 have support only for the input placeholder
// Both tests are available in feature-detects/forms-placeholder.js
Modernizr [ 'input' ] = ( function ( props ) {
for ( var i = 0 , len = props . length ; i < len ; i ++ ) {
attrs [ props [ i ] ] = ! ! ( props [ i ] in inputElem ) ;
}
2014-05-28 18:51:50 +04:00
if ( attrs . list ) {
// safari false positive's on datalist: webk.it/74252
// see also github.com/Modernizr/Modernizr/issues/146
attrs . list = ! ! ( document . createElement ( 'datalist' ) && window . HTMLDataListElement ) ;
}
2011-06-26 13:52:25 +04:00
return attrs ;
} ) ( 'autocomplete autofocus list placeholder max min multiple pattern required step' . split ( ' ' ) ) ;
2014-05-28 18:51:50 +04:00
/*>>input*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>inputtypes*/
2011-06-26 13:52:25 +04:00
// Run through HTML5's new input types to see if the UA understands any.
// This is put behind the tests runloop because it doesn't return a
// true/false like all the other tests; instead, it returns an object
// containing each input type with its corresponding true/false value
2014-05-28 18:51:50 +04:00
// Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
2011-06-26 13:52:25 +04:00
Modernizr [ 'inputtypes' ] = ( function ( props ) {
for ( var i = 0 , bool , inputElemType , defaultView , len = props . length ; i < len ; i ++ ) {
inputElem . setAttribute ( 'type' , inputElemType = props [ i ] ) ;
bool = inputElem . type !== 'text' ;
// We first check to see if the type we give it sticks..
// If the type does, we feed it a textual value, which shouldn't be valid.
// If the value doesn't stick, we know there's input sanitization which infers a custom UI
if ( bool ) {
inputElem . value = smile ;
inputElem . style . cssText = 'position:absolute;visibility:hidden;' ;
if ( /^range$/ . test ( inputElemType ) && inputElem . style . WebkitAppearance !== undefined ) {
docElement . appendChild ( inputElem ) ;
defaultView = document . defaultView ;
// Safari 2-4 allows the smiley as a value, despite making a slider
bool = defaultView . getComputedStyle &&
defaultView . getComputedStyle ( inputElem , null ) . WebkitAppearance !== 'textfield' &&
// Mobile android web browser has false positive, so must
// check the height to see if the widget is actually there.
( inputElem . offsetHeight !== 0 ) ;
docElement . removeChild ( inputElem ) ;
} else if ( /^(search|tel)$/ . test ( inputElemType ) ) {
2014-05-28 18:51:50 +04:00
// Spec doesn't define any special parsing or detectable UI
2011-06-26 13:52:25 +04:00
// behaviors so we pass these through as true
// Interestingly, opera fails the earlier test, so it doesn't
// even make it here.
} else if ( /^(url|email)$/ . test ( inputElemType ) ) {
// Real url and email support comes with prebaked validation.
bool = inputElem . checkValidity && inputElem . checkValidity ( ) === false ;
} else {
// If the upgraded input compontent rejects the :) text, we got a winner
bool = inputElem . value != smile ;
}
}
inputs [ props [ i ] ] = ! ! bool ;
}
return inputs ;
} ) ( 'search tel url email datetime date month week time datetime-local number range color' . split ( ' ' ) ) ;
2014-05-28 18:51:50 +04:00
/*>>inputtypes*/
2011-06-26 13:52:25 +04:00
}
2014-05-28 18:51:50 +04:00
/*>>webforms*/
2011-06-26 13:52:25 +04:00
// End of test definitions
// -----------------------
// Run through all tests and detect their support in the current UA.
// todo: hypothetically we could be doing an array of tests and use a basic loop here.
for ( var feature in tests ) {
2014-05-28 18:51:50 +04:00
if ( hasOwnProp ( tests , feature ) ) {
2011-06-26 13:52:25 +04:00
// 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.
featureName = feature . toLowerCase ( ) ;
Modernizr [ featureName ] = tests [ feature ] ( ) ;
classes . push ( ( Modernizr [ featureName ] ? '' : 'no-' ) + featureName ) ;
}
}
2014-05-28 18:51:50 +04:00
/*>>webforms*/
2011-06-26 13:52:25 +04:00
// input tests need to run.
Modernizr . input || webforms ( ) ;
2014-05-28 18:51:50 +04:00
/*>>webforms*/
2011-06-26 13:52:25 +04:00
/ * *
* 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
* /
Modernizr . addTest = function ( feature , test ) {
2014-05-28 18:51:50 +04:00
if ( typeof feature == 'object' ) {
2011-06-26 13:52:25 +04:00
for ( var key in feature ) {
2014-05-28 18:51:50 +04:00
if ( hasOwnProp ( feature , key ) ) {
2011-06-26 13:52:25 +04:00
Modernizr . addTest ( key , feature [ key ] ) ;
}
}
} else {
feature = feature . toLowerCase ( ) ;
if ( Modernizr [ feature ] !== 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:
2014-05-28 18:51:50 +04:00
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
2011-06-26 13:52:25 +04:00
// docElement.className = docElement.className.replace( re, '' );
// but, no rly, stuff 'em.
2014-05-28 18:51:50 +04:00
return Modernizr ;
2011-06-26 13:52:25 +04:00
}
2014-05-28 18:51:50 +04:00
test = typeof test == 'function' ? test ( ) : test ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
if ( typeof enableClasses !== "undefined" && enableClasses ) {
docElement . className += ' ' + ( test ? '' : 'no-' ) + feature ;
}
2011-06-26 13:52:25 +04:00
Modernizr [ feature ] = test ;
}
return Modernizr ; // allow chaining.
} ;
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
// Reset modElem.cssText to nothing to reduce memory footprint.
setCss ( '' ) ;
modElem = inputElem = null ;
2014-05-28 18:51:50 +04:00
/*>>shiv*/
/ * *
* @ preserve HTML5 Shiv prev3 . 7.1 | @ afarkas @ jdalton @ jon _neal @ rem | MIT / GPL2 Licensed
* /
; ( function ( window , document ) {
/*jshint evil:true */
/** version */
var version = '3.7.0' ;
/** 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 ;
2011-06-26 13:52:25 +04:00
}
2014-05-28 18:51:50 +04:00
} ( ) ) ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*--------------------------------------------------------------------------*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/ * *
* 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 ;
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
p . innerHTML = 'x<style>' + cssText + '</style>' ;
return parent . insertBefore ( p . lastChild , parent . firstChild ) ;
}
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/ * *
* 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 ;
}
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/ * *
* 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 ) ;
}
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
// 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 ) ;
2011-06-26 13:52:25 +04:00
} ;
2014-05-28 18:51:50 +04:00
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 ) ;
}
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*--------------------------------------------------------------------------*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/ * *
* 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 ;
}
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*--------------------------------------------------------------------------*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/ * *
* 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 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
} ;
/*--------------------------------------------------------------------------*/
// expose html5
window . html5 = html5 ;
// shiv the document
shivDocument ( document ) ;
} ( this , document ) ) ;
/*>>shiv*/
2011-06-26 13:52:25 +04:00
// Assign private properties to the return object with prefix
Modernizr . _version = version ;
// expose these for the plugin API. Look in the source for how to join() them against your input
2014-05-28 18:51:50 +04:00
/*>>prefixes*/
2011-06-26 13:52:25 +04:00
Modernizr . _prefixes = prefixes ;
2014-05-28 18:51:50 +04:00
/*>>prefixes*/
/*>>domprefixes*/
2011-06-26 13:52:25 +04:00
Modernizr . _domPrefixes = domPrefixes ;
2014-05-28 18:51:50 +04:00
Modernizr . _cssomPrefixes = cssomPrefixes ;
/*>>domprefixes*/
/*>>mq*/
2011-06-26 13:52:25 +04:00
// Modernizr.mq tests a given media query, live against the current state of the window
// A few important notes:
// * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
// * A max-width or orientation query will be evaluated against the current state, which may change later.
2014-05-28 18:51:50 +04:00
// * You must specify values. Eg. If you are testing support for the min-width media query use:
2011-06-26 13:52:25 +04:00
// Modernizr.mq('(min-width:0)')
// usage:
// Modernizr.mq('only screen and (max-width:768)')
2014-05-28 18:51:50 +04:00
Modernizr . mq = testMediaQuery ;
/*>>mq*/
/*>>hasevent*/
2011-06-26 13:52:25 +04:00
// Modernizr.hasEvent() detects support for a given event, with an optional element to test on
// Modernizr.hasEvent('gesturestart', elem)
2014-05-28 18:51:50 +04:00
Modernizr . hasEvent = isEventSupported ;
/*>>hasevent*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>testprop*/
2011-06-26 13:52:25 +04:00
// 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')
Modernizr . testProp = function ( prop ) {
return testProps ( [ prop ] ) ;
2014-05-28 18:51:50 +04:00
} ;
/*>>testprop*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>testallprops*/
2011-06-26 13:52:25 +04:00
// 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.
2014-05-28 18:51:50 +04:00
// Modernizr.testAllProps('boxSizing')
Modernizr . testAllProps = testPropsAll ;
/*>>testallprops*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>teststyles*/
2011-06-26 13:52:25 +04:00
// Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
// Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
2014-05-28 18:51:50 +04:00
Modernizr . testStyles = injectElementWithStyles ;
/*>>teststyles*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>prefixed*/
2011-06-26 13:52:25 +04:00
// Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
// Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
// Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
// Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
//
// str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
2014-05-28 18:51:50 +04:00
2011-06-26 13:52:25 +04:00
// If you're trying to ascertain which transition end event to bind to, you might do something like...
2014-05-28 18:51:50 +04:00
//
2011-06-26 13:52:25 +04:00
// var transEndEventNames = {
// 'WebkitTransition' : 'webkitTransitionEnd',
// 'MozTransition' : 'transitionend',
// 'OTransition' : 'oTransitionEnd',
2014-05-28 18:51:50 +04:00
// 'msTransition' : 'MSTransitionEnd',
// 'transition' : 'transitionend'
2011-06-26 13:52:25 +04:00
// },
// transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
2014-05-28 18:51:50 +04:00
Modernizr . prefixed = function ( prop , obj , elem ) {
if ( ! obj ) {
return testPropsAll ( prop , 'pfx' ) ;
} else {
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
return testPropsAll ( prop , obj , elem ) ;
}
} ;
/*>>prefixed*/
2011-06-26 13:52:25 +04:00
2014-05-28 18:51:50 +04:00
/*>>cssclasses*/
2011-06-26 13:52:25 +04:00
// Remove "no-js" class from <html> element, if it exists:
2014-05-28 18:51:50 +04:00
docElement . className = docElement . className . replace ( /(^|\s)no-js(\s|$)/ , '$1$2' ) +
2011-06-26 13:52:25 +04:00
// Add the new classes to the <html> element.
2014-05-28 18:51:50 +04:00
( enableClasses ? ' js ' + classes . join ( ' ' ) : '' ) ;
/*>>cssclasses*/
2011-06-26 13:52:25 +04:00
return Modernizr ;
} ) ( this , this . document ) ;