diff --git a/feature-detects/css/resize.js b/feature-detects/css/resize.js index 14719b6039..34135659f5 100644 --- a/feature-detects/css/resize.js +++ b/feature-detects/css/resize.js @@ -1,7 +1,17 @@ +/*! +{ + "name": "CSS UI Resize", + "property": "cssresize", + "tags": ["css"], + "notes": [{ + "name": "W3C Specification", + "href": "http://www.w3.org/TR/css3-ui/#resize" + },{ + "name": "MDN Docs", + "href": "https://developer.mozilla.org/en/CSS/resize" + }] +} +!*/ define(['Modernizr', 'testAllProps'], function( Modernizr, testAllProps ) { - // Test for CSS 3 UI "resize" property - // http://www.w3.org/TR/css3-ui/#resize - // https://developer.mozilla.org/en/CSS/resize - Modernizr.addTest('cssresize', testAllProps('resize')); }); diff --git a/feature-detects/css/rgba.js b/feature-detects/css/rgba.js index 0c149dd32f..6ed1236aaa 100644 --- a/feature-detects/css/rgba.js +++ b/feature-detects/css/rgba.js @@ -1,6 +1,15 @@ +/*! +{ + "name": "CSS rgba", + "property": "rgba", + "tags": ["css"], + "notes": [{ + "name": "CSSTricks Tutorial", + "href": "http://css-tricks.com/rgba-browser-support/" + }] +} +!*/ define(['Modernizr', 'createElement'], function( Modernizr, createElement ) { - // css-tricks.com/rgba-browser-support/ - Modernizr.addTest('rgba', function() { var elem = createElement('div'); var style = elem.style; diff --git a/feature-detects/css/subpixelfont.js b/feature-detects/css/subpixelfont.js index e1cd97aa3c..d9d0ec5124 100644 --- a/feature-detects/css/subpixelfont.js +++ b/feature-detects/css/subpixelfont.js @@ -1,9 +1,24 @@ +/*! +{ + "name": "CSS Subpixel Fonts", + "property": "subpixelfont", + "tags": ["css"], + "authors": [ + "@derSchepp", + "@gerritvanaaken", + "@rodneyrehm", + "@yatil", + "@ryanseddon" + ], + "notes": [{ + "name": "Origin Test", + "href": "https://github.com/gerritvanaaken/subpixeldetect" + }] +} +!*/ define(['Modernizr', 'testStyles'], function( Modernizr, testStyles ) { /* - * Test for SubPixel Font Rendering * (to infer if GDI or DirectWrite is used on Windows) - * Authors: @derSchepp, @gerritvanaaken, @rodneyrehm, @yatil, @ryanseddon - * Web: https://github.com/gerritvanaaken/subpixeldetect */ testStyles( '#modernizr{position: absolute; top: -10em; visibility:hidden; font: normal 10px arial;}#subpixel{float: left; font-size: 33.3333%;}', diff --git a/feature-detects/css/supports.js b/feature-detects/css/supports.js index bb49dbe360..f2dff51790 100644 --- a/feature-detects/css/supports.js +++ b/feature-detects/css/supports.js @@ -1,8 +1,22 @@ +/*! +{ + "name": "CSS Supports", + "property": "supports", + "tags": ["css"], + "notes": [{ + "name": "W3 Spec", + "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports" + },{ + "name": "Related Github Issue", + "href": "github.com/Modernizr/Modernizr/issues/648" + },{ + "name": "W3 Info", + "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface" + }] +} +!*/ define(['Modernizr'], function( Modernizr ) { - // http://dev.w3.org/csswg/css3-conditional/#at-supports - // github.com/Modernizr/Modernizr/issues/648 // Relies on the fact that a browser vendor should expose the CSSSupportsRule interface - // http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface - Modernizr.addTest('supports','CSSSupportsRule' in window); + Modernizr.addTest('supports', 'CSSSupportsRule' in window); }); diff --git a/feature-detects/css/textshadow.js b/feature-detects/css/textshadow.js index c90d835f19..479e62775e 100644 --- a/feature-detects/css/textshadow.js +++ b/feature-detects/css/textshadow.js @@ -1,4 +1,11 @@ +/*! +{ + "name": "CSS textshadow", + "property": "textshadow", + "tags": ["css"], + "knownBugs": ["FF3.0 will false positive on this test"] +} +!*/ define(['Modernizr', 'createElement'], function( Modernizr, createElement ) { - // FF3.0 will false positive on this test Modernizr.addTest('textshadow', createElement('div').style.textShadow === ''); }); diff --git a/feature-detects/css/transforms.js b/feature-detects/css/transforms.js index c2723cf977..95a6cad7af 100644 --- a/feature-detects/css/transforms.js +++ b/feature-detects/css/transforms.js @@ -1,3 +1,10 @@ +/*! +{ + "name": "CSS Transforms", + "property": "csstransforms", + "tags": ["css"] +} +!*/ define(['Modernizr', 'testAllProps'], function( Modernizr, testAllProps ) { Modernizr.addTest('csstransforms', !!testAllProps('transform')); }); diff --git a/feature-detects/css/transforms3d.js b/feature-detects/css/transforms3d.js index 68c79cad3f..509da4b8c2 100644 --- a/feature-detects/css/transforms3d.js +++ b/feature-detects/css/transforms3d.js @@ -1,3 +1,10 @@ +/*! +{ + "name": "CSS Transforms 3D", + "property": "csstransforms3d", + "tags": ["css"] +} +!*/ define(['Modernizr', 'testAllProps', 'testStyles', 'docElement'], function( Modernizr, testAllProps, testStyles, docElement ) { Modernizr.addTest('csstransforms3d', function() { var ret = !!testAllProps('perspective'); @@ -15,6 +22,7 @@ define(['Modernizr', 'testAllProps', 'testStyles', 'docElement'], function( Mode ret = node.offsetLeft === 9 && node.offsetHeight === 5; }); } + return ret; }); }); diff --git a/feature-detects/css/transitions.js b/feature-detects/css/transitions.js index cd547eaaeb..e6b5ce599e 100644 --- a/feature-detects/css/transitions.js +++ b/feature-detects/css/transitions.js @@ -1,3 +1,10 @@ +/*! +{ + "name": "CSS Transitions", + "property": "csstransitions", + "tags": ["css"] +} +!*/ define(['Modernizr', 'testAllProps'], function( Modernizr, testAllProps ) { Modernizr.addTest('csstransitions', testAllProps('transition')); }); diff --git a/feature-detects/css/userselect.js b/feature-detects/css/userselect.js index 92684521ea..345a83db1e 100644 --- a/feature-detects/css/userselect.js +++ b/feature-detects/css/userselect.js @@ -1,7 +1,15 @@ +/*! +{ + "name": "CSS user-select", + "property": "userselect", + "authors": ["ryan seddon"], + "tags": ["css"], + "notes": [{ + "name": "Related Modernizr Issue", + "href": "https://github.com/Modernizr/Modernizr/issues/250" + }] +} +!*/ define(['Modernizr', 'testAllProps'], function( Modernizr, testAllProps ) { - // -moz-user-select:none test. - // by ryan seddon - //https://github.com/Modernizr/Modernizr/issues/250 - Modernizr.addTest('userselect', testAllProps('userSelect')); }); diff --git a/feature-detects/css/vhunit.js b/feature-detects/css/vhunit.js index c2e04a6b1e..35228cfdec 100644 --- a/feature-detects/css/vhunit.js +++ b/feature-detects/css/vhunit.js @@ -1,6 +1,18 @@ +/*! +{ + "name": "CSS vh unit", + "property": "cssvhunit", + "tags": ["css"], + "notes": [{ + "name": "Related Modernizr Issue", + "href": "https://github.com/Modernizr/Modernizr/issues/572" + },{ + "name": "Similar JSFiddle", + "href": "http://jsfiddle.net/FWeinb/etnYC/" + }] +} +!*/ define(['Modernizr', 'testStyles'], function( Modernizr, testStyles ) { - // https://github.com/Modernizr/Modernizr/issues/572 - // Similar to http://jsfiddle.net/FWeinb/etnYC/ testStyles('#modernizr { height: 50vh; }', function( elem, rule ) { var height = parseInt(window.innerHeight/2,10); var compStyle = parseInt((window.getComputedStyle ? diff --git a/feature-detects/css/vmaxunit.js b/feature-detects/css/vmaxunit.js index dd527c539e..158b95ac63 100644 --- a/feature-detects/css/vmaxunit.js +++ b/feature-detects/css/vmaxunit.js @@ -1,6 +1,18 @@ +/*! +{ + "name": "CSS vmax unit", + "property": "cssvmaxunit", + "tags": ["css"], + "notes": [{ + "name": "Related Modernizr Issue", + "href": "https://github.com/Modernizr/Modernizr/issues/572" + },{ + "name": "JSFiddle Example", + "href": "http://jsfiddle.net/glsee/JDsWQ/4/" + }] +} +!*/ define(['Modernizr', 'testStyles'], function( Modernizr, testStyles ) { - // https://github.com/Modernizr/Modernizr/issues/572 - // http://jsfiddle.net/glsee/JDsWQ/4/ testStyles('#modernizr { width: 50vmax; }', function( elem, rule ) { var one_vw = window.innerWidth/100; var one_vh = window.innerHeight/100; diff --git a/feature-detects/css/vminunit.js b/feature-detects/css/vminunit.js index 0dbbeb592b..bf9ab25922 100644 --- a/feature-detects/css/vminunit.js +++ b/feature-detects/css/vminunit.js @@ -1,6 +1,18 @@ +/*! +{ + "name": "CSS vmin unit", + "property": "cssvminunit", + "tags": ["css"], + "notes": [{ + "name": "Related Modernizr Issue", + "href": "https://github.com/Modernizr/Modernizr/issues/572" + },{ + "name": "JSFiddle Example", + "href": "http://jsfiddle.net/glsee/JRmdq/8/" + }] +} +!*/ define(['Modernizr', 'testStyles'], function( Modernizr, testStyles ) { - // https://github.com/Modernizr/Modernizr/issues/572 - // http://jsfiddle.net/glsee/JRmdq/8/ testStyles('#modernizr { width: 50vmin; }', function( elem, rule ) { var one_vw = window.innerWidth/100; var one_vh = window.innerHeight/100; diff --git a/feature-detects/css/vwunit.js b/feature-detects/css/vwunit.js index de96c2f87a..3bfd16ff61 100644 --- a/feature-detects/css/vwunit.js +++ b/feature-detects/css/vwunit.js @@ -1,6 +1,18 @@ +/*! +{ + "name": "CSS vw unit", + "property": "cssvwunit", + "tags": ["css"], + "notes": [{ + "name": "Related Modernizr Issue", + "href": "https://github.com/Modernizr/Modernizr/issues/572" + },{ + "name": "JSFiddle Example", + "href": "http://jsfiddle.net/FWeinb/etnYC/" + }] +} +!*/ define(['Modernizr', 'testStyles'], function( Modernizr, testStyles ) { - // https://github.com/Modernizr/Modernizr/issues/572 - // http://jsfiddle.net/FWeinb/etnYC/ testStyles('#modernizr { width: 50vw; }', function( elem, rule ) { var width = parseInt(window.innerWidth/2,10); var compStyle = parseInt((window.getComputedStyle ? diff --git a/feature-detects/css/wrapflow.js b/feature-detects/css/wrapflow.js index 22d38d96eb..cd005c745b 100644 --- a/feature-detects/css/wrapflow.js +++ b/feature-detects/css/wrapflow.js @@ -1,6 +1,18 @@ +/*! +{ + "name": "CSS wrap-flow", + "property": "wrapflow", + "tags": ["css"], + "notes": [{ + "name": "W3C Exclusions Spec", + "href": "http://www.w3.org/TR/css3-exclusions" + },{ + "name": "Example by Adobe", + "href": "http://html.adobe.com/webstandards/cssexclusions" + }] +} +!*/ define(['Modernizr', 'prefixed', 'docElement', 'createElement'], function( Modernizr, prefixed, docElement, createElement ) { - // http://www.w3.org/TR/css3-exclusions - // Examples: http://html.adobe.com/webstandards/cssexclusions // Separate test for `wrap-flow` property as IE10 has just implemented this alone Modernizr.addTest('wrapflow', function () { var prefixedProperty = prefixed('wrapFlow'); diff --git a/readme.md b/readme.md index 79eea9d03d..6c3b1034be 100644 --- a/readme.md +++ b/readme.md @@ -9,6 +9,29 @@ Modernizr tests which native CSS3 and HTML5 features are available in the curren Modernizr has an optional (*not included*) conditional resource loader called `Modernizr.load()`, based on [Yepnope.js](http://yepnopejs.com). You can get a build that includes `Modernizr.load()`, as well as choosing which feature tests to include on the [Download page](http://www.modernizr.com/download/). +## New Asynchronous Event Listeners + +Often times people want to know when an asynchronous test is done so they can allow their application to react to it. +In the past, you've had to rely on watching properties or `` classes. Only events on **asynchronous** tests are +supported. Synchronous tests should be handled synchronously for speed and consistency reasons. + +The new api looks like this: + +```javascript +// Listen to a test, give it a callback +Modernizr.on('testname', function( result ) { + if (result) { + console.log('The test passed!'); + } + else { + console.log('The test failed!'); + } +}); +``` + +We guarantee that we'll only invoke your function once (per time that you call `on`). We are currently not exposing +a method for exposing the `trigger` functionality. Instead, if you'd like to have control over async tests, use the +`src/addTest` feature, and any test that you set will automatically expose and trigger the `on` functionality. ## Test suite diff --git a/src/ModernizrProto.js b/src/ModernizrProto.js index ddd8db52f7..06d2344df0 100644 --- a/src/ModernizrProto.js +++ b/src/ModernizrProto.js @@ -1,22 +1,37 @@ define(['tests'], function ( tests ) { var ModernizrProto = { // The current version, dummy - _version : 'v3.0.0pre', + _version: 'v3.0.0pre', // Any settings that don't work as separate modules // can go in here as configuration. - _config : { + _config: { classPrefix : '', enableClasses : true }, - _q : [], + // Queue of tests + _q: [], - addTest : function( name, fn, options ) { + // Stub these for people who are listening + on: function( test, cb ) { + // I don't really think people should do this, but we can + // safe guard it a bit. + // -- NOTE:: this gets WAY overridden in src/addTest for + // actual async tests. This is in case people listen to + // synchronous tests. I would leave it out, but the code + // to *disallow* sync tests in the real version of this + // function is actually larger than this. + setTimeout(function() { + cb(this[test]); + }, 0); + }, + + addTest: function( name, fn, options ) { tests.push({name : name, fn : fn, options : options }); }, - addAsyncTest : function (fn) { + addAsyncTest: function (fn) { tests.push({name : null, fn : fn}); } }; diff --git a/src/addTest.js b/src/addTest.js index 64b2a3442d..d04fc9b48e 100644 --- a/src/addTest.js +++ b/src/addTest.js @@ -1,4 +1,53 @@ define(['ModernizrProto', 'Modernizr', 'hasOwnProp', 'setClasses'], function( ModernizrProto, Modernizr, hasOwnProp, setClasses ) { + // As far as I can think of, we shouldn't need or + // allow 'on' for non-async tests, and you can't do + // async tests without this 'addTest' module. + + // Listeners for async or post-run tests + ModernizrProto._l = {}; + + // 'addTest' implies a test after the core runloop, + // So we'll add in the events + ModernizrProto.on = function( test, cb ) { + // Create the list of listeners if it doesn't exist + if (!this._l[test]) { + this._l[test] = []; + } + + // Push this test on to the listener list + this._l[test].push(cb); + + // If it's already been resolved, trigger it on next tick + if (Modernizr.hasOwnProperty(test)) { + // Next Tick + setTimeout(function() { + Modernizr._trigger(test, Modernizr[test]); + }, 0); + } + }; + + ModernizrProto._trigger = function( test, res ) { + if (!this._l[test]) { + return; + } + + var cbs = this._l[test]; + var cb; + var i; + + /* jshint -W083 */ + for (i = 0; i < cbs.length; i++) { + cb = cbs[i]; + // Force async + setTimeout(function() { + cb(res); + },0); + } + + // Don't trigger these again + delete this._l[test]; + }; + /** * addTest allows the user to define their own feature tests * the result will be added onto the Modernizr object, @@ -29,10 +78,14 @@ define(['ModernizrProto', 'Modernizr', 'hasOwnProp', 'setClasses'], function( Mo test = typeof test == 'function' ? test() : test; + // Set the value (this is the magic, right here). Modernizr[feature] = test; // Set a single class (either `feature` or `no-feature`) setClasses([(test ? '' : 'no-') + feature]); + + // Trigger the event + Modernizr._trigger(feature, test); } return Modernizr; // allow chaining.