weblinc-modernizr-rails 1.0.0 → 2.0.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.
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);