snfn 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1116 @@
1
+ /*!
2
+ * Modernizr v2.0.6
3
+ * http://www.modernizr.com
4
+ *
5
+ * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton
6
+ * Dual-licensed under the BSD or 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
+
25
+ window.Modernizr = (function( window, document, undefined ) {
26
+
27
+ var version = '2.0.6',
28
+
29
+ Modernizr = {},
30
+
31
+ // option for enabling the HTML classes to be added
32
+ enableClasses = true,
33
+
34
+ docElement = document.documentElement,
35
+ docHead = document.head || document.getElementsByTagName('head')[0],
36
+
37
+ /**
38
+ * Create our "modernizr" element that we do most feature tests on.
39
+ */
40
+ mod = 'modernizr',
41
+ modElem = document.createElement(mod),
42
+ mStyle = modElem.style,
43
+
44
+ /**
45
+ * Create the input element for various Web Forms feature tests.
46
+ */
47
+ inputElem = document.createElement('input'),
48
+
49
+ smile = ':)',
50
+
51
+ toString = Object.prototype.toString,
52
+
53
+ // List of property values to set for css tests. See ticket #21
54
+ prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '),
55
+
56
+ // Following spec is to expose vendor-specific style properties as:
57
+ // elem.style.WebkitBorderRadius
58
+ // and the following would be incorrect:
59
+ // elem.style.webkitBorderRadius
60
+
61
+ // Webkit ghosts their properties in lowercase but Opera & Moz do not.
62
+ // Microsoft foregoes prefixes entirely <= IE8, but appears to
63
+ // use a lowercase `ms` instead of the correct `Ms` in IE9
64
+
65
+ // More here: http://github.com/Modernizr/Modernizr/issues/issue/21
66
+ domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
67
+
68
+ ns = {'svg': 'http://www.w3.org/2000/svg'},
69
+
70
+ tests = {},
71
+ inputs = {},
72
+ attrs = {},
73
+
74
+ classes = [],
75
+
76
+ featureName, // used in testing loop
77
+
78
+
79
+ // Inject element with style element and some CSS rules
80
+ injectElementWithStyles = function( rule, callback, nodes, testnames ) {
81
+
82
+ var style, ret, node,
83
+ div = document.createElement('div');
84
+
85
+ if ( parseInt(nodes, 10) ) {
86
+ // In order not to give false positives we create a node for each test
87
+ // This also allows the method to scale for unspecified uses
88
+ while ( nodes-- ) {
89
+ node = document.createElement('div');
90
+ node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
91
+ div.appendChild(node);
92
+ }
93
+ }
94
+
95
+ // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
96
+ // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
97
+ // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
98
+ // http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
99
+ style = ['&shy;', '<style>', rule, '</style>'].join('');
100
+ div.id = mod;
101
+ div.innerHTML += style;
102
+ docElement.appendChild(div);
103
+
104
+ ret = callback(div, rule);
105
+ div.parentNode.removeChild(div);
106
+
107
+ return !!ret;
108
+
109
+ },
110
+
111
+
112
+ // adapted from matchMedia polyfill
113
+ // by Scott Jehl and Paul Irish
114
+ // gist.github.com/786768
115
+ testMediaQuery = function( mq ) {
116
+
117
+ if ( window.matchMedia ) {
118
+ return matchMedia(mq).matches;
119
+ }
120
+
121
+ var bool;
122
+
123
+ injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
124
+ bool = (window.getComputedStyle ?
125
+ getComputedStyle(node, null) :
126
+ node.currentStyle)['position'] == 'absolute';
127
+ });
128
+
129
+ return bool;
130
+
131
+ },
132
+
133
+
134
+ /**
135
+ * isEventSupported determines if a given element supports the given event
136
+ * function from http://yura.thinkweb2.com/isEventSupported/
137
+ */
138
+ isEventSupported = (function() {
139
+
140
+ var TAGNAMES = {
141
+ 'select': 'input', 'change': 'input',
142
+ 'submit': 'form', 'reset': 'form',
143
+ 'error': 'img', 'load': 'img', 'abort': 'img'
144
+ };
145
+
146
+ function isEventSupported( eventName, element ) {
147
+
148
+ element = element || document.createElement(TAGNAMES[eventName] || 'div');
149
+ eventName = 'on' + eventName;
150
+
151
+ // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
152
+ var isSupported = eventName in element;
153
+
154
+ if ( !isSupported ) {
155
+ // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
156
+ if ( !element.setAttribute ) {
157
+ element = document.createElement('div');
158
+ }
159
+ if ( element.setAttribute && element.removeAttribute ) {
160
+ element.setAttribute(eventName, '');
161
+ isSupported = is(element[eventName], 'function');
162
+
163
+ // If property was created, "remove it" (by setting value to `undefined`)
164
+ if ( !is(element[eventName], undefined) ) {
165
+ element[eventName] = undefined;
166
+ }
167
+ element.removeAttribute(eventName);
168
+ }
169
+ }
170
+
171
+ element = null;
172
+ return isSupported;
173
+ }
174
+ return isEventSupported;
175
+ })();
176
+
177
+ // hasOwnProperty shim by kangax needed for Safari 2.0 support
178
+ var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty;
179
+ if ( !is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined) ) {
180
+ hasOwnProperty = function (object, property) {
181
+ return _hasOwnProperty.call(object, property);
182
+ };
183
+ }
184
+ else {
185
+ hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
186
+ return ((property in object) && is(object.constructor.prototype[property], undefined));
187
+ };
188
+ }
189
+
190
+ /**
191
+ * setCss applies given styles to the Modernizr DOM node.
192
+ */
193
+ function setCss( str ) {
194
+ mStyle.cssText = str;
195
+ }
196
+
197
+ /**
198
+ * setCssAll extrapolates all vendor-specific css strings.
199
+ */
200
+ function setCssAll( str1, str2 ) {
201
+ return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
202
+ }
203
+
204
+ /**
205
+ * is returns a boolean for if typeof obj is exactly type.
206
+ */
207
+ function is( obj, type ) {
208
+ return typeof obj === type;
209
+ }
210
+
211
+ /**
212
+ * contains returns a boolean for if substr is found within str.
213
+ */
214
+ function contains( str, substr ) {
215
+ return !!~('' + str).indexOf(substr);
216
+ }
217
+
218
+ /**
219
+ * testProps is a generic CSS / DOM property test; if a browser supports
220
+ * a certain property, it won't return undefined for it.
221
+ * A supported CSS property returns empty string when its not yet set.
222
+ */
223
+ function testProps( props, prefixed ) {
224
+ for ( var i in props ) {
225
+ if ( mStyle[ props[i] ] !== undefined ) {
226
+ return prefixed == 'pfx' ? props[i] : true;
227
+ }
228
+ }
229
+ return false;
230
+ }
231
+
232
+ /**
233
+ * testPropsAll tests a list of DOM properties we want to check against.
234
+ * We specify literally ALL possible (known and/or likely) properties on
235
+ * the element including the non-vendor prefixed one, for forward-
236
+ * compatibility.
237
+ */
238
+ function testPropsAll( prop, prefixed ) {
239
+
240
+ var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
241
+ props = (prop + ' ' + domPrefixes.join(ucProp + ' ') + ucProp).split(' ');
242
+
243
+ return testProps(props, prefixed);
244
+ }
245
+
246
+ /**
247
+ * testBundle tests a list of CSS features that require element and style injection.
248
+ * By bundling them together we can reduce the need to touch the DOM multiple times.
249
+ */
250
+ /*>>testBundle*/
251
+ var testBundle = (function( styles, tests ) {
252
+ var style = styles.join(''),
253
+ len = tests.length;
254
+
255
+ injectElementWithStyles(style, function( node, rule ) {
256
+ var style = document.styleSheets[document.styleSheets.length - 1],
257
+ // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests.
258
+ // So we check for cssRules and that there is a rule available
259
+ // More here: https://github.com/Modernizr/Modernizr/issues/288 & https://github.com/Modernizr/Modernizr/issues/293
260
+ cssText = style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || "",
261
+ children = node.childNodes, hash = {};
262
+
263
+ while ( len-- ) {
264
+ hash[children[len].id] = children[len];
265
+ }
266
+
267
+ /*>>touch*/ Modernizr['touch'] = ('ontouchstart' in window) || hash['touch'].offsetTop === 9; /*>>touch*/
268
+ /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = hash['csstransforms3d'].offsetLeft === 9; /*>>csstransforms3d*/
269
+ /*>>generatedcontent*/Modernizr['generatedcontent'] = hash['generatedcontent'].offsetHeight >= 1; /*>>generatedcontent*/
270
+ /*>>fontface*/ Modernizr['fontface'] = /src/i.test(cssText) &&
271
+ cssText.indexOf(rule.split(' ')[0]) === 0; /*>>fontface*/
272
+ }, len, tests);
273
+
274
+ })([
275
+ // Pass in styles to be injected into document
276
+ /*>>fontface*/ '@font-face {font-family:"font";src:url("https://")}' /*>>fontface*/
277
+
278
+ /*>>touch*/ ,['@media (',prefixes.join('touch-enabled),('),mod,')',
279
+ '{#touch{top:9px;position:absolute}}'].join('') /*>>touch*/
280
+
281
+ /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')',
282
+ '{#csstransforms3d{left:9px;position:absolute}}'].join('')/*>>csstransforms3d*/
283
+
284
+ /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'";visibility:hidden}'].join('') /*>>generatedcontent*/
285
+ ],
286
+ [
287
+ /*>>fontface*/ 'fontface' /*>>fontface*/
288
+ /*>>touch*/ ,'touch' /*>>touch*/
289
+ /*>>csstransforms3d*/ ,'csstransforms3d' /*>>csstransforms3d*/
290
+ /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/
291
+
292
+ ]);/*>>testBundle*/
293
+
294
+
295
+ /**
296
+ * Tests
297
+ * -----
298
+ */
299
+
300
+ tests['flexbox'] = function() {
301
+ /**
302
+ * setPrefixedValueCSS sets the property of a specified element
303
+ * adding vendor prefixes to the VALUE of the property.
304
+ * @param {Element} element
305
+ * @param {string} property The property name. This will not be prefixed.
306
+ * @param {string} value The value of the property. This WILL be prefixed.
307
+ * @param {string=} extra Additional CSS to append unmodified to the end of
308
+ * the CSS string.
309
+ */
310
+ function setPrefixedValueCSS( element, property, value, extra ) {
311
+ property += ':';
312
+ element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || '');
313
+ }
314
+
315
+ /**
316
+ * setPrefixedPropertyCSS sets the property of a specified element
317
+ * adding vendor prefixes to the NAME of the property.
318
+ * @param {Element} element
319
+ * @param {string} property The property name. This WILL be prefixed.
320
+ * @param {string} value The value of the property. This will not be prefixed.
321
+ * @param {string=} extra Additional CSS to append unmodified to the end of
322
+ * the CSS string.
323
+ */
324
+ function setPrefixedPropertyCSS( element, property, value, extra ) {
325
+ element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || '');
326
+ }
327
+
328
+ var c = document.createElement('div'),
329
+ elem = document.createElement('div');
330
+
331
+ setPrefixedValueCSS(c, 'display', 'box', 'width:42px;padding:0;');
332
+ setPrefixedPropertyCSS(elem, 'box-flex', '1', 'width:10px;');
333
+
334
+ c.appendChild(elem);
335
+ docElement.appendChild(c);
336
+
337
+ var ret = elem.offsetWidth === 42;
338
+
339
+ c.removeChild(elem);
340
+ docElement.removeChild(c);
341
+
342
+ return ret;
343
+ };
344
+
345
+ // On the S60 and BB Storm, getContext exists, but always returns undefined
346
+ // http://github.com/Modernizr/Modernizr/issues/issue/97/
347
+
348
+ tests['canvas'] = function() {
349
+ var elem = document.createElement('canvas');
350
+ return !!(elem.getContext && elem.getContext('2d'));
351
+ };
352
+
353
+ tests['canvastext'] = function() {
354
+ return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
355
+ };
356
+
357
+ // This WebGL test may false positive.
358
+ // But really it's quite impossible to know whether webgl will succeed until after you create the context.
359
+ // You might have hardware that can support a 100x100 webgl canvas, but will not support a 1000x1000 webgl
360
+ // canvas. So this feature inference is weak, but intentionally so.
361
+
362
+ // It is known to false positive in FF4 with certain hardware and the iPad 2.
363
+
364
+ tests['webgl'] = function() {
365
+ return !!window.WebGLRenderingContext;
366
+ };
367
+
368
+ /*
369
+ * The Modernizr.touch test only indicates if the browser supports
370
+ * touch events, which does not necessarily reflect a touchscreen
371
+ * device, as evidenced by tablets running Windows 7 or, alas,
372
+ * the Palm Pre / WebOS (touch) phones.
373
+ *
374
+ * Additionally, Chrome (desktop) used to lie about its support on this,
375
+ * but that has since been rectified: http://crbug.com/36415
376
+ *
377
+ * We also test for Firefox 4 Multitouch Support.
378
+ *
379
+ * For more info, see: http://modernizr.github.com/Modernizr/touch.html
380
+ */
381
+
382
+ tests['touch'] = function() {
383
+ return Modernizr['touch'];
384
+ };
385
+
386
+ /**
387
+ * geolocation tests for the new Geolocation API specification.
388
+ * This test is a standards compliant-only test; for more complete
389
+ * testing, including a Google Gears fallback, please see:
390
+ * http://code.google.com/p/geo-location-javascript/
391
+ * or view a fallback solution using google's geo API:
392
+ * http://gist.github.com/366184
393
+ */
394
+ tests['geolocation'] = function() {
395
+ return !!navigator.geolocation;
396
+ };
397
+
398
+ // Per 1.6:
399
+ // This used to be Modernizr.crosswindowmessaging but the longer
400
+ // name has been deprecated in favor of a shorter and property-matching one.
401
+ // The old API is still available in 1.6, but as of 2.0 will throw a warning,
402
+ // and in the first release thereafter disappear entirely.
403
+ tests['postmessage'] = function() {
404
+ return !!window.postMessage;
405
+ };
406
+
407
+ // Web SQL database detection is tricky:
408
+
409
+ // In chrome incognito mode, openDatabase is truthy, but using it will
410
+ // throw an exception: http://crbug.com/42380
411
+ // We can create a dummy database, but there is no way to delete it afterwards.
412
+
413
+ // Meanwhile, Safari users can get prompted on any database creation.
414
+ // If they do, any page with Modernizr will give them a prompt:
415
+ // http://github.com/Modernizr/Modernizr/issues/closed#issue/113
416
+
417
+ // We have chosen to allow the Chrome incognito false positive, so that Modernizr
418
+ // doesn't litter the web with these test databases. As a developer, you'll have
419
+ // to account for this gotcha yourself.
420
+ tests['websqldatabase'] = function() {
421
+ var result = !!window.openDatabase;
422
+ /* if (result){
423
+ try {
424
+ result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4);
425
+ } catch(e) {
426
+ }
427
+ } */
428
+ return result;
429
+ };
430
+
431
+ // Vendors had inconsistent prefixing with the experimental Indexed DB:
432
+ // - Webkit's implementation is accessible through webkitIndexedDB
433
+ // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
434
+ // For speed, we don't test the legacy (and beta-only) indexedDB
435
+ tests['indexedDB'] = function() {
436
+ for ( var i = -1, len = domPrefixes.length; ++i < len; ){
437
+ if ( window[domPrefixes[i].toLowerCase() + 'IndexedDB'] ){
438
+ return true;
439
+ }
440
+ }
441
+ return !!window.indexedDB;
442
+ };
443
+
444
+ // documentMode logic from YUI to filter out IE8 Compat Mode
445
+ // which false positives.
446
+ tests['hashchange'] = function() {
447
+ return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
448
+ };
449
+
450
+ // Per 1.6:
451
+ // This used to be Modernizr.historymanagement but the longer
452
+ // name has been deprecated in favor of a shorter and property-matching one.
453
+ // The old API is still available in 1.6, but as of 2.0 will throw a warning,
454
+ // and in the first release thereafter disappear entirely.
455
+ tests['history'] = function() {
456
+ return !!(window.history && history.pushState);
457
+ };
458
+
459
+ tests['draganddrop'] = function() {
460
+ return isEventSupported('dragstart') && isEventSupported('drop');
461
+ };
462
+
463
+ // Mozilla is targeting to land MozWebSocket for FF6
464
+ // bugzil.la/659324
465
+ tests['websockets'] = function() {
466
+ for ( var i = -1, len = domPrefixes.length; ++i < len; ){
467
+ if ( window[domPrefixes[i] + 'WebSocket'] ){
468
+ return true;
469
+ }
470
+ }
471
+ return 'WebSocket' in window;
472
+ };
473
+
474
+
475
+ // http://css-tricks.com/rgba-browser-support/
476
+ tests['rgba'] = function() {
477
+ // Set an rgba() color and check the returned value
478
+
479
+ setCss('background-color:rgba(150,255,150,.5)');
480
+
481
+ return contains(mStyle.backgroundColor, 'rgba');
482
+ };
483
+
484
+ tests['hsla'] = function() {
485
+ // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
486
+ // except IE9 who retains it as hsla
487
+
488
+ setCss('background-color:hsla(120,40%,100%,.5)');
489
+
490
+ return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
491
+ };
492
+
493
+ tests['multiplebgs'] = function() {
494
+ // Setting multiple images AND a color on the background shorthand property
495
+ // and then querying the style.background property value for the number of
496
+ // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
497
+
498
+ setCss('background:url(https://),url(https://),red url(https://)');
499
+
500
+ // If the UA supports multiple backgrounds, there should be three occurrences
501
+ // of the string "url(" in the return value for elemStyle.background
502
+
503
+ return /(url\s*\(.*?){3}/.test(mStyle.background);
504
+ };
505
+
506
+
507
+ // In testing support for a given CSS property, it's legit to test:
508
+ // `elem.style[styleName] !== undefined`
509
+ // If the property is supported it will return an empty string,
510
+ // if unsupported it will return undefined.
511
+
512
+ // We'll take advantage of this quick test and skip setting a style
513
+ // on our modernizr element, but instead just testing undefined vs
514
+ // empty string.
515
+
516
+
517
+ tests['backgroundsize'] = function() {
518
+ return testPropsAll('backgroundSize');
519
+ };
520
+
521
+ tests['borderimage'] = function() {
522
+ return testPropsAll('borderImage');
523
+ };
524
+
525
+
526
+ // Super comprehensive table about all the unique implementations of
527
+ // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance
528
+
529
+ tests['borderradius'] = function() {
530
+ return testPropsAll('borderRadius');
531
+ };
532
+
533
+ // WebOS unfortunately false positives on this test.
534
+ tests['boxshadow'] = function() {
535
+ return testPropsAll('boxShadow');
536
+ };
537
+
538
+ // FF3.0 will false positive on this test
539
+ tests['textshadow'] = function() {
540
+ return document.createElement('div').style.textShadow === '';
541
+ };
542
+
543
+
544
+ tests['opacity'] = function() {
545
+ // Browsers that actually have CSS Opacity implemented have done so
546
+ // according to spec, which means their return values are within the
547
+ // range of [0.0,1.0] - including the leading zero.
548
+
549
+ setCssAll('opacity:.55');
550
+
551
+ // The non-literal . in this regex is intentional:
552
+ // German Chrome returns this value as 0,55
553
+ // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
554
+ return /^0.55$/.test(mStyle.opacity);
555
+ };
556
+
557
+
558
+ tests['cssanimations'] = function() {
559
+ return testPropsAll('animationName');
560
+ };
561
+
562
+
563
+ tests['csscolumns'] = function() {
564
+ return testPropsAll('columnCount');
565
+ };
566
+
567
+
568
+ tests['cssgradients'] = function() {
569
+ /**
570
+ * For CSS Gradients syntax, please see:
571
+ * http://webkit.org/blog/175/introducing-css-gradients/
572
+ * https://developer.mozilla.org/en/CSS/-moz-linear-gradient
573
+ * https://developer.mozilla.org/en/CSS/-moz-radial-gradient
574
+ * http://dev.w3.org/csswg/css3-images/#gradients-
575
+ */
576
+
577
+ var str1 = 'background-image:',
578
+ str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
579
+ str3 = 'linear-gradient(left top,#9f9, white);';
580
+
581
+ setCss(
582
+ (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0, -str1.length)
583
+ );
584
+
585
+ return contains(mStyle.backgroundImage, 'gradient');
586
+ };
587
+
588
+
589
+ tests['cssreflections'] = function() {
590
+ return testPropsAll('boxReflect');
591
+ };
592
+
593
+
594
+ tests['csstransforms'] = function() {
595
+ return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']);
596
+ };
597
+
598
+
599
+ tests['csstransforms3d'] = function() {
600
+
601
+ var ret = !!testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']);
602
+
603
+ // Webkit’s 3D transforms are passed off to the browser's own graphics renderer.
604
+ // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
605
+ // some conditions. As a result, Webkit typically recognizes the syntax but
606
+ // will sometimes throw a false positive, thus we must do a more thorough check:
607
+ if ( ret && 'webkitPerspective' in docElement.style ) {
608
+
609
+ // Webkit allows this media query to succeed only if the feature is enabled.
610
+ // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }`
611
+ ret = Modernizr['csstransforms3d'];
612
+ }
613
+ return ret;
614
+ };
615
+
616
+
617
+ tests['csstransitions'] = function() {
618
+ return testPropsAll('transitionProperty');
619
+ };
620
+
621
+
622
+ /*>>fontface*/
623
+ // @font-face detection routine by Diego Perini
624
+ // http://javascript.nwbox.com/CSSSupport/
625
+ tests['fontface'] = function() {
626
+ return Modernizr['fontface'];
627
+ };
628
+ /*>>fontface*/
629
+
630
+ // CSS generated content detection
631
+ tests['generatedcontent'] = function() {
632
+ return Modernizr['generatedcontent'];
633
+ };
634
+
635
+
636
+
637
+ // These tests evaluate support of the video/audio elements, as well as
638
+ // testing what types of content they support.
639
+ //
640
+ // We're using the Boolean constructor here, so that we can extend the value
641
+ // e.g. Modernizr.video // true
642
+ // Modernizr.video.ogg // 'probably'
643
+ //
644
+ // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
645
+ // thx to NielsLeenheer and zcorpan
646
+
647
+ // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string.
648
+ // Modernizr does not normalize for that.
649
+
650
+ tests['video'] = function() {
651
+ var elem = document.createElement('video'),
652
+ bool = false;
653
+
654
+ // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
655
+ try {
656
+ if ( bool = !!elem.canPlayType ) {
657
+ bool = new Boolean(bool);
658
+ bool.ogg = elem.canPlayType('video/ogg; codecs="theora"');
659
+
660
+ // Workaround required for IE9, which doesn't report video support without audio codec specified.
661
+ // bug 599718 @ msft connect
662
+ var h264 = 'video/mp4; codecs="avc1.42E01E';
663
+ bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"');
664
+
665
+ bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"');
666
+ }
667
+
668
+ } catch(e) { }
669
+
670
+ return bool;
671
+ };
672
+
673
+ tests['audio'] = function() {
674
+ var elem = document.createElement('audio'),
675
+ bool = false;
676
+
677
+ try {
678
+ if ( bool = !!elem.canPlayType ) {
679
+ bool = new Boolean(bool);
680
+ bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"');
681
+ bool.mp3 = elem.canPlayType('audio/mpeg;');
682
+
683
+ // Mimetypes accepted:
684
+ // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
685
+ // http://bit.ly/iphoneoscodecs
686
+ bool.wav = elem.canPlayType('audio/wav; codecs="1"');
687
+ bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;');
688
+ }
689
+ } catch(e) { }
690
+
691
+ return bool;
692
+ };
693
+
694
+
695
+ // Firefox has made these tests rather unfun.
696
+
697
+ // In FF4, if disabled, window.localStorage should === null.
698
+
699
+ // Normally, we could not test that directly and need to do a
700
+ // `('localStorage' in window) && ` test first because otherwise Firefox will
701
+ // throw http://bugzil.la/365772 if cookies are disabled
702
+
703
+ // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning
704
+ // the property will throw an exception. http://bugzil.la/599479
705
+ // This looks to be fixed for FF4 Final.
706
+
707
+ // Because we are forced to try/catch this, we'll go aggressive.
708
+
709
+ // FWIW: IE8 Compat mode supports these features completely:
710
+ // http://www.quirksmode.org/dom/html5.html
711
+ // But IE8 doesn't support either with local files
712
+
713
+ tests['localstorage'] = function() {
714
+ try {
715
+ return !!localStorage.getItem;
716
+ } catch(e) {
717
+ return false;
718
+ }
719
+ };
720
+
721
+ tests['sessionstorage'] = function() {
722
+ try {
723
+ return !!sessionStorage.getItem;
724
+ } catch(e){
725
+ return false;
726
+ }
727
+ };
728
+
729
+
730
+ tests['webworkers'] = function() {
731
+ return !!window.Worker;
732
+ };
733
+
734
+
735
+ tests['applicationcache'] = function() {
736
+ return !!window.applicationCache;
737
+ };
738
+
739
+
740
+ // Thanks to Erik Dahlstrom
741
+ tests['svg'] = function() {
742
+ return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
743
+ };
744
+
745
+ // specifically for SVG inline in HTML, not within XHTML
746
+ // test page: paulirish.com/demo/inline-svg
747
+ tests['inlinesvg'] = function() {
748
+ var div = document.createElement('div');
749
+ div.innerHTML = '<svg/>';
750
+ return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
751
+ };
752
+
753
+ // Thanks to F1lt3r and lucideer, ticket #35
754
+ tests['smil'] = function() {
755
+ return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
756
+ };
757
+
758
+ tests['svgclippaths'] = function() {
759
+ // Possibly returns a false positive in Safari 3.2?
760
+ return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
761
+ };
762
+
763
+ // input features and input types go directly onto the ret object, bypassing the tests loop.
764
+ // Hold this guy to execute in a moment.
765
+ function webforms() {
766
+ // Run through HTML5's new input attributes to see if the UA understands any.
767
+ // We're using f which is the <input> element created early on
768
+ // Mike Taylr has created a comprehensive resource for testing these attributes
769
+ // when applied to all input types:
770
+ // http://miketaylr.com/code/input-type-attr.html
771
+ // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
772
+
773
+ // Only input placeholder is tested while textarea's placeholder is not.
774
+ // Currently Safari 4 and Opera 11 have support only for the input placeholder
775
+ // Both tests are available in feature-detects/forms-placeholder.js
776
+ Modernizr['input'] = (function( props ) {
777
+ for ( var i = 0, len = props.length; i < len; i++ ) {
778
+ attrs[ props[i] ] = !!(props[i] in inputElem);
779
+ }
780
+ return attrs;
781
+ })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
782
+
783
+ // Run through HTML5's new input types to see if the UA understands any.
784
+ // This is put behind the tests runloop because it doesn't return a
785
+ // true/false like all the other tests; instead, it returns an object
786
+ // containing each input type with its corresponding true/false value
787
+
788
+ // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/
789
+ Modernizr['inputtypes'] = (function(props) {
790
+
791
+ for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
792
+
793
+ inputElem.setAttribute('type', inputElemType = props[i]);
794
+ bool = inputElem.type !== 'text';
795
+
796
+ // We first check to see if the type we give it sticks..
797
+ // If the type does, we feed it a textual value, which shouldn't be valid.
798
+ // If the value doesn't stick, we know there's input sanitization which infers a custom UI
799
+ if ( bool ) {
800
+
801
+ inputElem.value = smile;
802
+ inputElem.style.cssText = 'position:absolute;visibility:hidden;';
803
+
804
+ if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
805
+
806
+ docElement.appendChild(inputElem);
807
+ defaultView = document.defaultView;
808
+
809
+ // Safari 2-4 allows the smiley as a value, despite making a slider
810
+ bool = defaultView.getComputedStyle &&
811
+ defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
812
+ // Mobile android web browser has false positive, so must
813
+ // check the height to see if the widget is actually there.
814
+ (inputElem.offsetHeight !== 0);
815
+
816
+ docElement.removeChild(inputElem);
817
+
818
+ } else if ( /^(search|tel)$/.test(inputElemType) ){
819
+ // Spec doesnt define any special parsing or detectable UI
820
+ // behaviors so we pass these through as true
821
+
822
+ // Interestingly, opera fails the earlier test, so it doesn't
823
+ // even make it here.
824
+
825
+ } else if ( /^(url|email)$/.test(inputElemType) ) {
826
+ // Real url and email support comes with prebaked validation.
827
+ bool = inputElem.checkValidity && inputElem.checkValidity() === false;
828
+
829
+ } else if ( /^color$/.test(inputElemType) ) {
830
+ // chuck into DOM and force reflow for Opera bug in 11.00
831
+ // github.com/Modernizr/Modernizr/issues#issue/159
832
+ docElement.appendChild(inputElem);
833
+ docElement.offsetWidth;
834
+ bool = inputElem.value != smile;
835
+ docElement.removeChild(inputElem);
836
+
837
+ } else {
838
+ // If the upgraded input compontent rejects the :) text, we got a winner
839
+ bool = inputElem.value != smile;
840
+ }
841
+ }
842
+
843
+ inputs[ props[i] ] = !!bool;
844
+ }
845
+ return inputs;
846
+ })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
847
+ }
848
+
849
+
850
+ // End of test definitions
851
+ // -----------------------
852
+
853
+
854
+
855
+ // Run through all tests and detect their support in the current UA.
856
+ // todo: hypothetically we could be doing an array of tests and use a basic loop here.
857
+ for ( var feature in tests ) {
858
+ if ( hasOwnProperty(tests, feature) ) {
859
+ // run the test, throw the return value into the Modernizr,
860
+ // then based on that boolean, define an appropriate className
861
+ // and push it into an array of classes we'll join later.
862
+ featureName = feature.toLowerCase();
863
+ Modernizr[featureName] = tests[feature]();
864
+
865
+ classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
866
+ }
867
+ }
868
+
869
+ // input tests need to run.
870
+ Modernizr.input || webforms();
871
+
872
+
873
+ /**
874
+ * addTest allows the user to define their own feature tests
875
+ * the result will be added onto the Modernizr object,
876
+ * as well as an appropriate className set on the html element
877
+ *
878
+ * @param feature - String naming the feature
879
+ * @param test - Function returning true if feature is supported, false if not
880
+ */
881
+ Modernizr.addTest = function ( feature, test ) {
882
+ if ( typeof feature == "object" ) {
883
+ for ( var key in feature ) {
884
+ if ( hasOwnProperty( feature, key ) ) {
885
+ Modernizr.addTest( key, feature[ key ] );
886
+ }
887
+ }
888
+ } else {
889
+
890
+ feature = feature.toLowerCase();
891
+
892
+ if ( Modernizr[feature] !== undefined ) {
893
+ // we're going to quit if you're trying to overwrite an existing test
894
+ // if we were to allow it, we'd do this:
895
+ // var re = new RegExp("\\b(no-)?" + feature + "\\b");
896
+ // docElement.className = docElement.className.replace( re, '' );
897
+ // but, no rly, stuff 'em.
898
+ return;
899
+ }
900
+
901
+ test = typeof test == "boolean" ? test : !!test();
902
+
903
+ docElement.className += ' ' + (test ? '' : 'no-') + feature;
904
+ Modernizr[feature] = test;
905
+
906
+ }
907
+
908
+ return Modernizr; // allow chaining.
909
+ };
910
+
911
+
912
+ // Reset modElem.cssText to nothing to reduce memory footprint.
913
+ setCss('');
914
+ modElem = inputElem = null;
915
+
916
+ //>>BEGIN IEPP
917
+ // Enable HTML 5 elements for styling (and printing) in IE.
918
+ if ( window.attachEvent && (function(){ var elem = document.createElement('div');
919
+ elem.innerHTML = '<elem></elem>';
920
+ return elem.childNodes.length !== 1; })() ) {
921
+
922
+ // iepp v2 by @jon_neal & afarkas : github.com/aFarkas/iepp/
923
+ (function(win, doc) {
924
+ win.iepp = win.iepp || {};
925
+ var iepp = win.iepp,
926
+ elems = iepp.html5elements || 'abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video',
927
+ elemsArr = elems.split('|'),
928
+ elemsArrLen = elemsArr.length,
929
+ elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'),
930
+ tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'),
931
+ filterReg = /^\s*[\{\}]\s*$/,
932
+ ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'),
933
+ docFrag = doc.createDocumentFragment(),
934
+ html = doc.documentElement,
935
+ head = html.firstChild,
936
+ bodyElem = doc.createElement('body'),
937
+ styleElem = doc.createElement('style'),
938
+ printMedias = /print|all/,
939
+ body;
940
+ function shim(doc) {
941
+ var a = -1;
942
+ while (++a < elemsArrLen)
943
+ // Use createElement so IE allows HTML5-named elements in a document
944
+ doc.createElement(elemsArr[a]);
945
+ }
946
+
947
+ iepp.getCSS = function(styleSheetList, mediaType) {
948
+ if(styleSheetList+'' === undefined){return '';}
949
+ var a = -1,
950
+ len = styleSheetList.length,
951
+ styleSheet,
952
+ cssTextArr = [];
953
+ while (++a < len) {
954
+ styleSheet = styleSheetList[a];
955
+ //currently no test for disabled/alternate stylesheets
956
+ if(styleSheet.disabled){continue;}
957
+ mediaType = styleSheet.media || mediaType;
958
+ // Get css from all non-screen stylesheets and their imports
959
+ if (printMedias.test(mediaType)) cssTextArr.push(iepp.getCSS(styleSheet.imports, mediaType), styleSheet.cssText);
960
+ //reset mediaType to all with every new *not imported* stylesheet
961
+ mediaType = 'all';
962
+ }
963
+ return cssTextArr.join('');
964
+ };
965
+
966
+ iepp.parseCSS = function(cssText) {
967
+ var cssTextArr = [],
968
+ rule;
969
+ while ((rule = ruleRegExp.exec(cssText)) != null){
970
+ // Replace all html5 element references with iepp substitute classnames
971
+ cssTextArr.push(( (filterReg.exec(rule[1]) ? '\n' : rule[1]) +rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]);
972
+ }
973
+ return cssTextArr.join('\n');
974
+ };
975
+
976
+ iepp.writeHTML = function() {
977
+ var a = -1;
978
+ body = body || doc.body;
979
+ while (++a < elemsArrLen) {
980
+ var nodeList = doc.getElementsByTagName(elemsArr[a]),
981
+ nodeListLen = nodeList.length,
982
+ b = -1;
983
+ while (++b < nodeListLen)
984
+ if (nodeList[b].className.indexOf('iepp_') < 0)
985
+ // Append iepp substitute classnames to all html5 elements
986
+ nodeList[b].className += ' iepp_'+elemsArr[a];
987
+ }
988
+ docFrag.appendChild(body);
989
+ html.appendChild(bodyElem);
990
+ // Write iepp substitute print-safe document
991
+ bodyElem.className = body.className;
992
+ bodyElem.id = body.id;
993
+ // Replace HTML5 elements with <font> which is print-safe and shouldn't conflict since it isn't part of html5
994
+ bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font');
995
+ };
996
+
997
+
998
+ iepp._beforePrint = function() {
999
+ // Write iepp custom print CSS
1000
+ styleElem.styleSheet.cssText = iepp.parseCSS(iepp.getCSS(doc.styleSheets, 'all'));
1001
+ iepp.writeHTML();
1002
+ };
1003
+
1004
+ iepp.restoreHTML = function(){
1005
+ // Undo everything done in onbeforeprint
1006
+ bodyElem.innerHTML = '';
1007
+ html.removeChild(bodyElem);
1008
+ html.appendChild(body);
1009
+ };
1010
+
1011
+ iepp._afterPrint = function(){
1012
+ // Undo everything done in onbeforeprint
1013
+ iepp.restoreHTML();
1014
+ styleElem.styleSheet.cssText = '';
1015
+ };
1016
+
1017
+
1018
+
1019
+ // Shim the document and iepp fragment
1020
+ shim(doc);
1021
+ shim(docFrag);
1022
+
1023
+ //
1024
+ if(iepp.disablePP){return;}
1025
+
1026
+ // Add iepp custom print style element
1027
+ head.insertBefore(styleElem, head.firstChild);
1028
+ styleElem.media = 'print';
1029
+ styleElem.className = 'iepp-printshim';
1030
+ win.attachEvent(
1031
+ 'onbeforeprint',
1032
+ iepp._beforePrint
1033
+ );
1034
+ win.attachEvent(
1035
+ 'onafterprint',
1036
+ iepp._afterPrint
1037
+ );
1038
+ })(window, document);
1039
+ }
1040
+ //>>END IEPP
1041
+
1042
+ // Assign private properties to the return object with prefix
1043
+ Modernizr._version = version;
1044
+
1045
+ // expose these for the plugin API. Look in the source for how to join() them against your input
1046
+ Modernizr._prefixes = prefixes;
1047
+ Modernizr._domPrefixes = domPrefixes;
1048
+
1049
+ // Modernizr.mq tests a given media query, live against the current state of the window
1050
+ // A few important notes:
1051
+ // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
1052
+ // * A max-width or orientation query will be evaluated against the current state, which may change later.
1053
+ // * You must specify values. Eg. If you are testing support for the min-width media query use:
1054
+ // Modernizr.mq('(min-width:0)')
1055
+ // usage:
1056
+ // Modernizr.mq('only screen and (max-width:768)')
1057
+ Modernizr.mq = testMediaQuery;
1058
+
1059
+ // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
1060
+ // Modernizr.hasEvent('gesturestart', elem)
1061
+ Modernizr.hasEvent = isEventSupported;
1062
+
1063
+ // Modernizr.testProp() investigates whether a given style property is recognized
1064
+ // Note that the property names must be provided in the camelCase variant.
1065
+ // Modernizr.testProp('pointerEvents')
1066
+ Modernizr.testProp = function(prop){
1067
+ return testProps([prop]);
1068
+ };
1069
+
1070
+ // Modernizr.testAllProps() investigates whether a given style property,
1071
+ // or any of its vendor-prefixed variants, is recognized
1072
+ // Note that the property names must be provided in the camelCase variant.
1073
+ // Modernizr.testAllProps('boxSizing')
1074
+ Modernizr.testAllProps = testPropsAll;
1075
+
1076
+
1077
+
1078
+ // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
1079
+ // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
1080
+ Modernizr.testStyles = injectElementWithStyles;
1081
+
1082
+
1083
+ // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
1084
+ // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
1085
+
1086
+ // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
1087
+ // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
1088
+ //
1089
+ // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
1090
+
1091
+ // If you're trying to ascertain which transition end event to bind to, you might do something like...
1092
+ //
1093
+ // var transEndEventNames = {
1094
+ // 'WebkitTransition' : 'webkitTransitionEnd',
1095
+ // 'MozTransition' : 'transitionend',
1096
+ // 'OTransition' : 'oTransitionEnd',
1097
+ // 'msTransition' : 'msTransitionEnd', // maybe?
1098
+ // 'transition' : 'transitionEnd'
1099
+ // },
1100
+ // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
1101
+
1102
+ Modernizr.prefixed = function(prop){
1103
+ return testPropsAll(prop, 'pfx');
1104
+ };
1105
+
1106
+
1107
+
1108
+ // Remove "no-js" class from <html> element, if it exists:
1109
+ docElement.className = docElement.className.replace(/\bno-js\b/, '')
1110
+
1111
+ // Add the new classes to the <html> element.
1112
+ + (enableClasses ? ' js ' + classes.join(' ') : '');
1113
+
1114
+ return Modernizr;
1115
+
1116
+ })(this, this.document);