source: ether_statistics/web/resources/js/Wijmo.2.2.2/Wijmo-Open/development-bundle/samples/explore/js/modernizr-2.5.3.js @ 649

Last change on this file since 649 was 627, checked in by vmipsl, 12 years ago

wijmo

File size: 47.0 KB
Line 
1/*!
2 * Modernizr v2.5.3
3 * www.modernizr.com
4 *
5 * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
6 * Available under the BSD and MIT licenses: www.modernizr.com/license/
7 */
8
9/*
10 * Modernizr tests which native CSS3 and HTML5 features are available in
11 * the current UA and makes the results available to you in two ways:
12 * as properties on a global Modernizr object, and as classes on the
13 * <html> element. This information allows you to progressively enhance
14 * your pages with a granular level of control over the experience.
15 *
16 * Modernizr has an optional (not included) conditional resource loader
17 * called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
18 * To get a build that includes Modernizr.load(), as well as choosing
19 * which tests to include, go to www.modernizr.com/download/
20 *
21 * Authors        Faruk Ates, Paul Irish, Alex Sexton
22 * Contributors   Ryan Seddon, Ben Alman
23 */
24
25window.Modernizr = (function( window, document, undefined ) {
26
27    var version = '2.5.3',
28
29    Modernizr = {},
30   
31    // option for enabling the HTML classes to be added
32    enableClasses = true,
33
34    docElement = document.documentElement,
35
36    /**
37     * Create our "modernizr" element that we do most feature tests on.
38     */
39    mod = 'modernizr',
40    modElem = document.createElement(mod),
41    mStyle = modElem.style,
42
43    /**
44     * Create the input element for various Web Forms feature tests.
45     */
46    inputElem = document.createElement('input'),
47
48    smile = ':)',
49
50    toString = {}.toString,
51
52    // List of property values to set for css tests. See ticket #21
53    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
54
55    // Following spec is to expose vendor-specific style properties as:
56    //   elem.style.WebkitBorderRadius
57    // and the following would be incorrect:
58    //   elem.style.webkitBorderRadius
59
60    // Webkit ghosts their properties in lowercase but Opera & Moz do not.
61    // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
62    //   erik.eae.net/archives/2008/03/10/21.48.10/
63
64    // More here: github.com/Modernizr/Modernizr/issues/issue/21
65    omPrefixes = 'Webkit Moz O ms',
66
67    cssomPrefixes = omPrefixes.split(' '),
68
69    domPrefixes = omPrefixes.toLowerCase().split(' '),
70
71    ns = {'svg': 'http://www.w3.org/2000/svg'},
72
73    tests = {},
74    inputs = {},
75    attrs = {},
76
77    classes = [],
78
79    slice = classes.slice,
80
81    featureName, // used in testing loop
82
83
84    // Inject element with style element and some CSS rules
85    injectElementWithStyles = function( rule, callback, nodes, testnames ) {
86
87      var style, ret, node,
88          div = document.createElement('div'),
89          // After page load injecting a fake body doesn't work so check if body exists
90          body = document.body, 
91          // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
92          fakeBody = body ? body : document.createElement('body');
93
94      if ( parseInt(nodes, 10) ) {
95          // In order not to give false positives we create a node for each test
96          // This also allows the method to scale for unspecified uses
97          while ( nodes-- ) {
98              node = document.createElement('div');
99              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
100              div.appendChild(node);
101          }
102      }
103
104      // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
105      // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
106      // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
107      // msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
108      // Documents served as xml will throw if using &shy; so use xml friendly encoded version. See issue #277
109      style = ['&#173;','<style>', rule, '</style>'].join('');
110      div.id = mod;
111      // 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.
112      // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
113      fakeBody.innerHTML += style;
114      fakeBody.appendChild(div);
115      if(!body){
116          //avoid crashing IE8, if background image is used
117          fakeBody.style.background = "";
118          docElement.appendChild(fakeBody);
119      }
120
121      ret = callback(div, rule);
122      // If this is done after page load we don't want to remove the body so check if body exists
123      !body ? fakeBody.parentNode.removeChild(fakeBody) : div.parentNode.removeChild(div);
124
125      return !!ret;
126
127    },
128
129
130    // adapted from matchMedia polyfill
131    // by Scott Jehl and Paul Irish
132    // gist.github.com/786768
133    testMediaQuery = function( mq ) {
134
135      var matchMedia = window.matchMedia || window.msMatchMedia;
136      if ( matchMedia ) {
137        return matchMedia(mq).matches;
138      }
139
140      var bool;
141
142      injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
143        bool = (window.getComputedStyle ?
144                  getComputedStyle(node, null) :
145                  node.currentStyle)['position'] == 'absolute';
146      });
147
148      return bool;
149
150     },
151
152
153    /**
154      * isEventSupported determines if a given element supports the given event
155      * function from yura.thinkweb2.com/isEventSupported/
156      */
157    isEventSupported = (function() {
158
159      var TAGNAMES = {
160        'select': 'input', 'change': 'input',
161        'submit': 'form', 'reset': 'form',
162        'error': 'img', 'load': 'img', 'abort': 'img'
163      };
164
165      function isEventSupported( eventName, element ) {
166
167        element = element || document.createElement(TAGNAMES[eventName] || 'div');
168        eventName = 'on' + eventName;
169
170        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
171        var isSupported = eventName in element;
172
173        if ( !isSupported ) {
174          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
175          if ( !element.setAttribute ) {
176            element = document.createElement('div');
177          }
178          if ( element.setAttribute && element.removeAttribute ) {
179            element.setAttribute(eventName, '');
180            isSupported = is(element[eventName], 'function');
181
182            // If property was created, "remove it" (by setting value to `undefined`)
183            if ( !is(element[eventName], 'undefined') ) {
184              element[eventName] = undefined;
185            }
186            element.removeAttribute(eventName);
187          }
188        }
189
190        element = null;
191        return isSupported;
192      }
193      return isEventSupported;
194    })();
195
196    // hasOwnProperty shim by kangax needed for Safari 2.0 support
197    var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty;
198    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
199      hasOwnProperty = function (object, property) {
200        return _hasOwnProperty.call(object, property);
201      };
202    }
203    else {
204      hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
205        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
206      };
207    }
208
209    // Taken from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
210    // ES-5 15.3.4.5
211    // http://es5.github.com/#x15.3.4.5
212
213    if (!Function.prototype.bind) {
214     
215      Function.prototype.bind = function bind(that) {
216       
217        var target = this;
218       
219        if (typeof target != "function") {
220            throw new TypeError();
221        }
222       
223        var args = slice.call(arguments, 1),
224            bound = function () {
225
226            if (this instanceof bound) {
227             
228              var F = function(){};
229              F.prototype = target.prototype;
230              var self = new F;
231
232              var result = target.apply(
233                  self,
234                  args.concat(slice.call(arguments))
235              );
236              if (Object(result) === result) {
237                  return result;
238              }
239              return self;
240
241            } else {
242             
243              return target.apply(
244                  that,
245                  args.concat(slice.call(arguments))
246              );
247
248            }
249
250        };
251       
252        return bound;
253      };
254    }
255
256    /**
257     * setCss applies given styles to the Modernizr DOM node.
258     */
259    function setCss( str ) {
260        mStyle.cssText = str;
261    }
262
263    /**
264     * setCssAll extrapolates all vendor-specific css strings.
265     */
266    function setCssAll( str1, str2 ) {
267        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
268    }
269
270    /**
271     * is returns a boolean for if typeof obj is exactly type.
272     */
273    function is( obj, type ) {
274        return typeof obj === type;
275    }
276
277    /**
278     * contains returns a boolean for if substr is found within str.
279     */
280    function contains( str, substr ) {
281        return !!~('' + str).indexOf(substr);
282    }
283
284    /**
285     * testProps is a generic CSS / DOM property test; if a browser supports
286     *   a certain property, it won't return undefined for it.
287     *   A supported CSS property returns empty string when its not yet set.
288     */
289    function testProps( props, prefixed ) {
290        for ( var i in props ) {
291            if ( mStyle[ props[i] ] !== undefined ) {
292                return prefixed == 'pfx' ? props[i] : true;
293            }
294        }
295        return false;
296    }
297
298    /**
299     * testDOMProps is a generic DOM property test; if a browser supports
300     *   a certain property, it won't return undefined for it.
301     */
302    function testDOMProps( props, obj, elem ) {
303        for ( var i in props ) {
304            var item = obj[props[i]];
305            if ( item !== undefined) {
306
307                // return the property name as a string
308                if (elem === false) return props[i];
309
310                // let's bind a function
311                if (is(item, 'function')){
312                  // default to autobind unless override
313                  return item.bind(elem || obj);
314                }
315               
316                // return the unbound function or obj or value
317                return item;
318            }
319        }
320        return false;
321    }
322
323    /**
324     * testPropsAll tests a list of DOM properties we want to check against.
325     *   We specify literally ALL possible (known and/or likely) properties on
326     *   the element including the non-vendor prefixed one, for forward-
327     *   compatibility.
328     */
329    function testPropsAll( prop, prefixed, elem ) {
330
331        var ucProp  = prop.charAt(0).toUpperCase() + prop.substr(1),
332            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
333
334        // did they call .prefixed('boxSizing') or are we just testing a prop?
335        if(is(prefixed, "string") || is(prefixed, "undefined")) {
336          return testProps(props, prefixed);
337
338        // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
339        } else {
340          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
341          return testDOMProps(props, prefixed, elem);
342        }
343    }
344
345    /**
346     * testBundle tests a list of CSS features that require element and style injection.
347     *   By bundling them together we can reduce the need to touch the DOM multiple times.
348     */
349    /*>>testBundle*/
350    var testBundle = (function( styles, tests ) {
351        var style = styles.join(''),
352            len = tests.length;
353
354        injectElementWithStyles(style, function( node, rule ) {
355            var style = document.styleSheets[document.styleSheets.length - 1],
356                // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests.
357                // So we check for cssRules and that there is a rule available
358                // More here: github.com/Modernizr/Modernizr/issues/288 & github.com/Modernizr/Modernizr/issues/293
359                cssText = style ? (style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || '') : '',
360                children = node.childNodes, hash = {};
361
362            while ( len-- ) {
363                hash[children[len].id] = children[len];
364            }
365
366             /*>>touch*/          Modernizr['touch'] = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch || (hash['touch'] && hash['touch'].offsetTop) === 9; /*>>touch*/
367            /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = (hash['csstransforms3d'] && hash['csstransforms3d'].offsetLeft) === 9 && hash['csstransforms3d'].offsetHeight === 3;          /*>>csstransforms3d*/
368            /*>>generatedcontent*/Modernizr['generatedcontent'] = (hash['generatedcontent'] && hash['generatedcontent'].offsetHeight) >= 1;       /*>>generatedcontent*/
369            /*>>fontface*/        Modernizr['fontface'] = /src/i.test(cssText) &&
370                                                                  cssText.indexOf(rule.split(' ')[0]) === 0;        /*>>fontface*/
371        }, len, tests);
372
373    })([
374        // Pass in styles to be injected into document
375        /*>>fontface*/        '@font-face {font-family:"font";src:url("https://")}'         /*>>fontface*/
376       
377        /*>>touch*/           ,['@media (',prefixes.join('touch-enabled),('),mod,')',
378                                '{#touch{top:9px;position:absolute}}'].join('')           /*>>touch*/
379                               
380        /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')',
381                                '{#csstransforms3d{left:9px;position:absolute;height:3px;}}'].join('')/*>>csstransforms3d*/
382                               
383        /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'";visibility:hidden}'].join('')  /*>>generatedcontent*/
384    ],
385      [
386        /*>>fontface*/        'fontface'          /*>>fontface*/
387        /*>>touch*/           ,'touch'            /*>>touch*/
388        /*>>csstransforms3d*/ ,'csstransforms3d'  /*>>csstransforms3d*/
389        /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/
390       
391    ]);/*>>testBundle*/
392
393
394    /**
395     * Tests
396     * -----
397     */
398
399    // The *new* flexbox
400    // dev.w3.org/csswg/css3-flexbox
401
402    tests['flexbox'] = function() {
403      return testPropsAll('flexOrder');
404    };
405
406    // The *old* flexbox
407    // www.w3.org/TR/2009/WD-css3-flexbox-20090723/
408
409    tests['flexbox-legacy'] = function() {
410        return testPropsAll('boxDirection');
411    };
412
413    // On the S60 and BB Storm, getContext exists, but always returns undefined
414    // so we actually have to call getContext() to verify
415    // github.com/Modernizr/Modernizr/issues/issue/97/
416
417    tests['canvas'] = function() {
418        var elem = document.createElement('canvas');
419        return !!(elem.getContext && elem.getContext('2d'));
420    };
421
422    tests['canvastext'] = function() {
423        return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
424    };
425
426    // this test initiates a new webgl context.
427    // webk.it/70117 is tracking a legit feature detect proposal
428   
429    tests['webgl'] = function() {
430        try {
431            var canvas = document.createElement('canvas'),
432                ret;
433            ret = !!(window.WebGLRenderingContext && (canvas.getContext('experimental-webgl') || canvas.getContext('webgl')));
434            canvas = undefined;
435        } catch (e){
436            ret = false;
437        }
438        return ret;
439    };
440
441    /*
442     * The Modernizr.touch test only indicates if the browser supports
443     *    touch events, which does not necessarily reflect a touchscreen
444     *    device, as evidenced by tablets running Windows 7 or, alas,
445     *    the Palm Pre / WebOS (touch) phones.
446     *
447     * Additionally, Chrome (desktop) used to lie about its support on this,
448     *    but that has since been rectified: crbug.com/36415
449     *
450     * We also test for Firefox 4 Multitouch Support.
451     *
452     * For more info, see: modernizr.github.com/Modernizr/touch.html
453     */
454
455    tests['touch'] = function() {
456        return Modernizr['touch'];
457    };
458
459    /**
460     * geolocation tests for the new Geolocation API specification.
461     *   This test is a standards compliant-only test; for more complete
462     *   testing, including a Google Gears fallback, please see:
463     *   code.google.com/p/geo-location-javascript/
464     * or view a fallback solution using google's geo API:
465     *   gist.github.com/366184
466     */
467    tests['geolocation'] = function() {
468        return !!navigator.geolocation;
469    };
470
471    // Per 1.6:
472    // This used to be Modernizr.crosswindowmessaging but the longer
473    // name has been deprecated in favor of a shorter and property-matching one.
474    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
475    // and in the first release thereafter disappear entirely.
476    tests['postmessage'] = function() {
477      return !!window.postMessage;
478    };
479
480
481    // Chrome incognito mode used to throw an exception when using openDatabase
482    // It doesn't anymore.
483    tests['websqldatabase'] = function() {
484      return !!window.openDatabase;
485    };
486
487    // Vendors had inconsistent prefixing with the experimental Indexed DB:
488    // - Webkit's implementation is accessible through webkitIndexedDB
489    // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
490    // For speed, we don't test the legacy (and beta-only) indexedDB
491    tests['indexedDB'] = function() {
492      return !!testPropsAll("indexedDB",window);
493    };
494
495    // documentMode logic from YUI to filter out IE8 Compat Mode
496    //   which false positives.
497    tests['hashchange'] = function() {
498      return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
499    };
500
501    // Per 1.6:
502    // This used to be Modernizr.historymanagement but the longer
503    // name has been deprecated in favor of a shorter and property-matching one.
504    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
505    // and in the first release thereafter disappear entirely.
506    tests['history'] = function() {
507      return !!(window.history && history.pushState);
508    };
509
510    tests['draganddrop'] = function() {
511        var div = document.createElement('div');
512        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
513    };
514
515    // FIXME: Once FF10 is sunsetted, we can drop prefixed MozWebSocket
516    // bugzil.la/695635
517    tests['websockets'] = function() {
518        for ( var i = -1, len = cssomPrefixes.length; ++i < len; ){
519          if ( window[cssomPrefixes[i] + 'WebSocket'] ){
520            return true;
521          }
522        }
523        return 'WebSocket' in window;
524    };
525
526
527    // css-tricks.com/rgba-browser-support/
528    tests['rgba'] = function() {
529        // Set an rgba() color and check the returned value
530
531        setCss('background-color:rgba(150,255,150,.5)');
532
533        return contains(mStyle.backgroundColor, 'rgba');
534    };
535
536    tests['hsla'] = function() {
537        // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
538        //   except IE9 who retains it as hsla
539
540        setCss('background-color:hsla(120,40%,100%,.5)');
541
542        return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
543    };
544
545    tests['multiplebgs'] = function() {
546        // Setting multiple images AND a color on the background shorthand property
547        //  and then querying the style.background property value for the number of
548        //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
549
550        setCss('background:url(https://),url(https://),red url(https://)');
551
552        // If the UA supports multiple backgrounds, there should be three occurrences
553        //   of the string "url(" in the return value for elemStyle.background
554
555        return /(url\s*\(.*?){3}/.test(mStyle.background);
556    };
557
558
559    // In testing support for a given CSS property, it's legit to test:
560    //    `elem.style[styleName] !== undefined`
561    // If the property is supported it will return an empty string,
562    // if unsupported it will return undefined.
563
564    // We'll take advantage of this quick test and skip setting a style
565    // on our modernizr element, but instead just testing undefined vs
566    // empty string.
567
568
569    tests['backgroundsize'] = function() {
570        return testPropsAll('backgroundSize');
571    };
572
573    tests['borderimage'] = function() {
574        return testPropsAll('borderImage');
575    };
576
577
578    // Super comprehensive table about all the unique implementations of
579    // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
580
581    tests['borderradius'] = function() {
582        return testPropsAll('borderRadius');
583    };
584
585    // WebOS unfortunately false positives on this test.
586    tests['boxshadow'] = function() {
587        return testPropsAll('boxShadow');
588    };
589
590    // FF3.0 will false positive on this test
591    tests['textshadow'] = function() {
592        return document.createElement('div').style.textShadow === '';
593    };
594
595
596    tests['opacity'] = function() {
597        // Browsers that actually have CSS Opacity implemented have done so
598        //  according to spec, which means their return values are within the
599        //  range of [0.0,1.0] - including the leading zero.
600
601        setCssAll('opacity:.55');
602
603        // The non-literal . in this regex is intentional:
604        //   German Chrome returns this value as 0,55
605        // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
606        return /^0.55$/.test(mStyle.opacity);
607    };
608
609
610    // Note, Android < 4 will pass this test, but can only animate
611    //   a single property at a time
612    //   daneden.me/2011/12/putting-up-with-androids-bullshit/
613    tests['cssanimations'] = function() {
614        return testPropsAll('animationName');
615    };
616
617
618    tests['csscolumns'] = function() {
619        return testPropsAll('columnCount');
620    };
621
622
623    tests['cssgradients'] = function() {
624        /**
625         * For CSS Gradients syntax, please see:
626         * webkit.org/blog/175/introducing-css-gradients/
627         * developer.mozilla.org/en/CSS/-moz-linear-gradient
628         * developer.mozilla.org/en/CSS/-moz-radial-gradient
629         * dev.w3.org/csswg/css3-images/#gradients-
630         */
631
632        var str1 = 'background-image:',
633            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
634            str3 = 'linear-gradient(left top,#9f9, white);';
635
636        setCss(
637             // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
638              (str1 + '-webkit- '.split(' ').join(str2 + str1) 
639             // standard syntax             // trailing 'background-image:'
640              + prefixes.join(str3 + str1)).slice(0, -str1.length)
641        );
642
643        return contains(mStyle.backgroundImage, 'gradient');
644    };
645
646
647    tests['cssreflections'] = function() {
648        return testPropsAll('boxReflect');
649    };
650
651
652    tests['csstransforms'] = function() {
653        return !!testPropsAll('transform');
654    };
655
656
657    tests['csstransforms3d'] = function() {
658
659        var ret = !!testPropsAll('perspective');
660
661        // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
662        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
663        //   some conditions. As a result, Webkit typically recognizes the syntax but
664        //   will sometimes throw a false positive, thus we must do a more thorough check:
665        if ( ret && 'webkitPerspective' in docElement.style ) {
666
667          // Webkit allows this media query to succeed only if the feature is enabled.
668          // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }`
669          ret = Modernizr['csstransforms3d'];
670        }
671        return ret;
672    };
673
674
675    tests['csstransitions'] = function() {
676        return testPropsAll('transition');
677    };
678
679
680    /*>>fontface*/
681    // @font-face detection routine by Diego Perini
682    // javascript.nwbox.com/CSSSupport/
683
684    // false positives in WebOS: github.com/Modernizr/Modernizr/issues/342
685    tests['fontface'] = function() {
686        return Modernizr['fontface'];
687    };
688    /*>>fontface*/
689
690    // CSS generated content detection
691    tests['generatedcontent'] = function() {
692        return Modernizr['generatedcontent'];
693    };
694
695
696
697    // These tests evaluate support of the video/audio elements, as well as
698    // testing what types of content they support.
699    //
700    // We're using the Boolean constructor here, so that we can extend the value
701    // e.g.  Modernizr.video     // true
702    //       Modernizr.video.ogg // 'probably'
703    //
704    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
705    //                     thx to NielsLeenheer and zcorpan
706
707    // Note: in some older browsers, "no" was a return value instead of empty string.
708    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
709    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
710
711    tests['video'] = function() {
712        var elem = document.createElement('video'),
713            bool = false;
714           
715        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
716        try {
717            if ( bool = !!elem.canPlayType ) {
718                bool      = new Boolean(bool);
719                bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"')      .replace(/^no$/,'');
720
721                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
722
723                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
724            }
725           
726        } catch(e) { }
727       
728        return bool;
729    };
730
731    tests['audio'] = function() {
732        var elem = document.createElement('audio'),
733            bool = false;
734
735        try { 
736            if ( bool = !!elem.canPlayType ) {
737                bool      = new Boolean(bool);
738                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
739                bool.mp3  = elem.canPlayType('audio/mpeg;')               .replace(/^no$/,'');
740
741                // Mimetypes accepted:
742                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
743                //   bit.ly/iphoneoscodecs
744                bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/,'');
745                bool.m4a  = ( elem.canPlayType('audio/x-m4a;')            || 
746                              elem.canPlayType('audio/aac;'))             .replace(/^no$/,'');
747            }
748        } catch(e) { }
749       
750        return bool;
751    };
752
753
754    // In FF4, if disabled, window.localStorage should === null.
755
756    // Normally, we could not test that directly and need to do a
757    //   `('localStorage' in window) && ` test first because otherwise Firefox will
758    //   throw bugzil.la/365772 if cookies are disabled
759
760    // Also in iOS5 Private Browsing mode, attepting to use localStorage.setItem
761    // will throw the exception:
762    //   QUOTA_EXCEEDED_ERRROR DOM Exception 22.
763    // Peculiarly, getItem and removeItem calls do not throw.
764
765    // Because we are forced to try/catch this, we'll go aggressive.
766
767    // Just FWIW: IE8 Compat mode supports these features completely:
768    //   www.quirksmode.org/dom/html5.html
769    // But IE8 doesn't support either with local files
770
771    tests['localstorage'] = function() {
772        try {
773            localStorage.setItem(mod, mod);
774            localStorage.removeItem(mod);
775            return true;
776        } catch(e) {
777            return false;
778        }
779    };
780
781    tests['sessionstorage'] = function() {
782        try {
783            sessionStorage.setItem(mod, mod);
784            sessionStorage.removeItem(mod);
785            return true;
786        } catch(e) {
787            return false;
788        }
789    };
790
791
792    tests['webworkers'] = function() {
793        return !!window.Worker;
794    };
795
796
797    tests['applicationcache'] = function() {
798        return !!window.applicationCache;
799    };
800
801
802    // Thanks to Erik Dahlstrom
803    tests['svg'] = function() {
804        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
805    };
806
807    // specifically for SVG inline in HTML, not within XHTML
808    // test page: paulirish.com/demo/inline-svg
809    tests['inlinesvg'] = function() {
810      var div = document.createElement('div');
811      div.innerHTML = '<svg/>';
812      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
813    };
814
815    // SVG SMIL animation
816    tests['smil'] = function() {
817        return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
818    };
819
820    // This test is only for clip paths in SVG proper, not clip paths on HTML content
821    // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
822
823    // However read the comments to dig into applying SVG clippaths to HTML content here:
824    //   github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
825    tests['svgclippaths'] = function() {
826        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
827    };
828
829    // input features and input types go directly onto the ret object, bypassing the tests loop.
830    // Hold this guy to execute in a moment.
831    function webforms() {
832        // Run through HTML5's new input attributes to see if the UA understands any.
833        // We're using f which is the <input> element created early on
834        // Mike Taylr has created a comprehensive resource for testing these attributes
835        //   when applied to all input types:
836        //   miketaylr.com/code/input-type-attr.html
837        // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
838       
839        // Only input placeholder is tested while textarea's placeholder is not.
840        // Currently Safari 4 and Opera 11 have support only for the input placeholder
841        // Both tests are available in feature-detects/forms-placeholder.js
842        Modernizr['input'] = (function( props ) {
843            for ( var i = 0, len = props.length; i < len; i++ ) {
844                attrs[ props[i] ] = !!(props[i] in inputElem);
845            }
846            if (attrs.list){
847              // safari false positive's on datalist: webk.it/74252
848              // see also github.com/Modernizr/Modernizr/issues/146
849              attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
850            }
851            return attrs;
852        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
853
854        // Run through HTML5's new input types to see if the UA understands any.
855        //   This is put behind the tests runloop because it doesn't return a
856        //   true/false like all the other tests; instead, it returns an object
857        //   containing each input type with its corresponding true/false value
858
859        // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
860        Modernizr['inputtypes'] = (function(props) {
861
862            for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
863
864                inputElem.setAttribute('type', inputElemType = props[i]);
865                bool = inputElem.type !== 'text';
866
867                // We first check to see if the type we give it sticks..
868                // If the type does, we feed it a textual value, which shouldn't be valid.
869                // If the value doesn't stick, we know there's input sanitization which infers a custom UI
870                if ( bool ) {
871
872                    inputElem.value         = smile;
873                    inputElem.style.cssText = 'position:absolute;visibility:hidden;';
874
875                    if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
876
877                      docElement.appendChild(inputElem);
878                      defaultView = document.defaultView;
879
880                      // Safari 2-4 allows the smiley as a value, despite making a slider
881                      bool =  defaultView.getComputedStyle &&
882                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
883                              // Mobile android web browser has false positive, so must
884                              // check the height to see if the widget is actually there.
885                              (inputElem.offsetHeight !== 0);
886
887                      docElement.removeChild(inputElem);
888
889                    } else if ( /^(search|tel)$/.test(inputElemType) ){
890                      // Spec doesnt define any special parsing or detectable UI
891                      //   behaviors so we pass these through as true
892
893                      // Interestingly, opera fails the earlier test, so it doesn't
894                      //  even make it here.
895
896                    } else if ( /^(url|email)$/.test(inputElemType) ) {
897                      // Real url and email support comes with prebaked validation.
898                      bool = inputElem.checkValidity && inputElem.checkValidity() === false;
899
900                    } else if ( /^color$/.test(inputElemType) ) {
901                        // chuck into DOM and force reflow for Opera bug in 11.00
902                        // github.com/Modernizr/Modernizr/issues#issue/159
903                        docElement.appendChild(inputElem);
904                        docElement.offsetWidth;
905                        bool = inputElem.value != smile;
906                        docElement.removeChild(inputElem);
907
908                    } else {
909                      // If the upgraded input compontent rejects the :) text, we got a winner
910                      bool = inputElem.value != smile;
911                    }
912                }
913
914                inputs[ props[i] ] = !!bool;
915            }
916            return inputs;
917        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
918    }
919
920
921    // End of test definitions
922    // -----------------------
923
924
925
926    // Run through all tests and detect their support in the current UA.
927    // todo: hypothetically we could be doing an array of tests and use a basic loop here.
928    for ( var feature in tests ) {
929        if ( hasOwnProperty(tests, feature) ) {
930            // run the test, throw the return value into the Modernizr,
931            //   then based on that boolean, define an appropriate className
932            //   and push it into an array of classes we'll join later.
933            featureName  = feature.toLowerCase();
934            Modernizr[featureName] = tests[feature]();
935
936            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
937        }
938    }
939
940    // input tests need to run.
941    Modernizr.input || webforms();
942
943
944    /**
945     * addTest allows the user to define their own feature tests
946     * the result will be added onto the Modernizr object,
947     * as well as an appropriate className set on the html element
948     *
949     * @param feature - String naming the feature
950     * @param test - Function returning true if feature is supported, false if not
951     */
952     Modernizr.addTest = function ( feature, test ) {
953       if ( typeof feature == 'object' ) {
954         for ( var key in feature ) {
955           if ( hasOwnProperty( feature, key ) ) {
956             Modernizr.addTest( key, feature[ key ] );
957           }
958         }
959       } else {
960
961         feature = feature.toLowerCase();
962
963         if ( Modernizr[feature] !== undefined ) {
964           // we're going to quit if you're trying to overwrite an existing test
965           // if we were to allow it, we'd do this:
966           //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
967           //   docElement.className = docElement.className.replace( re, '' );
968           // but, no rly, stuff 'em.
969           return Modernizr;
970         }
971
972         test = typeof test == 'function' ? test() : test;
973
974         docElement.className += ' ' + (test ? '' : 'no-') + feature;
975         Modernizr[feature] = test;
976
977       }
978
979       return Modernizr; // allow chaining.
980     };
981
982
983    // Reset modElem.cssText to nothing to reduce memory footprint.
984    setCss('');
985    modElem = inputElem = null;
986
987    //>>BEGIN IEPP
988    // Enable HTML 5 elements for styling in IE & add HTML5 css
989    /*! HTML5 Shiv v3.4 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
990    ;(function(window, document) {
991   
992      /** Preset options */
993      var options = window.html5 || {};
994   
995      /** Used to skip problem elements */
996      var reSkip = /^<|^(?:button|form|map|select|textarea)$/i;
997   
998      /** Detect whether the browser supports default html5 styles */
999      var supportsHtml5Styles;
1000   
1001      /** Detect whether the browser supports unknown elements */
1002      var supportsUnknownElements;
1003   
1004      (function() {
1005        var a = document.createElement('a');
1006   
1007        a.innerHTML = '<xyz></xyz>';
1008   
1009        //if the hidden property is implemented we can assume, that the browser supports HTML5 Styles
1010        supportsHtml5Styles = ('hidden' in a);
1011        supportsUnknownElements = a.childNodes.length == 1 || (function() {
1012          // assign a false positive if unable to shiv
1013          try {
1014            (document.createElement)('a');
1015          } catch(e) {
1016            return true;
1017          }
1018          var frag = document.createDocumentFragment();
1019          return (
1020            typeof frag.cloneNode == 'undefined' ||
1021            typeof frag.createDocumentFragment == 'undefined' ||
1022            typeof frag.createElement == 'undefined'
1023          );
1024        }());
1025   
1026      }());
1027   
1028      /*--------------------------------------------------------------------------*/
1029   
1030      /**
1031       * Creates a style sheet with the given CSS text and adds it to the document.
1032       * @private
1033       * @param {Document} ownerDocument The document.
1034       * @param {String} cssText The CSS text.
1035       * @returns {StyleSheet} The style element.
1036       */
1037      function addStyleSheet(ownerDocument, cssText) {
1038        var p = ownerDocument.createElement('p'),
1039            parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
1040   
1041        p.innerHTML = 'x<style>' + cssText + '</style>';
1042        return parent.insertBefore(p.lastChild, parent.firstChild);
1043      }
1044   
1045      /**
1046       * Returns the value of `html5.elements` as an array.
1047       * @private
1048       * @returns {Array} An array of shived element node names.
1049       */
1050      function getElements() {
1051        var elements = html5.elements;
1052        return typeof elements == 'string' ? elements.split(' ') : elements;
1053      }
1054   
1055      /**
1056       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
1057       * @private
1058       * @param {Document|DocumentFragment} ownerDocument The document.
1059       */
1060      function shivMethods(ownerDocument) {
1061        var cache = {},
1062            docCreateElement = ownerDocument.createElement,
1063            docCreateFragment = ownerDocument.createDocumentFragment,
1064            frag = docCreateFragment();
1065   
1066        ownerDocument.createElement = function(nodeName) {
1067          // Avoid adding some elements to fragments in IE < 9 because
1068          // * Attributes like `name` or `type` cannot be set/changed once an element
1069          //   is inserted into a document/fragment
1070          // * Link elements with `src` attributes that are inaccessible, as with
1071          //   a 403 response, will cause the tab/window to crash
1072          // * Script elements appended to fragments will execute when their `src`
1073          //   or `text` property is set
1074          var node = (cache[nodeName] || (cache[nodeName] = docCreateElement(nodeName))).cloneNode();
1075          return html5.shivMethods && node.canHaveChildren && !reSkip.test(nodeName) ? frag.appendChild(node) : node;
1076        };
1077   
1078        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
1079          'var n=f.cloneNode(),c=n.createElement;' +
1080          'h.shivMethods&&(' +
1081            // unroll the `createElement` calls
1082            getElements().join().replace(/\w+/g, function(nodeName) {
1083              cache[nodeName] = docCreateElement(nodeName);
1084              frag.createElement(nodeName);
1085              return 'c("' + nodeName + '")';
1086            }) +
1087          ');return n}'
1088        )(html5, frag);
1089      }
1090   
1091      /*--------------------------------------------------------------------------*/
1092   
1093      /**
1094       * Shivs the given document.
1095       * @memberOf html5
1096       * @param {Document} ownerDocument The document to shiv.
1097       * @returns {Document} The shived document.
1098       */
1099      function shivDocument(ownerDocument) {
1100        var shived;
1101        if (ownerDocument.documentShived) {
1102          return ownerDocument;
1103        }
1104        if (html5.shivCSS && !supportsHtml5Styles) {
1105          shived = !!addStyleSheet(ownerDocument,
1106            // corrects block display not defined in IE6/7/8/9
1107            'article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}' +
1108            // corrects audio display not defined in IE6/7/8/9
1109            'audio{display:none}' +
1110            // corrects canvas and video display not defined in IE6/7/8/9
1111            'canvas,video{display:inline-block;*display:inline;*zoom:1}' +
1112            // corrects 'hidden' attribute and audio[controls] display not present in IE7/8/9
1113            '[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}' +
1114            // adds styling not present in IE6/7/8/9
1115            'mark{background:#FF0;color:#000}'
1116          );
1117        }
1118        if (!supportsUnknownElements) {
1119          shived = !shivMethods(ownerDocument);
1120        }
1121        if (shived) {
1122          ownerDocument.documentShived = shived;
1123        }
1124        return ownerDocument;
1125      }
1126   
1127      /*--------------------------------------------------------------------------*/
1128   
1129      /**
1130       * The `html5` object is exposed so that more elements can be shived and
1131       * existing shiving can be detected on iframes.
1132       * @type Object
1133       * @example
1134       *
1135       * // options can be changed before the script is included
1136       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
1137       */
1138      var html5 = {
1139   
1140        /**
1141         * An array or space separated string of node names of the elements to shiv.
1142         * @memberOf html5
1143         * @type Array|String
1144         */
1145        'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video',
1146   
1147        /**
1148         * A flag to indicate that the HTML5 style sheet should be inserted.
1149         * @memberOf html5
1150         * @type Boolean
1151         */
1152        'shivCSS': !(options.shivCSS === false),
1153   
1154        /**
1155         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
1156         * methods should be overwritten.
1157         * @memberOf html5
1158         * @type Boolean
1159         */
1160        'shivMethods': !(options.shivMethods === false),
1161   
1162        /**
1163         * A string to describe the type of `html5` object ("default" or "default print").
1164         * @memberOf html5
1165         * @type String
1166         */
1167        'type': 'default',
1168   
1169        // shivs the document according to the specified `html5` object options
1170        'shivDocument': shivDocument
1171      };
1172   
1173      /*--------------------------------------------------------------------------*/
1174   
1175      // expose html5
1176      window.html5 = html5;
1177   
1178      // shiv the document
1179      shivDocument(document);
1180   
1181    }(this, document));
1182
1183    //>>END IEPP
1184
1185    // Assign private properties to the return object with prefix
1186    Modernizr._version      = version;
1187
1188    // expose these for the plugin API. Look in the source for how to join() them against your input
1189    Modernizr._prefixes     = prefixes;
1190    Modernizr._domPrefixes  = domPrefixes;
1191    Modernizr._cssomPrefixes  = cssomPrefixes;
1192   
1193    // Modernizr.mq tests a given media query, live against the current state of the window
1194    // A few important notes:
1195    //   * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
1196    //   * A max-width or orientation query will be evaluated against the current state, which may change later.
1197    //   * You must specify values. Eg. If you are testing support for the min-width media query use:
1198    //       Modernizr.mq('(min-width:0)')
1199    // usage:
1200    // Modernizr.mq('only screen and (max-width:768)')
1201    Modernizr.mq            = testMediaQuery;   
1202   
1203    // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
1204    // Modernizr.hasEvent('gesturestart', elem)
1205    Modernizr.hasEvent      = isEventSupported; 
1206
1207    // Modernizr.testProp() investigates whether a given style property is recognized
1208    // Note that the property names must be provided in the camelCase variant.
1209    // Modernizr.testProp('pointerEvents')
1210    Modernizr.testProp      = function(prop){
1211        return testProps([prop]);
1212    };       
1213
1214    // Modernizr.testAllProps() investigates whether a given style property,
1215    //   or any of its vendor-prefixed variants, is recognized
1216    // Note that the property names must be provided in the camelCase variant.
1217    // Modernizr.testAllProps('boxSizing')   
1218    Modernizr.testAllProps  = testPropsAll;     
1219
1220
1221   
1222    // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
1223    // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
1224    Modernizr.testStyles    = injectElementWithStyles; 
1225
1226
1227    // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
1228    // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
1229   
1230    // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
1231    // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
1232    //
1233    //     str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
1234   
1235    // If you're trying to ascertain which transition end event to bind to, you might do something like...
1236    //
1237    //     var transEndEventNames = {
1238    //       'WebkitTransition' : 'webkitTransitionEnd',
1239    //       'MozTransition'    : 'transitionend',
1240    //       'OTransition'      : 'oTransitionEnd',
1241    //       'msTransition'     : 'MsTransitionEnd',
1242    //       'transition'       : 'transitionend'
1243    //     },
1244    //     transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
1245   
1246    Modernizr.prefixed      = function(prop, obj, elem){
1247      if(!obj) {
1248        return testPropsAll(prop, 'pfx');
1249      } else {
1250        // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
1251        return testPropsAll(prop, obj, elem);
1252      }
1253    };
1254
1255
1256
1257    // Remove "no-js" class from <html> element, if it exists:
1258    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
1259                           
1260                            // Add the new classes to the <html> element.
1261                            (enableClasses ? ' js ' + classes.join(' ') : '');
1262
1263    return Modernizr;
1264
1265})(this, this.document);
Note: See TracBrowser for help on using the repository browser.