weblinc-modernizr-rails 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a6e6375c84b7270834efda61a992c23bac5a27b
4
- data.tar.gz: 81dcea5c602acb02205a1e59d9160bc31b58a4f0
3
+ metadata.gz: 6b8cde054cf10b27530b6bd9fa7357962d71e8c6
4
+ data.tar.gz: f0d251ffed11b363d68cef8b05c5857acdaba2f7
5
5
  SHA512:
6
- metadata.gz: de1d65b3f92c70e7ec20bc76d3b139f07608187162001acf88acf9365a8b77864650961095ccf15420ff352d7b4526e22d4cb16f3ae1569f3661b475394a7ca9
7
- data.tar.gz: 13881994177f106ff7723d41e8326e790b7626ef0629ec27b5be80ae22631e949653f7362b4985a84d652b73529cfb7100405671fa0494f69aea950d1f1f773d
6
+ metadata.gz: eab88736e4ff4f62bb2fd33677c09a8a076c6a8e12f118bcfe332be774fec44668db22624e56f5413d2c5c6717a912f31767c5da580769b075577744302fbf84
7
+ data.tar.gz: 95607e51ee1ab16b11dfbf7c10717e0956033d431850d5198e6ad22a9ce5afa79cc7d5d2216cbdbe2d899b0e80fbe8c6cc8996e8842a8c1d577875fedf839ac6
@@ -1,7 +1,7 @@
1
1
  module Weblinc
2
2
  module Modernizr
3
3
  module Rails
4
- VERSION = '1.0.0'
4
+ VERSION = '2.0.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,317 +1,1217 @@
1
- /* Modernizr 2.8.3 (Custom Build) | MIT & BSD
2
- * Build: http://modernizr.com/download/#-cssanimations-csstransitions-touch-mq-cssclasses-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes-cssclassprefix:modernizr!
1
+ /*!
2
+ * modernizr v3.2.0
3
+ * Build http://modernizr.com/download?-cssanimations-csstransitions-touchevents-domprefixes-mq-prefixed-prefixes-setclasses-testallprops-testprop-teststyles-dontmin-cssclassprefix:modernizr-
4
+ *
5
+ * Copyright (c)
6
+ * Faruk Ates
7
+ * Paul Irish
8
+ * Alex Sexton
9
+ * Ryan Seddon
10
+ * Patrick Kettner
11
+ * Stu Cox
12
+ * Richard Herrera
13
+
14
+ * MIT License
3
15
  */
4
- ;
5
16
 
17
+ /*
18
+ * Modernizr tests which native CSS3 and HTML5 features are available in the
19
+ * current UA and makes the results available to you in two ways: as properties on
20
+ * a global `Modernizr` object, and as classes on the `<html>` element. This
21
+ * information allows you to progressively enhance your pages with a granular level
22
+ * of control over the experience.
23
+ */
6
24
 
25
+ ;(function(window, document, undefined){
26
+ var classes = [];
7
27
 
8
- window.Modernizr = (function( window, document, undefined ) {
9
28
 
10
- var version = '2.8.3',
29
+ var tests = [];
11
30
 
12
- Modernizr = {},
13
31
 
14
- enableClasses = true,
32
+ /**
33
+ *
34
+ * ModernizrProto is the constructor for Modernizr
35
+ *
36
+ * @class
37
+ * @access public
38
+ */
15
39
 
16
- docElement = document.documentElement,
40
+ var ModernizrProto = {
41
+ // The current version, dummy
42
+ _version: '3.2.0',
17
43
 
18
- mod = 'modernizr',
19
- modElem = document.createElement(mod),
20
- mStyle = modElem.style,
44
+ // Any settings that don't work as separate modules
45
+ // can go in here as configuration.
46
+ _config: {
47
+ 'classPrefix': "modernizr-",
48
+ 'enableClasses': true,
49
+ 'enableJSClass': true,
50
+ 'usePrefixes': true
51
+ },
21
52
 
22
- inputElem ,
53
+ // Queue of tests
54
+ _q: [],
55
+
56
+ // Stub these for people who are listening
57
+ on: function(test, cb) {
58
+ // I don't really think people should do this, but we can
59
+ // safe guard it a bit.
60
+ // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
61
+ // This is in case people listen to synchronous tests. I would leave it out,
62
+ // but the code to *disallow* sync tests in the real version of this
63
+ // function is actually larger than this.
64
+ var self = this;
65
+ setTimeout(function() {
66
+ cb(self[test]);
67
+ }, 0);
68
+ },
23
69
 
70
+ addTest: function(name, fn, options) {
71
+ tests.push({name: name, fn: fn, options: options});
72
+ },
24
73
 
25
- toString = {}.toString,
74
+ addAsyncTest: function(fn) {
75
+ tests.push({name: null, fn: fn});
76
+ }
77
+ };
78
+
79
+
80
+
81
+ // Fake some of Object.create so we can force non test results to be non "own" properties.
82
+ var Modernizr = function() {};
83
+ Modernizr.prototype = ModernizrProto;
84
+
85
+ // Leak modernizr globally when you `require` it rather than force it here.
86
+ // Overwrite name so constructor name is nicer :D
87
+ Modernizr = new Modernizr();
88
+
89
+
90
+
91
+ /**
92
+ * List of property values to set for css tests. See ticket #21
93
+ * http://git.io/vUGl4
94
+ *
95
+ * @memberof Modernizr
96
+ * @name Modernizr._prefixes
97
+ * @optionName Modernizr._prefixes
98
+ * @optionProp prefixes
99
+ * @access public
100
+ * @example
101
+ *
102
+ * Modernizr._prefixes is the internal list of prefixes that we test against
103
+ * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
104
+ * an array of kebab-case vendor prefixes you can use within your code.
105
+ *
106
+ * Some common use cases include
107
+ *
108
+ * Generating all possible prefixed version of a CSS property
109
+ * ```js
110
+ * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
111
+ *
112
+ * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
113
+ * ```
114
+ *
115
+ * Generating all possible prefixed version of a CSS value
116
+ * ```js
117
+ * rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex';
118
+ *
119
+ * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
120
+ * ```
121
+ */
122
+
123
+ var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : []);
124
+
125
+ // expose these for the plugin API. Look in the source for how to join() them against your input
126
+ ModernizrProto._prefixes = prefixes;
127
+
128
+
129
+
130
+ /**
131
+ * is returns a boolean if the typeof an obj is exactly type.
132
+ *
133
+ * @access private
134
+ * @function is
135
+ * @param {*} obj - A thing we want to check the type of
136
+ * @param {string} type - A string to compare the typeof against
137
+ * @returns {boolean}
138
+ */
139
+
140
+ function is(obj, type) {
141
+ return typeof obj === type;
142
+ }
143
+ ;
144
+
145
+ /**
146
+ * Run through all tests and detect their support in the current UA.
147
+ *
148
+ * @access private
149
+ */
150
+
151
+ function testRunner() {
152
+ var featureNames;
153
+ var feature;
154
+ var aliasIdx;
155
+ var result;
156
+ var nameIdx;
157
+ var featureName;
158
+ var featureNameSplit;
159
+
160
+ for (var featureIdx in tests) {
161
+ if (tests.hasOwnProperty(featureIdx)) {
162
+ featureNames = [];
163
+ feature = tests[featureIdx];
164
+ // run the test, throw the return value into the Modernizr,
165
+ // then based on that boolean, define an appropriate className
166
+ // and push it into an array of classes we'll join later.
167
+ //
168
+ // If there is no name, it's an 'async' test that is run,
169
+ // but not directly added to the object. That should
170
+ // be done with a post-run addTest call.
171
+ if (feature.name) {
172
+ featureNames.push(feature.name.toLowerCase());
173
+
174
+ if (feature.options && feature.options.aliases && feature.options.aliases.length) {
175
+ // Add all the aliases into the names list
176
+ for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
177
+ featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
178
+ }
179
+ }
180
+ }
26
181
 
27
- prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
182
+ // Run the test, or use the raw value if it's not a function
183
+ result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
184
+
185
+
186
+ // Set each of the names on the Modernizr object
187
+ for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
188
+ featureName = featureNames[nameIdx];
189
+ // Support dot properties as sub tests. We don't do checking to make sure
190
+ // that the implied parent tests have been added. You must call them in
191
+ // order (either in the test, or make the parent test a dependency).
192
+ //
193
+ // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
194
+ // hashtag famous last words
195
+ featureNameSplit = featureName.split('.');
196
+
197
+ if (featureNameSplit.length === 1) {
198
+ Modernizr[featureNameSplit[0]] = result;
199
+ } else {
200
+ // cast to a Boolean, if not one already
201
+ /* jshint -W053 */
202
+ if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
203
+ Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
204
+ }
28
205
 
206
+ Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
207
+ }
29
208
 
209
+ classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
210
+ }
211
+ }
212
+ }
213
+ }
214
+ ;
30
215
 
31
- omPrefixes = 'Webkit Moz O ms',
216
+ /**
217
+ * docElement is a convenience wrapper to grab the root element of the document
218
+ *
219
+ * @access private
220
+ * @returns {HTMLElement|SVGElement} The root element of the document
221
+ */
32
222
 
33
- cssomPrefixes = omPrefixes.split(' '),
223
+ var docElement = document.documentElement;
34
224
 
35
- domPrefixes = omPrefixes.toLowerCase().split(' '),
36
225
 
226
+ /**
227
+ * A convenience helper to check if the document we are running in is an SVG document
228
+ *
229
+ * @access private
230
+ * @returns {boolean}
231
+ */
37
232
 
38
- tests = {},
39
- inputs = {},
40
- attrs = {},
233
+ var isSVG = docElement.nodeName.toLowerCase() === 'svg';
41
234
 
42
- classes = [],
43
235
 
44
- slice = classes.slice,
236
+ /**
237
+ * setClasses takes an array of class names and adds them to the root element
238
+ *
239
+ * @access private
240
+ * @function setClasses
241
+ * @param {string[]} classes - Array of class names
242
+ */
45
243
 
46
- featureName,
244
+ // Pass in an and array of class names, e.g.:
245
+ // ['no-webp', 'borderradius', ...]
246
+ function setClasses(classes) {
247
+ var className = docElement.className;
248
+ var classPrefix = Modernizr._config.classPrefix || '';
47
249
 
250
+ if (isSVG) {
251
+ className = className.baseVal;
252
+ }
48
253
 
49
- injectElementWithStyles = function( rule, callback, nodes, testnames ) {
254
+ // Change `no-js` to `js` (independently of the `enableClasses` option)
255
+ // Handle classPrefix on this too
256
+ if (Modernizr._config.enableJSClass) {
257
+ var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
258
+ className = className.replace(reJS, '$1' + classPrefix + 'js$2');
259
+ }
50
260
 
51
- var style, ret, node, docOverflow,
52
- div = document.createElement('div'),
53
- body = document.body,
54
- fakeBody = body || document.createElement('body');
261
+ if (Modernizr._config.enableClasses) {
262
+ // Add the new classes
263
+ className += ' ' + classPrefix + classes.join(' ' + classPrefix);
264
+ isSVG ? docElement.className.baseVal = className : docElement.className = className;
265
+ }
55
266
 
56
- if ( parseInt(nodes, 10) ) {
57
- while ( nodes-- ) {
58
- node = document.createElement('div');
59
- node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
60
- div.appendChild(node);
61
- }
62
- }
267
+ }
268
+
269
+ ;
270
+
271
+ /**
272
+ * If the browsers follow the spec, then they would expose vendor-specific style as:
273
+ * elem.style.WebkitBorderRadius
274
+ * instead of something like the following, which would be technically incorrect:
275
+ * elem.style.webkitBorderRadius
276
+
277
+ * Webkit ghosts their properties in lowercase but Opera & Moz do not.
278
+ * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
279
+ * erik.eae.net/archives/2008/03/10/21.48.10/
280
+
281
+ * More here: github.com/Modernizr/Modernizr/issues/issue/21
282
+ *
283
+ * @access private
284
+ * @returns {string} The string representing the vendor-specific style properties
285
+ */
286
+
287
+ var omPrefixes = 'Moz O ms Webkit';
288
+
289
+
290
+ /**
291
+ * List of JavaScript DOM values used for tests
292
+ *
293
+ * @memberof Modernizr
294
+ * @name Modernizr._domPrefixes
295
+ * @optionName Modernizr._domPrefixes
296
+ * @optionProp domPrefixes
297
+ * @access public
298
+ * @example
299
+ *
300
+ * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
301
+ * than kebab-case properties, all properties are their Capitalized variant
302
+ *
303
+ * ```js
304
+ * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
305
+ * ```
306
+ */
307
+
308
+ var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
309
+ ModernizrProto._domPrefixes = domPrefixes;
310
+
311
+
312
+ /**
313
+ * cssToDOM takes a kebab-case string and converts it to camelCase
314
+ * e.g. box-sizing -> boxSizing
315
+ *
316
+ * @access private
317
+ * @function cssToDOM
318
+ * @param {string} name - String name of kebab-case prop we want to convert
319
+ * @returns {string} The camelCase version of the supplied name
320
+ */
321
+
322
+ function cssToDOM(name) {
323
+ return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
324
+ return m1 + m2.toUpperCase();
325
+ }).replace(/^-/, '');
326
+ }
327
+ ;
328
+
329
+ /**
330
+ * createElement is a convenience wrapper around document.createElement. Since we
331
+ * use createElement all over the place, this allows for (slightly) smaller code
332
+ * as well as abstracting away issues with creating elements in contexts other than
333
+ * HTML documents (e.g. SVG documents).
334
+ *
335
+ * @access private
336
+ * @function createElement
337
+ * @returns {HTMLElement|SVGElement} An HTML or SVG element
338
+ */
339
+
340
+ function createElement() {
341
+ if (typeof document.createElement !== 'function') {
342
+ // This is the case in IE7, where the type of createElement is "object".
343
+ // For this reason, we cannot call apply() as Object is not a Function.
344
+ return document.createElement(arguments[0]);
345
+ } else if (isSVG) {
346
+ return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
347
+ } else {
348
+ return document.createElement.apply(document, arguments);
349
+ }
350
+ }
351
+
352
+ ;
353
+
354
+ /**
355
+ * getBody returns the body of a document, or an element that can stand in for
356
+ * the body if a real body does not exist
357
+ *
358
+ * @access private
359
+ * @function getBody
360
+ * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
361
+ * artificially created element that stands in for the body
362
+ */
363
+
364
+ function getBody() {
365
+ // After page load injecting a fake body doesn't work so check if body exists
366
+ var body = document.body;
367
+
368
+ if (!body) {
369
+ // Can't use the real body create a fake one.
370
+ body = createElement(isSVG ? 'svg' : 'body');
371
+ body.fake = true;
372
+ }
63
373
 
64
- style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
65
- div.id = mod;
66
- (body ? div : fakeBody).innerHTML += style;
67
- fakeBody.appendChild(div);
68
- if ( !body ) {
69
- fakeBody.style.background = '';
70
- fakeBody.style.overflow = 'hidden';
71
- docOverflow = docElement.style.overflow;
72
- docElement.style.overflow = 'hidden';
73
- docElement.appendChild(fakeBody);
374
+ return body;
375
+ }
376
+
377
+ ;
378
+
379
+ /**
380
+ * injectElementWithStyles injects an element with style element and some CSS rules
381
+ *
382
+ * @access private
383
+ * @function injectElementWithStyles
384
+ * @param {string} rule - String representing a css rule
385
+ * @param {function} callback - A function that is used to test the injected element
386
+ * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
387
+ * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
388
+ * @returns {boolean}
389
+ */
390
+
391
+ function injectElementWithStyles(rule, callback, nodes, testnames) {
392
+ var mod = 'modernizr';
393
+ var style;
394
+ var ret;
395
+ var node;
396
+ var docOverflow;
397
+ var div = createElement('div');
398
+ var body = getBody();
399
+
400
+ if (parseInt(nodes, 10)) {
401
+ // In order not to give false positives we create a node for each test
402
+ // This also allows the method to scale for unspecified uses
403
+ while (nodes--) {
404
+ node = createElement('div');
405
+ node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
406
+ div.appendChild(node);
74
407
  }
408
+ }
75
409
 
76
- ret = callback(div, rule);
77
- if ( !body ) {
78
- fakeBody.parentNode.removeChild(fakeBody);
79
- docElement.style.overflow = docOverflow;
80
- } else {
81
- div.parentNode.removeChild(div);
82
- }
410
+ style = createElement('style');
411
+ style.type = 'text/css';
412
+ style.id = 's' + mod;
83
413
 
84
- return !!ret;
414
+ // 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.
415
+ // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
416
+ (!body.fake ? div : body).appendChild(style);
417
+ body.appendChild(div);
85
418
 
86
- },
419
+ if (style.styleSheet) {
420
+ style.styleSheet.cssText = rule;
421
+ } else {
422
+ style.appendChild(document.createTextNode(rule));
423
+ }
424
+ div.id = mod;
425
+
426
+ if (body.fake) {
427
+ //avoid crashing IE8, if background image is used
428
+ body.style.background = '';
429
+ //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
430
+ body.style.overflow = 'hidden';
431
+ docOverflow = docElement.style.overflow;
432
+ docElement.style.overflow = 'hidden';
433
+ docElement.appendChild(body);
434
+ }
87
435
 
88
- testMediaQuery = function( mq ) {
436
+ ret = callback(div, rule);
437
+ // If this is done after page load we don't want to remove the body so check if body exists
438
+ if (body.fake) {
439
+ body.parentNode.removeChild(body);
440
+ docElement.style.overflow = docOverflow;
441
+ // Trigger layout so kinetic scrolling isn't disabled in iOS6+
442
+ docElement.offsetHeight;
443
+ } else {
444
+ div.parentNode.removeChild(div);
445
+ }
89
446
 
90
- var matchMedia = window.matchMedia || window.msMatchMedia;
91
- if ( matchMedia ) {
92
- return matchMedia(mq) && matchMedia(mq).matches || false;
93
- }
447
+ return !!ret;
448
+
449
+ }
450
+
451
+ ;
452
+
453
+ /**
454
+ * Modernizr.mq tests a given media query, live against the current state of the window
455
+ * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
456
+ * gist.github.com/786768
457
+ *
458
+ * @memberof Modernizr
459
+ * @name Modernizr.mq
460
+ * @optionName Modernizr.mq()
461
+ * @optionProp mq
462
+ * @access public
463
+ * @function mq
464
+ * @param {string} mq - String of the media query we want to test
465
+ * @returns {boolean}
466
+ * @example
467
+ * Modernizr.mq allows for you to programmatically check if the current browser
468
+ * window state matches a media query.
469
+ *
470
+ * ```js
471
+ * var query = Modernizr.mq('(min-width: 900px)');
472
+ *
473
+ * if (query) {
474
+ * // the browser window is larger than 900px
475
+ * }
476
+ * ```
477
+ *
478
+ * Only valid media queries are supported, therefore you must always include values
479
+ * with your media query
480
+ *
481
+ * ```js
482
+ * // good
483
+ * Modernizr.mq('(min-width: 900px)');
484
+ *
485
+ * // bad
486
+ * Modernizr.mq('min-width');
487
+ * ```
488
+ *
489
+ * If you would just like to test that media queries are supported in general, use
490
+ *
491
+ * ```js
492
+ * Modernizr.mq('only all'); // true if MQ are supported, false if not
493
+ * ```
494
+ *
495
+ *
496
+ * Note that if the browser does not support media queries (e.g. old IE) mq will
497
+ * always return false.
498
+ */
499
+
500
+ var mq = (function() {
501
+ var matchMedia = window.matchMedia || window.msMatchMedia;
502
+ if (matchMedia) {
503
+ return function(mq) {
504
+ var mql = matchMedia(mq);
505
+ return mql && mql.matches || false;
506
+ };
507
+ }
94
508
 
95
- var bool;
509
+ return function(mq) {
510
+ var bool = false;
96
511
 
97
- injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
512
+ injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
98
513
  bool = (window.getComputedStyle ?
99
- getComputedStyle(node, null) :
100
- node.currentStyle)['position'] == 'absolute';
514
+ window.getComputedStyle(node, null) :
515
+ node.currentStyle).position == 'absolute';
101
516
  });
102
517
 
103
518
  return bool;
104
-
105
- },
106
- _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
107
-
108
- if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
109
- hasOwnProp = function (object, property) {
110
- return _hasOwnProperty.call(object, property);
111
- };
519
+ };
520
+ })();
521
+
522
+
523
+ ModernizrProto.mq = mq;
524
+
525
+
526
+
527
+ /**
528
+ * testStyles injects an element with style element and some CSS rules
529
+ *
530
+ * @memberof Modernizr
531
+ * @name Modernizr.testStyles
532
+ * @optionName Modernizr.testStyles()
533
+ * @optionProp testStyles
534
+ * @access public
535
+ * @function testStyles
536
+ * @param {string} rule - String representing a css rule
537
+ * @param {function} callback - A function that is used to test the injected element
538
+ * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
539
+ * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
540
+ * @returns {boolean}
541
+ * @example
542
+ *
543
+ * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
544
+ * along with (possibly multiple) DOM elements. This lets you check for features
545
+ * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
546
+ *
547
+ * ```js
548
+ * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
549
+ * // elem is the first DOM node in the page (by default #modernizr)
550
+ * // rule is the first argument you supplied - the CSS rule in string form
551
+ *
552
+ * addTest('widthworks', elem.style.width === '9px')
553
+ * });
554
+ * ```
555
+ *
556
+ * If your test requires multiple nodes, you can include a third argument
557
+ * indicating how many additional div elements to include on the page. The
558
+ * additional nodes are injected as children of the `elem` that is returned as
559
+ * the first argument to the callback.
560
+ *
561
+ * ```js
562
+ * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
563
+ * document.getElementById('modernizr').style.width === '1px'; // true
564
+ * document.getElementById('modernizr2').style.width === '2px'; // true
565
+ * elem.firstChild === document.getElementById('modernizr2'); // true
566
+ * }, 1);
567
+ * ```
568
+ *
569
+ * By default, all of the additional elements have an ID of `modernizr[n]`, where
570
+ * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
571
+ * the second additional is `#modernizr3`, etc.).
572
+ * If you want to have more meaningful IDs for your function, you can provide
573
+ * them as the fourth argument, as an array of strings
574
+ *
575
+ * ```js
576
+ * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
577
+ * elem.firstChild === document.getElementById('foo'); // true
578
+ * elem.lastChild === document.getElementById('bar'); // true
579
+ * }, 2, ['foo', 'bar']);
580
+ * ```
581
+ *
582
+ */
583
+
584
+ var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
585
+
586
+ /*!
587
+ {
588
+ "name": "Touch Events",
589
+ "property": "touchevents",
590
+ "caniuse" : "touch",
591
+ "tags": ["media", "attribute"],
592
+ "notes": [{
593
+ "name": "Touch Events spec",
594
+ "href": "http://www.w3.org/TR/2013/WD-touch-events-20130124/"
595
+ }],
596
+ "warnings": [
597
+ "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
598
+ ],
599
+ "knownBugs": [
600
+ "False-positive on some configurations of Nokia N900",
601
+ "False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
602
+ ]
603
+ }
604
+ !*/
605
+ /* DOC
606
+ Indicates if the browser supports the W3C Touch Events API.
607
+
608
+ This *does not* necessarily reflect a touchscreen device:
609
+
610
+ * Older touchscreen devices only emulate mouse events
611
+ * Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
612
+ * Some browsers & OS setups may enable touch APIs when no touchscreen is connected
613
+ * Future browsers may implement other event models for touch interactions
614
+
615
+ See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
616
+
617
+ It's recommended to bind both mouse and touch/pointer events simultaneously – see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/).
618
+
619
+ This test will also return `true` for Firefox 4 Multitouch support.
620
+ */
621
+
622
+ // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
623
+ Modernizr.addTest('touchevents', function() {
624
+ var bool;
625
+ if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
626
+ bool = true;
627
+ } else {
628
+ var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
629
+ testStyles(query, function(node) {
630
+ bool = node.offsetTop === 9;
631
+ });
112
632
  }
113
- else {
114
- hasOwnProp = function (object, property) {
115
- return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
116
- };
633
+ return bool;
634
+ });
635
+
636
+
637
+ var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
638
+ ModernizrProto._cssomPrefixes = cssomPrefixes;
639
+
640
+
641
+ /**
642
+ * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
643
+ * some prefixed form, or false, in the case of an unsupported rule
644
+ *
645
+ * @memberof Modernizr
646
+ * @name Modernizr.atRule
647
+ * @optionName Modernizr.atRule()
648
+ * @optionProp atRule
649
+ * @access public
650
+ * @function atRule
651
+ * @param {string} prop - String name of the @-rule to test for
652
+ * @returns {string|boolean} The string representing the (possibly prefixed)
653
+ * valid version of the @-rule, or `false` when it is unsupported.
654
+ * @example
655
+ * ```js
656
+ * var keyframes = Modernizr.atRule('@keyframes');
657
+ *
658
+ * if (keyframes) {
659
+ * // keyframes are supported
660
+ * // could be `@-webkit-keyframes` or `@keyframes`
661
+ * } else {
662
+ * // keyframes === `false`
663
+ * }
664
+ * ```
665
+ *
666
+ */
667
+
668
+ var atRule = function(prop) {
669
+ var length = prefixes.length;
670
+ var cssrule = window.CSSRule;
671
+ var rule;
672
+
673
+ if (typeof cssrule === 'undefined') {
674
+ return undefined;
117
675
  }
118
676
 
119
-
120
- if (!Function.prototype.bind) {
121
- Function.prototype.bind = function bind(that) {
122
-
123
- var target = this;
124
-
125
- if (typeof target != "function") {
126
- throw new TypeError();
127
- }
128
-
129
- var args = slice.call(arguments, 1),
130
- bound = function () {
131
-
132
- if (this instanceof bound) {
133
-
134
- var F = function(){};
135
- F.prototype = target.prototype;
136
- var self = new F();
137
-
138
- var result = target.apply(
139
- self,
140
- args.concat(slice.call(arguments))
141
- );
142
- if (Object(result) === result) {
143
- return result;
144
- }
145
- return self;
146
-
147
- } else {
148
-
149
- return target.apply(
150
- that,
151
- args.concat(slice.call(arguments))
152
- );
153
-
154
- }
155
-
156
- };
157
-
158
- return bound;
159
- };
677
+ if (!prop) {
678
+ return false;
160
679
  }
161
680
 
162
- function setCss( str ) {
163
- mStyle.cssText = str;
164
- }
681
+ // remove literal @ from beginning of provided property
682
+ prop = prop.replace(/^@/, '');
165
683
 
166
- function setCssAll( str1, str2 ) {
167
- return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
168
- }
684
+ // CSSRules use underscores instead of dashes
685
+ rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
169
686
 
170
- function is( obj, type ) {
171
- return typeof obj === type;
687
+ if (rule in cssrule) {
688
+ return '@' + prop;
172
689
  }
173
690
 
174
- function contains( str, substr ) {
175
- return !!~('' + str).indexOf(substr);
176
- }
691
+ for (var i = 0; i < length; i++) {
692
+ // prefixes gives us something like -o-, and we want O_
693
+ var prefix = prefixes[i];
694
+ var thisRule = prefix.toUpperCase() + '_' + rule;
177
695
 
178
- function testProps( props, prefixed ) {
179
- for ( var i in props ) {
180
- var prop = props[i];
181
- if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
182
- return prefixed == 'pfx' ? prop : true;
183
- }
184
- }
185
- return false;
696
+ if (thisRule in cssrule) {
697
+ return '@-' + prefix.toLowerCase() + '-' + prop;
698
+ }
186
699
  }
187
700
 
188
- function testDOMProps( props, obj, elem ) {
189
- for ( var i in props ) {
190
- var item = obj[props[i]];
191
- if ( item !== undefined) {
701
+ return false;
702
+ };
192
703
 
193
- if (elem === false) return props[i];
704
+ ModernizrProto.atRule = atRule;
194
705
 
195
- if (is(item, 'function')){
196
- return item.bind(elem || obj);
197
- }
198
706
 
199
- return item;
200
- }
201
- }
202
- return false;
203
- }
204
707
 
205
- function testPropsAll( prop, prefixed, elem ) {
206
708
 
207
- var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
208
- props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
709
+ /**
710
+ * contains checks to see if a string contains another string
711
+ *
712
+ * @access private
713
+ * @function contains
714
+ * @param {string} str - The string we want to check for substrings
715
+ * @param {string} substr - The substring we want to search the first string for
716
+ * @returns {boolean}
717
+ */
209
718
 
210
- if(is(prefixed, "string") || is(prefixed, "undefined")) {
211
- return testProps(props, prefixed);
719
+ function contains(str, substr) {
720
+ return !!~('' + str).indexOf(substr);
721
+ }
212
722
 
213
- } else {
214
- props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
215
- return testDOMProps(props, prefixed, elem);
216
- }
217
- } tests['touch'] = function() {
218
- var bool;
219
-
220
- if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
221
- bool = true;
222
- } else {
223
- injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
224
- bool = node.offsetTop === 9;
225
- });
226
- }
723
+ ;
227
724
 
228
- return bool;
229
- };
230
- tests['cssanimations'] = function() {
231
- return testPropsAll('animationName');
232
- };
725
+ /**
726
+ * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
727
+ *
728
+ * @access private
729
+ * @function fnBind
730
+ * @param {function} fn - a function you want to change `this` reference to
731
+ * @param {object} that - the `this` you want to call the function with
732
+ * @returns {function} The wrapped version of the supplied function
733
+ */
233
734
 
234
-
235
- tests['csstransitions'] = function() {
236
- return testPropsAll('transition');
735
+ function fnBind(fn, that) {
736
+ return function() {
737
+ return fn.apply(that, arguments);
237
738
  };
739
+ }
740
+
741
+ ;
742
+
743
+ /**
744
+ * testDOMProps is a generic DOM property test; if a browser supports
745
+ * a certain property, it won't return undefined for it.
746
+ *
747
+ * @access private
748
+ * @function testDOMProps
749
+ * @param {array.<string>} props - An array of properties to test for
750
+ * @param {object} obj - An object or Element you want to use to test the parameters again
751
+ * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
752
+ */
753
+ function testDOMProps(props, obj, elem) {
754
+ var item;
755
+
756
+ for (var i in props) {
757
+ if (props[i] in obj) {
758
+
759
+ // return the property name as a string
760
+ if (elem === false) {
761
+ return props[i];
762
+ }
238
763
 
764
+ item = obj[props[i]];
239
765
 
766
+ // let's bind a function
767
+ if (is(item, 'function')) {
768
+ // bind to obj unless overriden
769
+ return fnBind(item, elem || obj);
770
+ }
240
771
 
241
- for ( var feature in tests ) {
242
- if ( hasOwnProp(tests, feature) ) {
243
- featureName = feature.toLowerCase();
244
- Modernizr[featureName] = tests[feature]();
245
-
246
- classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
772
+ // return the unbound function or obj or value
773
+ return item;
774
+ }
775
+ }
776
+ return false;
777
+ }
778
+
779
+ ;
780
+
781
+ /**
782
+ * Create our "modernizr" element that we do most feature tests on.
783
+ *
784
+ * @access private
785
+ */
786
+
787
+ var modElem = {
788
+ elem: createElement('modernizr')
789
+ };
790
+
791
+ // Clean up this element
792
+ Modernizr._q.push(function() {
793
+ delete modElem.elem;
794
+ });
795
+
796
+
797
+
798
+ var mStyle = {
799
+ style: modElem.elem.style
800
+ };
801
+
802
+ // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
803
+ // the front of the queue.
804
+ Modernizr._q.unshift(function() {
805
+ delete mStyle.style;
806
+ });
807
+
808
+
809
+
810
+ /**
811
+ * domToCSS takes a camelCase string and converts it to kebab-case
812
+ * e.g. boxSizing -> box-sizing
813
+ *
814
+ * @access private
815
+ * @function domToCSS
816
+ * @param {string} name - String name of camelCase prop we want to convert
817
+ * @returns {string} The kebab-case version of the supplied name
818
+ */
819
+
820
+ function domToCSS(name) {
821
+ return name.replace(/([A-Z])/g, function(str, m1) {
822
+ return '-' + m1.toLowerCase();
823
+ }).replace(/^ms-/, '-ms-');
824
+ }
825
+ ;
826
+
827
+ /**
828
+ * nativeTestProps allows for us to use native feature detection functionality if available.
829
+ * some prefixed form, or false, in the case of an unsupported rule
830
+ *
831
+ * @access private
832
+ * @function nativeTestProps
833
+ * @param {array} props - An array of property names
834
+ * @param {string} value - A string representing the value we want to check via @supports
835
+ * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
836
+ */
837
+
838
+ // Accepts a list of property names and a single value
839
+ // Returns `undefined` if native detection not available
840
+ function nativeTestProps(props, value) {
841
+ var i = props.length;
842
+ // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
843
+ if ('CSS' in window && 'supports' in window.CSS) {
844
+ // Try every prefixed variant of the property
845
+ while (i--) {
846
+ if (window.CSS.supports(domToCSS(props[i]), value)) {
847
+ return true;
247
848
  }
849
+ }
850
+ return false;
248
851
  }
852
+ // Otherwise fall back to at-rule (for Opera 12.x)
853
+ else if ('CSSSupportsRule' in window) {
854
+ // Build a condition string for every prefixed variant
855
+ var conditionText = [];
856
+ while (i--) {
857
+ conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
858
+ }
859
+ conditionText = conditionText.join(' or ');
860
+ return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
861
+ return getComputedStyle(node, null).position == 'absolute';
862
+ });
863
+ }
864
+ return undefined;
865
+ }
866
+ ;
249
867
 
868
+ // testProps is a generic CSS / DOM property test.
250
869
 
870
+ // In testing support for a given CSS property, it's legit to test:
871
+ // `elem.style[styleName] !== undefined`
872
+ // If the property is supported it will return an empty string,
873
+ // if unsupported it will return undefined.
251
874
 
252
- Modernizr.addTest = function ( feature, test ) {
253
- if ( typeof feature == 'object' ) {
254
- for ( var key in feature ) {
255
- if ( hasOwnProp( feature, key ) ) {
256
- Modernizr.addTest( key, feature[ key ] );
257
- }
258
- }
259
- } else {
260
-
261
- feature = feature.toLowerCase();
262
-
263
- if ( Modernizr[feature] !== undefined ) {
264
- return Modernizr;
265
- }
266
-
267
- test = typeof test == 'function' ? test() : test;
268
-
269
- if (typeof enableClasses !== "undefined" && enableClasses) {
270
- docElement.className+=" modernizr-" + (test ? '' : 'no-') + feature;
271
- }
272
- Modernizr[feature] = test;
273
-
274
- }
275
-
276
- return Modernizr;
277
- };
278
-
279
-
280
- setCss('');
281
- modElem = inputElem = null;
875
+ // We'll take advantage of this quick test and skip setting a style
876
+ // on our modernizr element, but instead just testing undefined vs
877
+ // empty string.
282
878
 
879
+ // Property names can be provided in either camelCase or kebab-case.
283
880
 
284
- Modernizr._version = version;
881
+ function testProps(props, prefixed, value, skipValueTest) {
882
+ skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
285
883
 
286
- Modernizr._prefixes = prefixes;
287
- Modernizr._domPrefixes = domPrefixes;
288
- Modernizr._cssomPrefixes = cssomPrefixes;
884
+ // Try native detect first
885
+ if (!is(value, 'undefined')) {
886
+ var result = nativeTestProps(props, value);
887
+ if (!is(result, 'undefined')) {
888
+ return result;
889
+ }
890
+ }
289
891
 
290
- Modernizr.mq = testMediaQuery;
892
+ // Otherwise do it properly
893
+ var afterInit, i, propsLength, prop, before;
291
894
 
895
+ // If we don't have a style element, that means we're running async or after
896
+ // the core tests, so we'll need to create our own elements to use
292
897
 
293
- Modernizr.testProp = function(prop){
294
- return testProps([prop]);
295
- };
898
+ // inside of an SVG element, in certain browsers, the `style` element is only
899
+ // defined for valid tags. Therefore, if `modernizr` does not have one, we
900
+ // fall back to a less used element and hope for the best.
901
+ var elems = ['modernizr', 'tspan'];
902
+ while (!mStyle.style) {
903
+ afterInit = true;
904
+ mStyle.modElem = createElement(elems.shift());
905
+ mStyle.style = mStyle.modElem.style;
906
+ }
296
907
 
297
- Modernizr.testAllProps = testPropsAll;
908
+ // Delete the objects if we created them.
909
+ function cleanElems() {
910
+ if (afterInit) {
911
+ delete mStyle.style;
912
+ delete mStyle.modElem;
913
+ }
914
+ }
298
915
 
916
+ propsLength = props.length;
917
+ for (i = 0; i < propsLength; i++) {
918
+ prop = props[i];
919
+ before = mStyle.style[prop];
299
920
 
300
- Modernizr.testStyles = injectElementWithStyles;
301
- Modernizr.prefixed = function(prop, obj, elem){
302
- if(!obj) {
303
- return testPropsAll(prop, 'pfx');
304
- } else {
305
- return testPropsAll(prop, obj, elem);
921
+ if (contains(prop, '-')) {
922
+ prop = cssToDOM(prop);
306
923
  }
307
- };
308
-
309
924
 
310
- docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
925
+ if (mStyle.style[prop] !== undefined) {
926
+
927
+ // If value to test has been passed in, do a set-and-check test.
928
+ // 0 (integer) is a valid property value, so check that `value` isn't
929
+ // undefined, rather than just checking it's truthy.
930
+ if (!skipValueTest && !is(value, 'undefined')) {
931
+
932
+ // Needs a try catch block because of old IE. This is slow, but will
933
+ // be avoided in most cases because `skipValueTest` will be used.
934
+ try {
935
+ mStyle.style[prop] = value;
936
+ } catch (e) {}
937
+
938
+ // If the property value has changed, we assume the value used is
939
+ // supported. If `value` is empty string, it'll fail here (because
940
+ // it hasn't changed), which matches how browsers have implemented
941
+ // CSS.supports()
942
+ if (mStyle.style[prop] != before) {
943
+ cleanElems();
944
+ return prefixed == 'pfx' ? prop : true;
945
+ }
946
+ }
947
+ // Otherwise just return true, or the property name if this is a
948
+ // `prefixed()` call
949
+ else {
950
+ cleanElems();
951
+ return prefixed == 'pfx' ? prop : true;
952
+ }
953
+ }
954
+ }
955
+ cleanElems();
956
+ return false;
957
+ }
958
+
959
+ ;
960
+
961
+ /**
962
+ * testProp() investigates whether a given style property is recognized
963
+ * Property names can be provided in either camelCase or kebab-case.
964
+ *
965
+ * @memberof Modernizr
966
+ * @name Modernizr.testProp
967
+ * @access public
968
+ * @optionName Modernizr.testProp()
969
+ * @optionProp testProp
970
+ * @function testProp
971
+ * @param {string} prop - Name of the CSS property to check
972
+ * @param {string} [value] - Name of the CSS value to check
973
+ * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
974
+ * @returns {boolean}
975
+ * @example
976
+ *
977
+ * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
978
+ * version of the string.
979
+ *
980
+ * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
981
+ *
982
+ * ```js
983
+ * Modernizr.testProp('pointerEvents') // true
984
+ * ```
985
+ *
986
+ * You can also provide a value as an optional second argument to check if a
987
+ * specific value is supported
988
+ *
989
+ * ```js
990
+ * Modernizr.testProp('pointerEvents', 'none') // true
991
+ * Modernizr.testProp('pointerEvents', 'penguin') // false
992
+ * ```
993
+ */
994
+
995
+ var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
996
+ return testProps([prop], undefined, value, useValue);
997
+ };
998
+
999
+
1000
+ /**
1001
+ * testPropsAll tests a list of DOM properties we want to check against.
1002
+ * We specify literally ALL possible (known and/or likely) properties on
1003
+ * the element including the non-vendor prefixed one, for forward-
1004
+ * compatibility.
1005
+ *
1006
+ * @access private
1007
+ * @function testPropsAll
1008
+ * @param {string} prop - A string of the property to test for
1009
+ * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
1010
+ * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
1011
+ * @param {string} [value] - A string of a css value
1012
+ * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
1013
+ */
1014
+ function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
1015
+
1016
+ var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
1017
+ props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
1018
+
1019
+ // did they call .prefixed('boxSizing') or are we just testing a prop?
1020
+ if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
1021
+ return testProps(props, prefixed, value, skipValueTest);
1022
+
1023
+ // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
1024
+ } else {
1025
+ props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
1026
+ return testDOMProps(props, prefixed, elem);
1027
+ }
1028
+ }
1029
+
1030
+ // Modernizr.testAllProps() investigates whether a given style property,
1031
+ // or any of its vendor-prefixed variants, is recognized
1032
+ //
1033
+ // Note that the property names must be provided in the camelCase variant.
1034
+ // Modernizr.testAllProps('boxSizing')
1035
+ ModernizrProto.testAllProps = testPropsAll;
1036
+
1037
+
1038
+
1039
+ /**
1040
+ * prefixed returns the prefixed or nonprefixed property name variant of your input
1041
+ *
1042
+ * @memberof Modernizr
1043
+ * @name Modernizr.prefixed
1044
+ * @optionName Modernizr.prefixed()
1045
+ * @optionProp prefixed
1046
+ * @access public
1047
+ * @function prefixed
1048
+ * @param {string} prop - String name of the property to test for
1049
+ * @param {object} [obj] - An object to test for the prefixed properties on
1050
+ * @param {HTMLElement} [elem] - An element used to test specific properties against
1051
+ * @returns {string|false} The string representing the (possibly prefixed) valid
1052
+ * version of the property, or `false` when it is unsupported.
1053
+ * @example
1054
+ *
1055
+ * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
1056
+ * opposed to the css style kebab-case) form and returns the (possibly prefixed)
1057
+ * version of that property that the browser actually supports.
1058
+ *
1059
+ * For example, in older Firefox...
1060
+ * ```js
1061
+ * prefixed('boxSizing')
1062
+ * ```
1063
+ * returns 'MozBoxSizing'
1064
+ *
1065
+ * In newer Firefox, as well as any other browser that support the unprefixed
1066
+ * version would simply return `boxSizing`. Any browser that does not support
1067
+ * the property at all, it will return `false`.
1068
+ *
1069
+ * By default, prefixed is checked against a DOM element. If you want to check
1070
+ * for a property on another object, just pass it as a second argument
1071
+ *
1072
+ * ```js
1073
+ * var rAF = prefixed('requestAnimationFrame', window);
1074
+ *
1075
+ * raf(function() {
1076
+ * renderFunction();
1077
+ * })
1078
+ * ```
1079
+ *
1080
+ * Note that this will return _the actual function_ - not the name of the function.
1081
+ * If you need the actual name of the property, pass in `false` as a third argument
1082
+ *
1083
+ * ```js
1084
+ * var rAFProp = prefixed('requestAnimationFrame', window, false);
1085
+ *
1086
+ * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
1087
+ * ```
1088
+ *
1089
+ * One common use case for prefixed is if you're trying to determine which transition
1090
+ * end event to bind to, you might do something like...
1091
+ * ```js
1092
+ * var transEndEventNames = {
1093
+ * 'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
1094
+ * 'MozTransition' : 'transitionend', * only for FF < 15
1095
+ * 'transition' : 'transitionend' * IE10, Opera, Chrome, FF 15+, Saf 7+
1096
+ * };
1097
+ *
1098
+ * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
1099
+ * ```
1100
+ *
1101
+ * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
1102
+ */
1103
+
1104
+ var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
1105
+ if (prop.indexOf('@') === 0) {
1106
+ return atRule(prop);
1107
+ }
311
1108
 
312
- (enableClasses ? " modernizr-js modernizr-"+classes.join(" modernizr-") : '');
1109
+ if (prop.indexOf('-') != -1) {
1110
+ // Convert kebab-case to camelCase
1111
+ prop = cssToDOM(prop);
1112
+ }
1113
+ if (!obj) {
1114
+ return testPropsAll(prop, 'pfx');
1115
+ } else {
1116
+ // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
1117
+ return testPropsAll(prop, obj, elem);
1118
+ }
1119
+ };
1120
+
1121
+
1122
+
1123
+ /**
1124
+ * testAllProps determines whether a given CSS property is supported in the browser
1125
+ *
1126
+ * @memberof Modernizr
1127
+ * @name Modernizr.testAllProps
1128
+ * @optionName Modernizr.testAllProps()
1129
+ * @optionProp testAllProps
1130
+ * @access public
1131
+ * @function testAllProps
1132
+ * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
1133
+ * @param {string} [value] - String of the value to test
1134
+ * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
1135
+ * @example
1136
+ *
1137
+ * testAllProps determines whether a given CSS property, in some prefixed form,
1138
+ * is supported by the browser.
1139
+ *
1140
+ * ```js
1141
+ * testAllProps('boxSizing') // true
1142
+ * ```
1143
+ *
1144
+ * It can optionally be given a CSS value in string form to test if a property
1145
+ * value is valid
1146
+ *
1147
+ * ```js
1148
+ * testAllProps('display', 'block') // true
1149
+ * testAllProps('display', 'penguin') // false
1150
+ * ```
1151
+ *
1152
+ * A boolean can be passed as a third parameter to skip the value check when
1153
+ * native detection (@supports) isn't available.
1154
+ *
1155
+ * ```js
1156
+ * testAllProps('shapeOutside', 'content-box', true);
1157
+ * ```
1158
+ */
1159
+
1160
+ function testAllProps(prop, value, skipValueTest) {
1161
+ return testPropsAll(prop, undefined, undefined, value, skipValueTest);
1162
+ }
1163
+ ModernizrProto.testAllProps = testAllProps;
1164
+
1165
+ /*!
1166
+ {
1167
+ "name": "CSS Animations",
1168
+ "property": "cssanimations",
1169
+ "caniuse": "css-animation",
1170
+ "polyfills": ["transformie", "csssandpaper"],
1171
+ "tags": ["css"],
1172
+ "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
1173
+ "notes": [{
1174
+ "name" : "Article: 'Dispelling the Android CSS animation myths'",
1175
+ "href": "http://goo.gl/OGw5Gm"
1176
+ }]
1177
+ }
1178
+ !*/
1179
+ /* DOC
1180
+ Detects whether or not elements can be animated using CSS
1181
+ */
1182
+
1183
+ Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
1184
+
1185
+ /*!
1186
+ {
1187
+ "name": "CSS Transitions",
1188
+ "property": "csstransitions",
1189
+ "caniuse": "css-transitions",
1190
+ "tags": ["css"]
1191
+ }
1192
+ !*/
1193
+
1194
+ Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
1195
+
1196
+
1197
+ // Run each test
1198
+ testRunner();
1199
+
1200
+ // Remove the "no-js" class if it exists
1201
+ setClasses(classes);
1202
+
1203
+ delete ModernizrProto.addTest;
1204
+ delete ModernizrProto.addAsyncTest;
1205
+
1206
+ // Run the things that are supposed to run after the tests
1207
+ for (var i = 0; i < Modernizr._q.length; i++) {
1208
+ Modernizr._q[i]();
1209
+ }
1210
+
1211
+ // Leak Modernizr namespace
1212
+ window.Modernizr = Modernizr;
313
1213
 
314
- return Modernizr;
315
1214
 
316
- })(this, this.document);
317
1215
  ;
1216
+
1217
+ })(window, document);