diff --git a/examples/modernizr.js b/examples/modernizr.js index f9e57c81b..24de6cc75 100644 --- a/examples/modernizr.js +++ b/examples/modernizr.js @@ -1,9 +1,9 @@ /*! - * Modernizr v2.0.6 - * http://www.modernizr.com + * Modernizr v2.8.2 + * www.modernizr.com * - * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton - * Dual-licensed under the BSD or MIT licenses: www.modernizr.com/license/ + * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton + * Available under the BSD and MIT licenses: www.modernizr.com/license/ */ /* @@ -18,21 +18,22 @@ * To get a build that includes Modernizr.load(), as well as choosing * which tests to include, go to www.modernizr.com/download/ * - * Authors Faruk Ates, Paul Irish, Alex Sexton, + * Authors Faruk Ates, Paul Irish, Alex Sexton * Contributors Ryan Seddon, Ben Alman */ window.Modernizr = (function( window, document, undefined ) { - var version = '2.0.6', + var version = '2.8.2', Modernizr = {}, - + + /*>>cssclasses*/ // option for enabling the HTML classes to be added enableClasses = true, + /*>>cssclasses*/ docElement = document.documentElement, - docHead = document.head || document.getElementsByTagName('head')[0], /** * Create our "modernizr" element that we do most feature tests on. @@ -44,28 +45,41 @@ window.Modernizr = (function( window, document, undefined ) { /** * Create the input element for various Web Forms feature tests. */ - inputElem = document.createElement('input'), + inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ , + /*>>smile*/ smile = ':)', + /*>>smile*/ - toString = Object.prototype.toString, + toString = {}.toString, + // TODO :: make the prefixes more granular + /*>>prefixes*/ // List of property values to set for css tests. See ticket #21 - prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '), + prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), + /*>>prefixes*/ + /*>>domprefixes*/ // 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. - // Microsoft foregoes prefixes entirely <= IE8, but appears to - // use a lowercase `ms` instead of the correct `Ms` in IE9 + // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ + // erik.eae.net/archives/2008/03/10/21.48.10/ - // More here: http://github.com/Modernizr/Modernizr/issues/issue/21 - domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), + // More here: github.com/Modernizr/Modernizr/issues/issue/21 + omPrefixes = 'Webkit Moz O ms', + cssomPrefixes = omPrefixes.split(' '), + + domPrefixes = omPrefixes.toLowerCase().split(' '), + /*>>domprefixes*/ + + /*>>ns*/ ns = {'svg': 'http://www.w3.org/2000/svg'}, + /*>>ns*/ tests = {}, inputs = {}, @@ -73,14 +87,21 @@ window.Modernizr = (function( window, document, undefined ) { classes = [], + slice = classes.slice, + featureName, // used in testing loop + /*>>teststyles*/ // Inject element with style element and some CSS rules injectElementWithStyles = function( rule, callback, nodes, testnames ) { - var style, ret, node, - div = document.createElement('div'); + 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'); if ( parseInt(nodes, 10) ) { // In order not to give false positives we create a node for each test @@ -95,27 +116,47 @@ window.Modernizr = (function( window, document, undefined ) { // '].join(''); + // 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 = ['­',''].join(''); div.id = mod; - div.innerHTML += style; - docElement.appendChild(div); + // 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); + } ret = callback(div, rule); - div.parentNode.removeChild(div); + // 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); + } return !!ret; }, + /*>>teststyles*/ - + /*>>mq*/ // adapted from matchMedia polyfill // by Scott Jehl and Paul Irish // gist.github.com/786768 testMediaQuery = function( mq ) { - if ( window.matchMedia ) { - return matchMedia(mq).matches; + var matchMedia = window.matchMedia || window.msMatchMedia; + if ( matchMedia ) { + return matchMedia(mq) && matchMedia(mq).matches || false; } var bool; @@ -129,12 +170,18 @@ window.Modernizr = (function( window, document, undefined ) { return bool; }, + /*>>mq*/ - /** - * isEventSupported determines if a given element supports the given event - * function from http://yura.thinkweb2.com/isEventSupported/ - */ + /*>>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 + // ... isEventSupported = (function() { var TAGNAMES = { @@ -161,7 +208,7 @@ window.Modernizr = (function( window, document, undefined ) { isSupported = is(element[eventName], 'function'); // If property was created, "remove it" (by setting value to `undefined`) - if ( !is(element[eventName], undefined) ) { + if ( !is(element[eventName], 'undefined') ) { element[eventName] = undefined; } element.removeAttribute(eventName); @@ -172,18 +219,67 @@ window.Modernizr = (function( window, document, undefined ) { return isSupported; } return isEventSupported; - })(); + })(), + /*>>hasevent*/ + + // TODO :: Add flag for hasownprop ? didn't last time // hasOwnProperty shim by kangax needed for Safari 2.0 support - var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; - if ( !is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined) ) { - hasOwnProperty = function (object, property) { + _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp; + + if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { + hasOwnProp = function (object, property) { return _hasOwnProperty.call(object, property); }; } else { - hasOwnProperty = 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)); + 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; }; } @@ -215,81 +311,86 @@ window.Modernizr = (function( window, document, undefined ) { return !!~('' + str).indexOf(substr); } - /** - * testProps is a generic CSS / DOM property test; if a browser supports - * a certain property, it won't return undefined for it. - * A supported CSS property returns empty string when its not yet set. - */ + /*>>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 ) { - if ( mStyle[ props[i] ] !== undefined ) { - return prefixed == 'pfx' ? props[i] : true; + var prop = props[i]; + if ( !contains(prop, "-") && mStyle[prop] !== undefined ) { + return prefixed == 'pfx' ? prop : true; + } + } + return false; + } + /*>>testprop*/ + + // TODO :: add testDOMProps + /** + * testDOMProps is a generic DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + */ + function testDOMProps( props, obj, elem ) { + for ( var i in props ) { + 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; } } return false; } + /*>>testallprops*/ /** * 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. */ - function testPropsAll( prop, prefixed ) { + function testPropsAll( prop, prefixed, elem ) { - var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1), - props = (prop + ' ' + domPrefixes.join(ucProp + ' ') + ucProp).split(' '); + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), + props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); - return testProps(props, prefixed); + // did they call .prefixed('boxSizing') or are we just testing a prop? + if(is(prefixed, "string") || is(prefixed, "undefined")) { + return testProps(props, prefixed); + + // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) + } else { + props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); + return testDOMProps(props, prefixed, elem); + } } - - /** - * testBundle tests a list of CSS features that require element and style injection. - * By bundling them together we can reduce the need to touch the DOM multiple times. - */ - /*>>testBundle*/ - var testBundle = (function( styles, tests ) { - var style = styles.join(''), - len = tests.length; - - injectElementWithStyles(style, function( node, rule ) { - var style = document.styleSheets[document.styleSheets.length - 1], - // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests. - // So we check for cssRules and that there is a rule available - // More here: https://github.com/Modernizr/Modernizr/issues/288 & https://github.com/Modernizr/Modernizr/issues/293 - cssText = style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || "", - children = node.childNodes, hash = {}; - - while ( len-- ) { - hash[children[len].id] = children[len]; - } - - /*>>touch*/ Modernizr['touch'] = ('ontouchstart' in window) || hash['touch'].offsetTop === 9; /*>>touch*/ - /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = hash['csstransforms3d'].offsetLeft === 9; /*>>csstransforms3d*/ - /*>>generatedcontent*/Modernizr['generatedcontent'] = hash['generatedcontent'].offsetHeight >= 1; /*>>generatedcontent*/ - /*>>fontface*/ Modernizr['fontface'] = /src/i.test(cssText) && - cssText.indexOf(rule.split(' ')[0]) === 0; /*>>fontface*/ - }, len, tests); - - })([ - // Pass in styles to be injected into document - /*>>fontface*/ '@font-face {font-family:"font";src:url("https://")}' /*>>fontface*/ - - /*>>touch*/ ,['@media (',prefixes.join('touch-enabled),('),mod,')', - '{#touch{top:9px;position:absolute}}'].join('') /*>>touch*/ - - /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')', - '{#csstransforms3d{left:9px;position:absolute}}'].join('')/*>>csstransforms3d*/ - - /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'";visibility:hidden}'].join('') /*>>generatedcontent*/ - ], - [ - /*>>fontface*/ 'fontface' /*>>fontface*/ - /*>>touch*/ ,'touch' /*>>touch*/ - /*>>csstransforms3d*/ ,'csstransforms3d' /*>>csstransforms3d*/ - /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/ - - ]);/*>>testBundle*/ + /*>>testallprops*/ /** @@ -297,53 +398,23 @@ window.Modernizr = (function( window, document, undefined ) { * ----- */ + // The *new* flexbox + // dev.w3.org/csswg/css3-flexbox + tests['flexbox'] = function() { - /** - * setPrefixedValueCSS sets the property of a specified element - * adding vendor prefixes to the VALUE of the property. - * @param {Element} element - * @param {string} property The property name. This will not be prefixed. - * @param {string} value The value of the property. This WILL be prefixed. - * @param {string=} extra Additional CSS to append unmodified to the end of - * the CSS string. - */ - function setPrefixedValueCSS( element, property, value, extra ) { - property += ':'; - element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || ''); - } + return testPropsAll('flexWrap'); + }; - /** - * setPrefixedPropertyCSS sets the property of a specified element - * adding vendor prefixes to the NAME of the property. - * @param {Element} element - * @param {string} property The property name. This WILL be prefixed. - * @param {string} value The value of the property. This will not be prefixed. - * @param {string=} extra Additional CSS to append unmodified to the end of - * the CSS string. - */ - function setPrefixedPropertyCSS( element, property, value, extra ) { - element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || ''); - } + // The *old* flexbox + // www.w3.org/TR/2009/WD-css3-flexbox-20090723/ - var c = document.createElement('div'), - elem = document.createElement('div'); - - setPrefixedValueCSS(c, 'display', 'box', 'width:42px;padding:0;'); - setPrefixedPropertyCSS(elem, 'box-flex', '1', 'width:10px;'); - - c.appendChild(elem); - docElement.appendChild(c); - - var ret = elem.offsetWidth === 42; - - c.removeChild(elem); - docElement.removeChild(c); - - return ret; + tests['flexboxlegacy'] = function() { + return testPropsAll('boxDirection'); }; // On the S60 and BB Storm, getContext exists, but always returns undefined - // http://github.com/Modernizr/Modernizr/issues/issue/97/ + // so we actually have to call getContext() to verify + // github.com/Modernizr/Modernizr/issues/issue/97/ tests['canvas'] = function() { var elem = document.createElement('canvas'); @@ -354,13 +425,11 @@ window.Modernizr = (function( window, document, undefined ) { return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function')); }; - // This WebGL test may false positive. - // But really it's quite impossible to know whether webgl will succeed until after you create the context. - // You might have hardware that can support a 100x100 webgl canvas, but will not support a 1000x1000 webgl - // canvas. So this feature inference is weak, but intentionally so. - - // It is known to false positive in FF4 with certain hardware and the iPad 2. - + // 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 + tests['webgl'] = function() { return !!window.WebGLRenderingContext; }; @@ -372,60 +441,52 @@ window.Modernizr = (function( window, document, undefined ) { * the Palm Pre / WebOS (touch) phones. * * Additionally, Chrome (desktop) used to lie about its support on this, - * but that has since been rectified: http://crbug.com/36415 + * but that has since been rectified: crbug.com/36415 * * We also test for Firefox 4 Multitouch Support. * - * For more info, see: http://modernizr.github.com/Modernizr/touch.html + * For more info, see: modernizr.github.com/Modernizr/touch.html */ tests['touch'] = function() { - return Modernizr['touch']; + 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; }; - /** - * geolocation tests for the new Geolocation API specification. - * This test is a standards compliant-only test; for more complete - * testing, including a Google Gears fallback, please see: - * http://code.google.com/p/geo-location-javascript/ - * or view a fallback solution using google's geo API: - * http://gist.github.com/366184 - */ + + // 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 + tests['geolocation'] = function() { - return !!navigator.geolocation; + return 'geolocation' in navigator; }; - // Per 1.6: - // This used to be Modernizr.crosswindowmessaging 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['postmessage'] = function() { return !!window.postMessage; }; - // Web SQL database detection is tricky: - // In chrome incognito mode, openDatabase is truthy, but using it will - // throw an exception: http://crbug.com/42380 - // We can create a dummy database, but there is no way to delete it afterwards. - - // Meanwhile, Safari users can get prompted on any database creation. - // If they do, any page with Modernizr will give them a prompt: - // http://github.com/Modernizr/Modernizr/issues/closed#issue/113 - - // We have chosen to allow the Chrome incognito false positive, so that Modernizr - // doesn't litter the web with these test databases. As a developer, you'll have - // to account for this gotcha yourself. + // Chrome incognito mode used to throw an exception when using openDatabase + // It doesn't anymore. tests['websqldatabase'] = function() { - var result = !!window.openDatabase; - /* if (result){ - try { - result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4); - } catch(e) { - } - } */ - return result; + return !!window.openDatabase; }; // Vendors had inconsistent prefixing with the experimental Indexed DB: @@ -433,12 +494,7 @@ window.Modernizr = (function( window, document, undefined ) { // - 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() { - for ( var i = -1, len = domPrefixes.length; ++i < len; ){ - if ( window[domPrefixes[i].toLowerCase() + 'IndexedDB'] ){ - return true; - } - } - return !!window.indexedDB; + return !!testPropsAll("indexedDB", window); }; // documentMode logic from YUI to filter out IE8 Compat Mode @@ -457,22 +513,20 @@ window.Modernizr = (function( window, document, undefined ) { }; tests['draganddrop'] = function() { - return isEventSupported('dragstart') && isEventSupported('drop'); + var div = document.createElement('div'); + return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div); }; - // Mozilla is targeting to land MozWebSocket for FF6 - // bugzil.la/659324 + // 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/ tests['websockets'] = function() { - for ( var i = -1, len = domPrefixes.length; ++i < len; ){ - if ( window[domPrefixes[i] + 'WebSocket'] ){ - return true; - } - } - return 'WebSocket' in window; + return 'WebSocket' in window || 'MozWebSocket' in window; }; - // http://css-tricks.com/rgba-browser-support/ + // css-tricks.com/rgba-browser-support/ tests['rgba'] = function() { // Set an rgba() color and check the returned value @@ -500,19 +554,13 @@ window.Modernizr = (function( window, document, undefined ) { // If the UA supports multiple backgrounds, there should be three occurrences // of the string "url(" in the return value for elemStyle.background - return /(url\s*\(.*?){3}/.test(mStyle.background); + return (/(url\s*\(.*?){3}/).test(mStyle.background); }; - // 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. + // this will false positive in Opera Mini + // github.com/Modernizr/Modernizr/issues/396 tests['backgroundsize'] = function() { return testPropsAll('backgroundSize'); @@ -524,7 +572,7 @@ window.Modernizr = (function( window, document, undefined ) { // Super comprehensive table about all the unique implementations of - // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance + // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance tests['borderradius'] = function() { return testPropsAll('borderRadius'); @@ -550,11 +598,14 @@ window.Modernizr = (function( window, document, undefined ) { // The non-literal . in this regex is intentional: // German Chrome returns this value as 0,55 - // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 - return /^0.55$/.test(mStyle.opacity); + // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return (/^0.55$/).test(mStyle.opacity); }; + // Note, Android < 4 will pass this test, but can only animate + // a single property at a time + // goo.gl/v3V4Gp tests['cssanimations'] = function() { return testPropsAll('animationName'); }; @@ -568,10 +619,10 @@ window.Modernizr = (function( window, document, undefined ) { tests['cssgradients'] = function() { /** * For CSS Gradients syntax, please see: - * http://webkit.org/blog/175/introducing-css-gradients/ - * https://developer.mozilla.org/en/CSS/-moz-linear-gradient - * https://developer.mozilla.org/en/CSS/-moz-radial-gradient - * http://dev.w3.org/csswg/css3-images/#gradients- + * 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- */ var str1 = 'background-image:', @@ -579,7 +630,10 @@ window.Modernizr = (function( window, document, undefined ) { str3 = 'linear-gradient(left top,#9f9, white);'; setCss( - (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0, -str1.length) + // 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) ); return contains(mStyle.backgroundImage, 'gradient'); @@ -592,44 +646,66 @@ window.Modernizr = (function( window, document, undefined ) { tests['csstransforms'] = function() { - return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']); + return !!testPropsAll('transform'); }; tests['csstransforms3d'] = function() { - var ret = !!testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']); + var ret = !!testPropsAll('perspective'); - // Webkit’s 3D transforms are passed off to the browser's own graphics renderer. + // 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 && 'webkitPerspective' in docElement.style ) { // Webkit allows this media query to succeed only if the feature is enabled. - // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` - ret = Modernizr['csstransforms3d']; + // `@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; + }); } return ret; }; tests['csstransitions'] = function() { - return testPropsAll('transitionProperty'); + return testPropsAll('transition'); }; /*>>fontface*/ // @font-face detection routine by Diego Perini - // http://javascript.nwbox.com/CSSSupport/ + // javascript.nwbox.com/CSSSupport/ + + // false positives: + // WebOS github.com/Modernizr/Modernizr/issues/342 + // WP7 github.com/Modernizr/Modernizr/issues/538 tests['fontface'] = function() { - return Modernizr['fontface']; + 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; }; /*>>fontface*/ // CSS generated content detection tests['generatedcontent'] = function() { - return Modernizr['generatedcontent']; + 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; }; @@ -641,32 +717,31 @@ window.Modernizr = (function( window, document, undefined ) { // e.g. Modernizr.video // true // Modernizr.video.ogg // 'probably' // - // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 // thx to NielsLeenheer and zcorpan - // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string. - // Modernizr does not normalize for that. + // 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 tests['video'] = function() { var elem = document.createElement('video'), bool = false; - + // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 try { if ( bool = !!elem.canPlayType ) { bool = new Boolean(bool); - bool.ogg = elem.canPlayType('video/ogg; codecs="theora"'); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,''); - // Workaround required for IE9, which doesn't report video support without audio codec specified. - // bug 599718 @ msft connect - var h264 = 'video/mp4; codecs="avc1.42E01E'; - bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"'); + // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546 + bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,''); - bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"'); + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,''); } - + } catch(e) { } - + return bool; }; @@ -674,45 +749,47 @@ window.Modernizr = (function( window, document, undefined ) { var elem = document.createElement('audio'), bool = false; - try { + try { if ( bool = !!elem.canPlayType ) { bool = new Boolean(bool); - bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"'); - bool.mp3 = elem.canPlayType('audio/mpeg;'); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''); + bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,''); // Mimetypes accepted: - // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements - // http://bit.ly/iphoneoscodecs - bool.wav = elem.canPlayType('audio/wav; codecs="1"'); - bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;'); + // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,''); + bool.m4a = ( elem.canPlayType('audio/x-m4a;') || + elem.canPlayType('audio/aac;')) .replace(/^no$/,''); } } catch(e) { } - + return bool; }; - // Firefox has made these tests rather unfun. - // 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 - // throw http://bugzil.la/365772 if cookies are disabled + // throw bugzil.la/365772 if cookies are disabled - // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning - // the property will throw an exception. http://bugzil.la/599479 - // This looks to be fixed for FF4 Final. + // 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. // Because we are forced to try/catch this, we'll go aggressive. - // FWIW: IE8 Compat mode supports these features completely: - // http://www.quirksmode.org/dom/html5.html + // Just FWIW: IE8 Compat mode supports these features completely: + // www.quirksmode.org/dom/html5.html // But IE8 doesn't support either with local files tests['localstorage'] = function() { try { - return !!localStorage.getItem; + localStorage.setItem(mod, mod); + localStorage.removeItem(mod); + return true; } catch(e) { return false; } @@ -720,8 +797,10 @@ window.Modernizr = (function( window, document, undefined ) { tests['sessionstorage'] = function() { try { - return !!sessionStorage.getItem; - } catch(e){ + sessionStorage.setItem(mod, mod); + sessionStorage.removeItem(mod); + return true; + } catch(e) { return false; } }; @@ -750,42 +829,55 @@ window.Modernizr = (function( window, document, undefined ) { return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; }; - // Thanks to F1lt3r and lucideer, ticket #35 + // SVG SMIL animation tests['smil'] = function() { - return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); + return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); }; + // 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 tests['svgclippaths'] = function() { - // Possibly returns a false positive in Safari 3.2? - return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); + return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); }; + /*>>webforms*/ // 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() { + /*>>input*/ // Run through HTML5's new input attributes to see if the UA understands any. // We're using f which is the element created early on // Mike Taylr has created a comprehensive resource for testing these attributes // when applied to all input types: - // http://miketaylr.com/code/input-type-attr.html - // spec: http://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. + // 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. // 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); } + 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); + } return attrs; })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); + /*>>input*/ + /*>>inputtypes*/ // 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 - // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/ + // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ Modernizr['inputtypes'] = (function(props) { for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { @@ -816,7 +908,7 @@ window.Modernizr = (function( window, document, undefined ) { docElement.removeChild(inputElem); } else if ( /^(search|tel)$/.test(inputElemType) ){ - // Spec doesnt define any special parsing or detectable UI + // Spec doesn't define any special parsing or detectable UI // behaviors so we pass these through as true // Interestingly, opera fails the earlier test, so it doesn't @@ -826,14 +918,6 @@ window.Modernizr = (function( window, document, undefined ) { // Real url and email support comes with prebaked validation. bool = inputElem.checkValidity && inputElem.checkValidity() === false; - } else if ( /^color$/.test(inputElemType) ) { - // chuck into DOM and force reflow for Opera bug in 11.00 - // github.com/Modernizr/Modernizr/issues#issue/159 - docElement.appendChild(inputElem); - docElement.offsetWidth; - bool = inputElem.value != smile; - docElement.removeChild(inputElem); - } else { // If the upgraded input compontent rejects the :) text, we got a winner bool = inputElem.value != smile; @@ -844,7 +928,9 @@ window.Modernizr = (function( window, document, undefined ) { } return inputs; })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); + /*>>inputtypes*/ } + /*>>webforms*/ // End of test definitions @@ -855,7 +941,7 @@ window.Modernizr = (function( window, document, undefined ) { // 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 ) { - if ( hasOwnProperty(tests, feature) ) { + if ( hasOwnProp(tests, feature) ) { // 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. @@ -866,8 +952,10 @@ window.Modernizr = (function( window, document, undefined ) { } } + /*>>webforms*/ // input tests need to run. Modernizr.input || webforms(); + /*>>webforms*/ /** @@ -879,9 +967,9 @@ window.Modernizr = (function( window, document, undefined ) { * @param test - Function returning true if feature is supported, false if not */ Modernizr.addTest = function ( feature, test ) { - if ( typeof feature == "object" ) { + if ( typeof feature == 'object' ) { for ( var key in feature ) { - if ( hasOwnProperty( feature, key ) ) { + if ( hasOwnProp( feature, key ) ) { Modernizr.addTest( key, feature[ key ] ); } } @@ -892,224 +980,426 @@ window.Modernizr = (function( window, document, undefined ) { 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: - // var re = new RegExp("\\b(no-)?" + feature + "\\b"); + // var re = new RegExp("\\b(no-)?" + feature + "\\b"); // docElement.className = docElement.className.replace( re, '' ); // but, no rly, stuff 'em. - return; + return Modernizr; } - test = typeof test == "boolean" ? test : !!test(); + test = typeof test == 'function' ? test() : test; - docElement.className += ' ' + (test ? '' : 'no-') + feature; + if (typeof enableClasses !== "undefined" && enableClasses) { + docElement.className += ' ' + (test ? '' : 'no-') + feature; + } Modernizr[feature] = test; } return Modernizr; // allow chaining. }; - + // Reset modElem.cssText to nothing to reduce memory footprint. setCss(''); modElem = inputElem = null; - //>>BEGIN IEPP - // Enable HTML 5 elements for styling (and printing) in IE. - if ( window.attachEvent && (function(){ var elem = document.createElement('div'); - elem.innerHTML = ''; - return elem.childNodes.length !== 1; })() ) { - - // iepp v2 by @jon_neal & afarkas : github.com/aFarkas/iepp/ - (function(win, doc) { - win.iepp = win.iepp || {}; - var iepp = win.iepp, - elems = iepp.html5elements || 'abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', - elemsArr = elems.split('|'), - elemsArrLen = elemsArr.length, - elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'), - tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'), - filterReg = /^\s*[\{\}]\s*$/, - ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'), - docFrag = doc.createDocumentFragment(), - html = doc.documentElement, - head = html.firstChild, - bodyElem = doc.createElement('body'), - styleElem = doc.createElement('style'), - printMedias = /print|all/, - body; - function shim(doc) { - var a = -1; - while (++a < elemsArrLen) - // Use createElement so IE allows HTML5-named elements in a document - doc.createElement(elemsArr[a]); + /*>>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 = ''; + //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; } - iepp.getCSS = function(styleSheetList, mediaType) { - if(styleSheetList+'' === undefined){return '';} - var a = -1, - len = styleSheetList.length, - styleSheet, - cssTextArr = []; - while (++a < len) { - styleSheet = styleSheetList[a]; - //currently no test for disabled/alternate stylesheets - if(styleSheet.disabled){continue;} - mediaType = styleSheet.media || mediaType; - // Get css from all non-screen stylesheets and their imports - if (printMedias.test(mediaType)) cssTextArr.push(iepp.getCSS(styleSheet.imports, mediaType), styleSheet.cssText); - //reset mediaType to all with every new *not imported* stylesheet - mediaType = 'all'; + }()); + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a style sheet with the given CSS text and adds it to the document. + * @private + * @param {Document} ownerDocument The document. + * @param {String} cssText The CSS text. + * @returns {StyleSheet} The style element. + */ + function addStyleSheet(ownerDocument, cssText) { + var p = ownerDocument.createElement('p'), + parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; + + p.innerHTML = 'x'; + return parent.insertBefore(p.lastChild, parent.firstChild); + } + + /** + * Returns the value of `html5.elements` as an array. + * @private + * @returns {Array} An array of shived element node names. + */ + function getElements() { + var elements = html5.elements; + return typeof elements == 'string' ? elements.split(' ') : elements; + } + + /** + * Returns the data associated to the given document + * @private + * @param {Document} ownerDocument The document. + * @returns {Object} An object of data. + */ + function getExpandoData(ownerDocument) { + var data = expandoData[ownerDocument[expando]]; + if (!data) { + data = {}; + expanID++; + ownerDocument[expando] = expanID; + expandoData[expanID] = data; + } + return data; + } + + /** + * returns a shived element for the given nodeName and document + * @memberOf html5 + * @param {String} nodeName name of the element + * @param {Document} ownerDocument The context document. + * @returns {Object} The shived element. + */ + function createElement(nodeName, ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createElement(nodeName); + } + if (!data) { + data = getExpandoData(ownerDocument); + } + var node; + + if (data.cache[nodeName]) { + node = data.cache[nodeName].cloneNode(); + } else if (saveClones.test(nodeName)) { + node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); + } else { + node = data.createElem(nodeName); + } + + // Avoid adding some elements to fragments in IE < 9 because + // * Attributes like `name` or `type` cannot be set/changed once an element + // is inserted into a document/fragment + // * Link elements with `src` attributes that are inaccessible, as with + // a 403 response, will cause the tab/window to crash + // * Script elements appended to fragments will execute when their `src` + // or `text` property is set + return node.canHaveChildren && !reSkip.test(nodeName) && !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 which is print-safe and shouldn't conflict since it isn't part of html5 - bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font'); - }; + /*--------------------------------------------------------------------------*/ + /** + * 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); - iepp._beforePrint = function() { - // Write iepp custom print CSS - styleElem.styleSheet.cssText = iepp.parseCSS(iepp.getCSS(doc.styleSheets, 'all')); - iepp.writeHTML(); - }; + 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; + } - iepp.restoreHTML = function(){ - // Undo everything done in onbeforeprint - bodyElem.innerHTML = ''; - html.removeChild(bodyElem); - html.appendChild(body); - }; + /*--------------------------------------------------------------------------*/ - iepp._afterPrint = function(){ - // Undo everything done in onbeforeprint - iepp.restoreHTML(); - styleElem.styleSheet.cssText = ''; - }; + /** + * 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, - // Shim the document and iepp fragment - shim(doc); - shim(docFrag); + /** + * A flag to indicate that the HTML5 style sheet should be inserted. + * @memberOf html5 + * @type Boolean + */ + 'shivCSS': (options.shivCSS !== false), - // - if(iepp.disablePP){return;} + /** + * Is equal to true if a browser supports creating unknown/HTML5 elements + * @memberOf html5 + * @type boolean + */ + 'supportsUnknownElements': supportsUnknownElements, - // Add iepp custom print style element - head.insertBefore(styleElem, head.firstChild); - styleElem.media = 'print'; - styleElem.className = 'iepp-printshim'; - win.attachEvent( - 'onbeforeprint', - iepp._beforePrint - ); - win.attachEvent( - 'onafterprint', - iepp._afterPrint - ); - })(window, document); - } - //>>END IEPP + /** + * 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*/ // 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 + /*>>prefixes*/ Modernizr._prefixes = prefixes; + /*>>prefixes*/ + /*>>domprefixes*/ Modernizr._domPrefixes = domPrefixes; - + Modernizr._cssomPrefixes = cssomPrefixes; + /*>>domprefixes*/ + + /*>>mq*/ // 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. - // * You must specify values. Eg. If you are testing support for the min-width media query use: + // * You must specify values. Eg. If you are testing support for the min-width media query use: // Modernizr.mq('(min-width:0)') // usage: // Modernizr.mq('only screen and (max-width:768)') - Modernizr.mq = testMediaQuery; - + Modernizr.mq = testMediaQuery; + /*>>mq*/ + + /*>>hasevent*/ // Modernizr.hasEvent() detects support for a given event, with an optional element to test on // Modernizr.hasEvent('gesturestart', elem) - Modernizr.hasEvent = isEventSupported; + Modernizr.hasEvent = isEventSupported; + /*>>hasevent*/ + /*>>testprop*/ // 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]); - }; + }; + /*>>testprop*/ + /*>>testallprops*/ // 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') - Modernizr.testAllProps = testPropsAll; + // Modernizr.testAllProps('boxSizing') + Modernizr.testAllProps = testPropsAll; + /*>>testallprops*/ - + /*>>teststyles*/ // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... }) - Modernizr.testStyles = injectElementWithStyles; + Modernizr.testStyles = injectElementWithStyles; + /*>>teststyles*/ + /*>>prefixed*/ // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input // Modernizr.prefixed('boxSizing') // 'MozBoxSizing' - + // 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-'); - + // If you're trying to ascertain which transition end event to bind to, you might do something like... - // + // // var transEndEventNames = { // 'WebkitTransition' : 'webkitTransitionEnd', // 'MozTransition' : 'transitionend', // 'OTransition' : 'oTransitionEnd', - // 'msTransition' : 'msTransitionEnd', // maybe? - // 'transition' : 'transitionEnd' + // 'msTransition' : 'MSTransitionEnd', + // 'transition' : 'transitionend' // }, // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; - - Modernizr.prefixed = function(prop){ - return testPropsAll(prop, 'pfx'); + + 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*/ - + /*>>cssclasses*/ // Remove "no-js" class from element, if it exists: - docElement.className = docElement.className.replace(/\bno-js\b/, '') - + docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + + // Add the new classes to the element. - + (enableClasses ? ' js ' + classes.join(' ') : ''); + (enableClasses ? ' js ' + classes.join(' ') : ''); + /*>>cssclasses*/ return Modernizr;