Completed
Push — master ( 5bf5a9...80b817 )
by Rain
01:36
created

vendors/modernizr/modernizr-custom.js   F

Complexity

Total Complexity 87
Complexity/F 2.9

Size

Lines of Code 881
Function Count 30

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 0
wmc 87
nc 393216
mnd 5
bc 77
fnc 30
dl 0
loc 881
rs 2.1818
bpm 2.5666
cpm 2.9
noi 8
c 2
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like vendors/modernizr/modernizr-custom.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * modernizr v3.3.1
3
 * Build http://modernizr.com/download?-backgroundsize-boxshadow-cssanimations-csstransitions-rgba-textshadow-setclasses-dontmin
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
15
 */
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
*/
24
25
;(function(window, document, undefined){
26
  var classes = [];
27
28
29
  var tests = [];
30
31
32
  /**
33
   *
34
   * ModernizrProto is the constructor for Modernizr
35
   *
36
   * @class
37
   * @access public
38
   */
39
40
  var ModernizrProto = {
41
    // The current version, dummy
42
    _version: '3.3.1',
43
44
    // Any settings that don't work as separate modules
45
    // can go in here as configuration.
46
    _config: {
47
      'classPrefix': '',
48
      'enableClasses': true,
49
      'enableJSClass': true,
50
      'usePrefixes': true
51
    },
52
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
    },
69
70
    addTest: function(name, fn, options) {
71
      tests.push({name: name, fn: fn, options: options});
72
    },
73
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
   * is returns a boolean if the typeof an obj is exactly type.
93
   *
94
   * @access private
95
   * @function is
96
   * @param {*} obj - A thing we want to check the type of
97
   * @param {string} type - A string to compare the typeof against
98
   * @returns {boolean}
99
   */
100
101
  function is(obj, type) {
102
    return typeof obj === type;
103
  }
104
  ;
105
106
  /**
107
   * Run through all tests and detect their support in the current UA.
108
   *
109
   * @access private
110
   */
111
112
  function testRunner() {
113
    var featureNames;
114
    var feature;
115
    var aliasIdx;
116
    var result;
117
    var nameIdx;
118
    var featureName;
119
    var featureNameSplit;
120
121
    for (var featureIdx in tests) {
122
      if (tests.hasOwnProperty(featureIdx)) {
123
        featureNames = [];
124
        feature = tests[featureIdx];
125
        // run the test, throw the return value into the Modernizr,
126
        // then based on that boolean, define an appropriate className
127
        // and push it into an array of classes we'll join later.
128
        //
129
        // If there is no name, it's an 'async' test that is run,
130
        // but not directly added to the object. That should
131
        // be done with a post-run addTest call.
132
        if (feature.name) {
133
          featureNames.push(feature.name.toLowerCase());
134
135
          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
136
            // Add all the aliases into the names list
137
            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
138
              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
139
            }
140
          }
141
        }
142
143
        // Run the test, or use the raw value if it's not a function
144
        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
145
146
147
        // Set each of the names on the Modernizr object
148
        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
149
          featureName = featureNames[nameIdx];
150
          // Support dot properties as sub tests. We don't do checking to make sure
151
          // that the implied parent tests have been added. You must call them in
152
          // order (either in the test, or make the parent test a dependency).
153
          //
154
          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
155
          // hashtag famous last words
156
          featureNameSplit = featureName.split('.');
157
158
          if (featureNameSplit.length === 1) {
159
            Modernizr[featureNameSplit[0]] = result;
160
          } else {
161
            // cast to a Boolean, if not one already
162
            /* jshint -W053 */
163
            if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
164
              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
165
            }
166
167
            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
168
          }
169
170
          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
171
        }
172
      }
173
    }
174
  }
175
  ;
176
177
  /**
178
   * docElement is a convenience wrapper to grab the root element of the document
179
   *
180
   * @access private
181
   * @returns {HTMLElement|SVGElement} The root element of the document
182
   */
183
184
  var docElement = document.documentElement;
185
186
187
  /**
188
   * A convenience helper to check if the document we are running in is an SVG document
189
   *
190
   * @access private
191
   * @returns {boolean}
192
   */
193
194
  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
195
196
197
  /**
198
   * setClasses takes an array of class names and adds them to the root element
199
   *
200
   * @access private
201
   * @function setClasses
202
   * @param {string[]} classes - Array of class names
203
   */
204
205
  // Pass in an and array of class names, e.g.:
206
  //  ['no-webp', 'borderradius', ...]
207
  function setClasses(classes) {
208
    var className = docElement.className;
209
    var classPrefix = Modernizr._config.classPrefix || '';
210
211
    if (isSVG) {
212
      className = className.baseVal;
213
    }
214
215
    // Change `no-js` to `js` (independently of the `enableClasses` option)
216
    // Handle classPrefix on this too
217
    if (Modernizr._config.enableJSClass) {
218
      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
219
      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
220
    }
221
222
    if (Modernizr._config.enableClasses) {
223
      // Add the new classes
224
      className += ' ' + classPrefix + classes.join(' ' + classPrefix);
225
      isSVG ? docElement.className.baseVal = className : docElement.className = className;
226
    }
227
228
  }
229
230
  ;
231
232
  /**
233
   * createElement is a convenience wrapper around document.createElement. Since we
234
   * use createElement all over the place, this allows for (slightly) smaller code
235
   * as well as abstracting away issues with creating elements in contexts other than
236
   * HTML documents (e.g. SVG documents).
237
   *
238
   * @access private
239
   * @function createElement
240
   * @returns {HTMLElement|SVGElement} An HTML or SVG element
241
   */
242
243
  function createElement() {
244
    if (typeof document.createElement !== 'function') {
245
      // This is the case in IE7, where the type of createElement is "object".
246
      // For this reason, we cannot call apply() as Object is not a Function.
247
      return document.createElement(arguments[0]);
248
    } else if (isSVG) {
249
      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
250
    } else {
251
      return document.createElement.apply(document, arguments);
252
    }
253
  }
254
255
  ;
256
/*!
257
{
258
  "name": "CSS rgba",
259
  "caniuse": "css3-colors",
260
  "property": "rgba",
261
  "tags": ["css"],
262
  "notes": [{
263
    "name": "CSSTricks Tutorial",
264
    "href": "https://css-tricks.com/rgba-browser-support/"
265
  }]
266
}
267
!*/
268
269
  Modernizr.addTest('rgba', function() {
270
    var style = createElement('a').style;
271
    style.cssText = 'background-color:rgba(150,255,150,.5)';
272
273
    return ('' + style.backgroundColor).indexOf('rgba') > -1;
274
  });
275
276
277
278
  /**
279
   * contains checks to see if a string contains another string
280
   *
281
   * @access private
282
   * @function contains
283
   * @param {string} str - The string we want to check for substrings
284
   * @param {string} substr - The substring we want to search the first string for
285
   * @returns {boolean}
286
   */
287
288
  function contains(str, substr) {
289
    return !!~('' + str).indexOf(substr);
290
  }
291
292
  ;
293
294
  /**
295
   * cssToDOM takes a kebab-case string and converts it to camelCase
296
   * e.g. box-sizing -> boxSizing
297
   *
298
   * @access private
299
   * @function cssToDOM
300
   * @param {string} name - String name of kebab-case prop we want to convert
301
   * @returns {string} The camelCase version of the supplied name
302
   */
303
304
  function cssToDOM(name) {
305
    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
306
      return m1 + m2.toUpperCase();
307
    }).replace(/^-/, '');
308
  }
309
  ;
310
311
  /**
312
   * If the browsers follow the spec, then they would expose vendor-specific style as:
313
   *   elem.style.WebkitBorderRadius
314
   * instead of something like the following, which would be technically incorrect:
315
   *   elem.style.webkitBorderRadius
316
317
   * Webkit ghosts their properties in lowercase but Opera & Moz do not.
318
   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
319
   *   erik.eae.net/archives/2008/03/10/21.48.10/
320
321
   * More here: github.com/Modernizr/Modernizr/issues/issue/21
322
   *
323
   * @access private
324
   * @returns {string} The string representing the vendor-specific style properties
325
   */
326
327
  var omPrefixes = 'Moz O ms Webkit';
328
329
330
  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
331
  ModernizrProto._cssomPrefixes = cssomPrefixes;
332
333
334
  /**
335
   * List of JavaScript DOM values used for tests
336
   *
337
   * @memberof Modernizr
338
   * @name Modernizr._domPrefixes
339
   * @optionName Modernizr._domPrefixes
340
   * @optionProp domPrefixes
341
   * @access public
342
   * @example
343
   *
344
   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
345
   * than kebab-case properties, all properties are their Capitalized variant
346
   *
347
   * ```js
348
   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
349
   * ```
350
   */
351
352
  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
353
  ModernizrProto._domPrefixes = domPrefixes;
354
355
356
  /**
357
   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
358
   *
359
   * @access private
360
   * @function fnBind
361
   * @param {function} fn - a function you want to change `this` reference to
362
   * @param {object} that - the `this` you want to call the function with
363
   * @returns {function} The wrapped version of the supplied function
364
   */
365
366
  function fnBind(fn, that) {
367
    return function() {
368
      return fn.apply(that, arguments);
369
    };
370
  }
371
372
  ;
373
374
  /**
375
   * testDOMProps is a generic DOM property test; if a browser supports
376
   *   a certain property, it won't return undefined for it.
377
   *
378
   * @access private
379
   * @function testDOMProps
380
   * @param {array.<string>} props - An array of properties to test for
381
   * @param {object} obj - An object or Element you want to use to test the parameters again
382
   * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
383
   */
384
  function testDOMProps(props, obj, elem) {
385
    var item;
386
387
    for (var i in props) {
388
      if (props[i] in obj) {
389
390
        // return the property name as a string
391
        if (elem === false) {
392
          return props[i];
393
        }
394
395
        item = obj[props[i]];
396
397
        // let's bind a function
398
        if (is(item, 'function')) {
399
          // bind to obj unless overriden
400
          return fnBind(item, elem || obj);
401
        }
402
403
        // return the unbound function or obj or value
404
        return item;
405
      }
406
    }
407
    return false;
408
  }
409
410
  ;
411
412
  /**
413
   * Create our "modernizr" element that we do most feature tests on.
414
   *
415
   * @access private
416
   */
417
418
  var modElem = {
419
    elem: createElement('modernizr')
420
  };
421
422
  // Clean up this element
423
  Modernizr._q.push(function() {
424
    delete modElem.elem;
425
  });
426
427
428
429
  var mStyle = {
430
    style: modElem.elem.style
431
  };
432
433
  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
434
  // the front of the queue.
435
  Modernizr._q.unshift(function() {
436
    delete mStyle.style;
437
  });
438
439
440
441
  /**
442
   * domToCSS takes a camelCase string and converts it to kebab-case
443
   * e.g. boxSizing -> box-sizing
444
   *
445
   * @access private
446
   * @function domToCSS
447
   * @param {string} name - String name of camelCase prop we want to convert
448
   * @returns {string} The kebab-case version of the supplied name
449
   */
450
451
  function domToCSS(name) {
452
    return name.replace(/([A-Z])/g, function(str, m1) {
453
      return '-' + m1.toLowerCase();
454
    }).replace(/^ms-/, '-ms-');
455
  }
456
  ;
457
458
  /**
459
   * getBody returns the body of a document, or an element that can stand in for
460
   * the body if a real body does not exist
461
   *
462
   * @access private
463
   * @function getBody
464
   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
465
   * artificially created element that stands in for the body
466
   */
467
468
  function getBody() {
469
    // After page load injecting a fake body doesn't work so check if body exists
470
    var body = document.body;
471
472
    if (!body) {
473
      // Can't use the real body create a fake one.
474
      body = createElement(isSVG ? 'svg' : 'body');
475
      body.fake = true;
476
    }
477
478
    return body;
479
  }
480
481
  ;
482
483
  /**
484
   * injectElementWithStyles injects an element with style element and some CSS rules
485
   *
486
   * @access private
487
   * @function injectElementWithStyles
488
   * @param {string} rule - String representing a css rule
489
   * @param {function} callback - A function that is used to test the injected element
490
   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
491
   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
492
   * @returns {boolean}
493
   */
494
495
  function injectElementWithStyles(rule, callback, nodes, testnames) {
496
    var mod = 'modernizr';
497
    var style;
498
    var ret;
499
    var node;
500
    var docOverflow;
501
    var div = createElement('div');
502
    var body = getBody();
503
504
    if (parseInt(nodes, 10)) {
505
      // In order not to give false positives we create a node for each test
506
      // This also allows the method to scale for unspecified uses
507
      while (nodes--) {
508
        node = createElement('div');
509
        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
510
        div.appendChild(node);
511
      }
512
    }
513
514
    style = createElement('style');
515
    style.type = 'text/css';
516
    style.id = 's' + mod;
517
518
    // 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.
519
    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
520
    (!body.fake ? div : body).appendChild(style);
521
    body.appendChild(div);
522
523
    if (style.styleSheet) {
524
      style.styleSheet.cssText = rule;
525
    } else {
526
      style.appendChild(document.createTextNode(rule));
527
    }
528
    div.id = mod;
529
530
    if (body.fake) {
531
      //avoid crashing IE8, if background image is used
532
      body.style.background = '';
533
      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
534
      body.style.overflow = 'hidden';
535
      docOverflow = docElement.style.overflow;
536
      docElement.style.overflow = 'hidden';
537
      docElement.appendChild(body);
538
    }
539
540
    ret = callback(div, rule);
541
    // If this is done after page load we don't want to remove the body so check if body exists
542
    if (body.fake) {
543
      body.parentNode.removeChild(body);
544
      docElement.style.overflow = docOverflow;
545
      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
546
      docElement.offsetHeight;
547
    } else {
548
      div.parentNode.removeChild(div);
549
    }
550
551
    return !!ret;
552
553
  }
554
555
  ;
556
557
  /**
558
   * nativeTestProps allows for us to use native feature detection functionality if available.
559
   * some prefixed form, or false, in the case of an unsupported rule
560
   *
561
   * @access private
562
   * @function nativeTestProps
563
   * @param {array} props - An array of property names
564
   * @param {string} value - A string representing the value we want to check via @supports
565
   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
566
   */
567
568
  // Accepts a list of property names and a single value
569
  // Returns `undefined` if native detection not available
570
  function nativeTestProps(props, value) {
571
    var i = props.length;
572
    // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
573
    if ('CSS' in window && 'supports' in window.CSS) {
574
      // Try every prefixed variant of the property
575
      while (i--) {
576
        if (window.CSS.supports(domToCSS(props[i]), value)) {
577
          return true;
578
        }
579
      }
580
      return false;
581
    }
582
    // Otherwise fall back to at-rule (for Opera 12.x)
583
    else if ('CSSSupportsRule' in window) {
584
      // Build a condition string for every prefixed variant
585
      var conditionText = [];
586
      while (i--) {
587
        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
588
      }
589
      conditionText = conditionText.join(' or ');
590
      return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
591
        return getComputedStyle(node, null).position == 'absolute';
592
      });
593
    }
594
    return undefined;
595
  }
596
  ;
597
598
  // testProps is a generic CSS / DOM property test.
599
600
  // In testing support for a given CSS property, it's legit to test:
601
  //    `elem.style[styleName] !== undefined`
602
  // If the property is supported it will return an empty string,
603
  // if unsupported it will return undefined.
604
605
  // We'll take advantage of this quick test and skip setting a style
606
  // on our modernizr element, but instead just testing undefined vs
607
  // empty string.
608
609
  // Property names can be provided in either camelCase or kebab-case.
610
611
  function testProps(props, prefixed, value, skipValueTest) {
612
    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
613
614
    // Try native detect first
615
    if (!is(value, 'undefined')) {
616
      var result = nativeTestProps(props, value);
617
      if (!is(result, 'undefined')) {
618
        return result;
619
      }
620
    }
621
622
    // Otherwise do it properly
623
    var afterInit, i, propsLength, prop, before;
624
625
    // If we don't have a style element, that means we're running async or after
626
    // the core tests, so we'll need to create our own elements to use
627
628
    // inside of an SVG element, in certain browsers, the `style` element is only
629
    // defined for valid tags. Therefore, if `modernizr` does not have one, we
630
    // fall back to a less used element and hope for the best.
631
    var elems = ['modernizr', 'tspan'];
632
    while (!mStyle.style) {
633
      afterInit = true;
634
      mStyle.modElem = createElement(elems.shift());
635
      mStyle.style = mStyle.modElem.style;
636
    }
637
638
    // Delete the objects if we created them.
639
    function cleanElems() {
640
      if (afterInit) {
641
        delete mStyle.style;
642
        delete mStyle.modElem;
643
      }
644
    }
645
646
    propsLength = props.length;
647
    for (i = 0; i < propsLength; i++) {
648
      prop = props[i];
649
      before = mStyle.style[prop];
650
651
      if (contains(prop, '-')) {
652
        prop = cssToDOM(prop);
653
      }
654
655
      if (mStyle.style[prop] !== undefined) {
656
657
        // If value to test has been passed in, do a set-and-check test.
658
        // 0 (integer) is a valid property value, so check that `value` isn't
659
        // undefined, rather than just checking it's truthy.
660
        if (!skipValueTest && !is(value, 'undefined')) {
661
662
          // Needs a try catch block because of old IE. This is slow, but will
663
          // be avoided in most cases because `skipValueTest` will be used.
664
          try {
665
            mStyle.style[prop] = value;
666
          } catch (e) {}
667
668
          // If the property value has changed, we assume the value used is
669
          // supported. If `value` is empty string, it'll fail here (because
670
          // it hasn't changed), which matches how browsers have implemented
671
          // CSS.supports()
672
          if (mStyle.style[prop] != before) {
673
            cleanElems();
674
            return prefixed == 'pfx' ? prop : true;
675
          }
676
        }
677
        // Otherwise just return true, or the property name if this is a
678
        // `prefixed()` call
679
        else {
680
          cleanElems();
681
          return prefixed == 'pfx' ? prop : true;
682
        }
683
      }
684
    }
685
    cleanElems();
686
    return false;
687
  }
688
689
  ;
690
691
  /**
692
   * testProp() investigates whether a given style property is recognized
693
   * Property names can be provided in either camelCase or kebab-case.
694
   *
695
   * @memberof Modernizr
696
   * @name Modernizr.testProp
697
   * @access public
698
   * @optionName Modernizr.testProp()
699
   * @optionProp testProp
700
   * @function testProp
701
   * @param {string} prop - Name of the CSS property to check
702
   * @param {string} [value] - Name of the CSS value to check
703
   * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
704
   * @returns {boolean}
705
   * @example
706
   *
707
   * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
708
   * version of the string.
709
   *
710
   * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
711
   *
712
   * ```js
713
   * Modernizr.testProp('pointerEvents')  // true
714
   * ```
715
   *
716
   * You can also provide a value as an optional second argument to check if a
717
   * specific value is supported
718
   *
719
   * ```js
720
   * Modernizr.testProp('pointerEvents', 'none') // true
721
   * Modernizr.testProp('pointerEvents', 'penguin') // false
722
   * ```
723
   */
724
725
  var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
726
    return testProps([prop], undefined, value, useValue);
727
  };
728
729
/*!
730
{
731
  "name": "CSS textshadow",
732
  "property": "textshadow",
733
  "caniuse": "css-textshadow",
734
  "tags": ["css"],
735
  "knownBugs": ["FF3.0 will false positive on this test"]
736
}
737
!*/
738
739
  Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
740
741
742
  /**
743
   * testPropsAll tests a list of DOM properties we want to check against.
744
   * We specify literally ALL possible (known and/or likely) properties on
745
   * the element including the non-vendor prefixed one, for forward-
746
   * compatibility.
747
   *
748
   * @access private
749
   * @function testPropsAll
750
   * @param {string} prop - A string of the property to test for
751
   * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
752
   * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
753
   * @param {string} [value] - A string of a css value
754
   * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
755
   */
756
  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
757
758
    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
759
    props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
760
761
    // did they call .prefixed('boxSizing') or are we just testing a prop?
762
    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
763
      return testProps(props, prefixed, value, skipValueTest);
764
765
      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
766
    } else {
767
      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
768
      return testDOMProps(props, prefixed, elem);
769
    }
770
  }
771
772
  // Modernizr.testAllProps() investigates whether a given style property,
773
  // or any of its vendor-prefixed variants, is recognized
774
  //
775
  // Note that the property names must be provided in the camelCase variant.
776
  // Modernizr.testAllProps('boxSizing')
777
  ModernizrProto.testAllProps = testPropsAll;
778
779
780
781
  /**
782
   * testAllProps determines whether a given CSS property is supported in the browser
783
   *
784
   * @memberof Modernizr
785
   * @name Modernizr.testAllProps
786
   * @optionName Modernizr.testAllProps()
787
   * @optionProp testAllProps
788
   * @access public
789
   * @function testAllProps
790
   * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
791
   * @param {string} [value] - String of the value to test
792
   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
793
   * @example
794
   *
795
   * testAllProps determines whether a given CSS property, in some prefixed form,
796
   * is supported by the browser.
797
   *
798
   * ```js
799
   * testAllProps('boxSizing')  // true
800
   * ```
801
   *
802
   * It can optionally be given a CSS value in string form to test if a property
803
   * value is valid
804
   *
805
   * ```js
806
   * testAllProps('display', 'block') // true
807
   * testAllProps('display', 'penguin') // false
808
   * ```
809
   *
810
   * A boolean can be passed as a third parameter to skip the value check when
811
   * native detection (@supports) isn't available.
812
   *
813
   * ```js
814
   * testAllProps('shapeOutside', 'content-box', true);
815
   * ```
816
   */
817
818
  function testAllProps(prop, value, skipValueTest) {
819
    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
820
  }
821
  ModernizrProto.testAllProps = testAllProps;
822
823
/*!
824
{
825
  "name": "CSS Animations",
826
  "property": "cssanimations",
827
  "caniuse": "css-animation",
828
  "polyfills": ["transformie", "csssandpaper"],
829
  "tags": ["css"],
830
  "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
831
  "notes": [{
832
    "name" : "Article: 'Dispelling the Android CSS animation myths'",
833
    "href": "https://goo.gl/OGw5Gm"
834
  }]
835
}
836
!*/
837
/* DOC
838
Detects whether or not elements can be animated using CSS
839
*/
840
841
  Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
842
843
/*!
844
{
845
  "name": "Background Size",
846
  "property": "backgroundsize",
847
  "tags": ["css"],
848
  "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"],
849
  "notes": [{
850
    "name": "Related Issue",
851
    "href": "https://github.com/Modernizr/Modernizr/issues/396"
852
  }]
853
}
854
!*/
855
856
  Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
857
858
/*!
859
{
860
  "name": "CSS Transitions",
861
  "property": "csstransitions",
862
  "caniuse": "css-transitions",
863
  "tags": ["css"]
864
}
865
!*/
866
867
  Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
868
869
/*!
870
{
871
  "name": "Box Shadow",
872
  "property": "boxshadow",
873
  "caniuse": "css-boxshadow",
874
  "tags": ["css"],
875
  "knownBugs": [
876
    "WebOS false positives on this test.",
877
    "The Kindle Silk browser false positives"
878
  ]
879
}
880
!*/
881
882
  Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
883
884
885
  // Run each test
886
  testRunner();
887
888
  // Remove the "no-js" class if it exists
889
  setClasses(classes);
890
891
  delete ModernizrProto.addTest;
892
  delete ModernizrProto.addAsyncTest;
893
894
  // Run the things that are supposed to run after the tests
895
  for (var i = 0; i < Modernizr._q.length; i++) {
896
    Modernizr._q[i]();
897
  }
898
899
  // Leak Modernizr namespace
900
  window.Modernizr = Modernizr;
901
902
903
;
904
905
})(window, document);