PageSourceSearch

https://www1.micard.co.jp/app/static/js/modernizr-custom.js?v=20170313_01

js micard.co.jp collected 2026-09-29 10:01:28 UTC 65,798 bytes, 3,627 lines download raw bytes

1/*!
2
3 * modernizr v3.3.1
4
5 * Build https://modernizr.com/download?-blobconstructor-canvas-cookies-csshairline-csspositionsticky-cssvhunit-cssvmaxunit-cssvminunit-cssvwunit-flexbox-flexboxlegacy-flexboxtweener-flexwrap-notification-svg-touchevents-video-videoautoplay-hasevent-setclasses-dontmin
6
7 *
8
9 * Copyright (c)
10
11 *  Faruk Ates
12
13 *  Paul Irish
14
15 *  Alex Sexton
16
17 *  Ryan Seddon
18
19 *  Patrick Kettner
20
21 *  Stu Cox
22
23 *  Richard Herrera
24
25
26
27 * MIT License
28
29 */
30
31
32
33/*
34
35 * Modernizr tests which native CSS3 and HTML5 features are available in the
36
37 * current UA and makes the results available to you in two ways: as properties on
38
39 * a global `Modernizr` object, and as classes on the `<html>` element. This
40
41 * information allows you to progressively enhance your pages with a granular level
42
43 * of control over the experience.
44
45*/
46
47
48
49;(function(window, document, undefined){
50
51  var classes = [];
52
53  
54
55
56
57  var tests = [];
58
59  
60
61
62
63  /**
64
65   *
66
67   * ModernizrProto is the constructor for Modernizr
68
69   *
70
71   * @class
72
73   * @access public
74
75   */
76
77
78
79  var ModernizrProto = {
80
81    // The current version, dummy
82
83    _version: '3.3.1',
84
85
86
87    // Any settings that don't work as separate modules
88
89    // can go in here as configuration.
90
91    _config: {
92
93      'classPrefix': '',
94
95      'enableClasses': true,
96
97      'enableJSClass': true,
98
99      'usePrefixes': true
100
101    },
102
103
104
105    // Queue of tests
106
107    _q: [],
108
109
110
111    // Stub these for people who are listening
112
113    on: function(test, cb) {
114
115      // I don't really think people should do this, but we can
116
117      // safe guard it a bit.
118
119      // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
120
121      // This is in case people listen to synchronous tests. I would leave it out,
122
123      // but the code to *disallow* sync tests in the real version of this
124
125      // function is actually larger than this.
126
127      var self = this;
128
129      setTimeout(function() {
130
131        cb(self[test]);
132
133      }, 0);
134
135    },
136
137
138
139    addTest: function(name, fn, options) {
140
141      tests.push({name: name, fn: fn, options: options});
142
143    },
144
145
146
147    addAsyncTest: function(fn) {
148
149      tests.push({name: null, fn: fn});
150
151    }
152
153  };
154
155
156
157  
158
159
160
161  // Fake some of Object.create so we can force non test results to be non "own" properties.
162
163  var Modernizr = function() {};
164
165  Modernizr.prototype = ModernizrProto;
166
167
168
169  // Leak modernizr globally when you `require` it rather than force it here.
170
171  // Overwrite name so constructor name is nicer :D
172
173  Modernizr = new Modernizr();
174
175
176
177  
178
179/*!
180
181{
182
183  "name": "Blob constructor",
184
185  "property": "blobconstructor",
186
187  "aliases": ["blob-constructor"],
188
189  "builderAliases": ["blob_constructor"],
190
191  "caniuse": "blobbuilder",
192
193  "notes": [{
194
195    "name": "W3C spec",
196
197    "href": "https://w3c.github.io/FileAPI/#constructorBlob"
198
199  }],
200
201  "polyfills": ["blobjs"]
202
203}
204
205!*/
206
207/* DOC
208
209Detects support for the Blob constructor, for creating file-like objects of immutable, raw data.
210
211*/
212
213
214
215  Modernizr.addTest('blobconstructor', function() {
216
217    try {
218
219      return !!new Blob();
220
221    } catch (e) {
222
223      return false;
224
225    }
226
227  }, {
228
229    aliases: ['blob-constructor']
230
231  });
232
233
234
235/*!
236
237{
238
239  "name": "Cookies",
240
241  "property": "cookies",
242
243  "tags": ["storage"],
244
245  "authors": ["tauren"]
246
247}
248
249!*/
250
251/* DOC
252
253Detects whether cookie support is enabled.
254
255*/
256
257
258
259  // https://github.com/Modernizr/Modernizr/issues/191
260
261
262
263  Modernizr.addTest('cookies', function() {
264
265    // navigator.cookieEnabled cannot detect custom or nuanced cookie blocking
266
267    // configurations. For example, when blocking cookies via the Advanced
268
269    // Privacy Settings in IE9, it always returns true. And there have been
270
271    // issues in the past with site-specific exceptions.
272
273    // Don't rely on it.
274
275
276
277    // try..catch because some in situations `document.cookie` is exposed but throws a
278
279    // SecurityError if you try to access it; e.g. documents created from data URIs
280
281    // or in sandboxed iframes (depending on flags/context)
282
283    try {
284
285      // Create cookie
286
287      document.cookie = 'cookietest=1';
288
289      var ret = document.cookie.indexOf('cookietest=') != -1;
290
291      // Delete cookie
292
293      document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
294
295      return ret;
296
297    }
298
299    catch (e) {
300
301      return false;
302
303    }
304
305  });
306
307
308
309/*!
310
311{
312
313  "name": "Notification",
314
315  "property": "notification",
316
317  "caniuse": "notifications",
318
319  "authors": ["Theodoor van Donge", "Hendrik Beskow"],
320
321  "notes": [{
322
323    "name": "HTML5 Rocks tutorial",
324
325    "href": "http://www.html5rocks.com/en/tutorials/notifications/quick/"
326
327  },{
328
329    "name": "W3C spec",
330
331    "href": "https://www.w3.org/TR/notifications/"
332
333  }, {
334
335    "name": "Changes in Chrome to Notifications API due to Service Worker Push Notifications",
336
337    "href": "https://developers.google.com/web/updates/2015/05/Notifying-you-of-notificiation-changes"
338
339  }],
340
341  "knownBugs": [
342
343    "Possibility of false-positive on Chrome for Android if permissions we're granted for a website prior to Chrome 44."
344
345  ],
346
347  "polyfills": ["desktop-notify", "html5-notifications"]
348
349}
350
351!*/
352
353/* DOC
354
355Detects support for the Notifications API
356
357*/
358
359
360
361  Modernizr.addTest('notification', function() {
362
363    if (!window.Notification || !window.Notification.requestPermission) {
364
365      return false;
366
367    }
368
369    // if permission is already granted, assume support
370
371    if (window.Notification.permission === 'granted') {
372
373      return true;
374
375    }
376
377
378
379    try {
380
381      new window.Notification('');
382
383    } catch (e) {
384
385      if (e.name === 'TypeError') {
386
387        return false;
388
389      }
390
391    }
392
393
394
395    return true;
396
397  });
398
399
400
401/*!
402
403{
404
405  "name": "SVG",
406
407  "property": "svg",
408
409  "caniuse": "svg",
410
411  "tags": ["svg"],
412
413  "authors": ["Erik Dahlstrom"],
414
415  "polyfills": [
416
417    "svgweb",
418
419    "raphael",
420
421    "amplesdk",
422
423    "canvg",
424
425    "svg-boilerplate",
426
427    "sie",
428
429    "dojogfx",
430
431    "fabricjs"
432
433  ]
434
435}
436
437!*/
438
439/* DOC
440
441Detects support for SVG in `<embed>` or `<object>` elements.
442
443*/
444
445
446
447  Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
448
449
450
451
452
453  /**
454
455   * is returns a boolean if the typeof an obj is exactly type.
456
457   *
458
459   * @access private
460
461   * @function is
462
463   * @param {*} obj - A thing we want to check the type of
464
465   * @param {string} type - A string to compare the typeof against
466
467   * @returns {boolean}
468
469   */
470
471
472
473  function is(obj, type) {
474
475    return typeof obj === type;
476
477  }
478
479  ;
480
481
482
483  /**
484
485   * Run through all tests and detect their support in the current UA.
486
487   *
488
489   * @access private
490
491   */
492
493
494
495  function testRunner() {
496
497    var featureNames;
498
499    var feature;
500
501    var aliasIdx;
502
503    var result;
504
505    var nameIdx;
506
507    var featureName;
508
509    var featureNameSplit;
510
511
512
513    for (var featureIdx in tests) {
514
515      if (tests.hasOwnProperty(featureIdx)) {
516
517        featureNames = [];
518
519        feature = tests[featureIdx];
520
521        // run the test, throw the return value into the Modernizr,
522
523        // then based on that boolean, define an appropriate className
524
525        // and push it into an array of classes we'll join later.
526
527        //
528
529        // If there is no name, it's an 'async' test that is run,
530
531        // but not directly added to the object. That should
532
533        // be done with a post-run addTest call.
534
535        if (feature.name) {
536
537          featureNames.push(feature.name.toLowerCase());
538
539
540
541          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
542
543            // Add all the aliases into the names list
544
545            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
546
547              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
548
549            }
550
551          }
552
553        }
554
555
556
557        // Run the test, or use the raw value if it's not a function
558
559        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
560
561
562
563
564
565        // Set each of the names on the Modernizr object
566
567        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
568
569          featureName = featureNames[nameIdx];
570
571          // Support dot properties as sub tests. We don't do checking to make sure
572
573          // that the implied parent tests have been added. You must call them in
574
575          // order (either in the test, or make the parent test a dependency).
576
577          //
578
579          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
580
581          // hashtag famous last words
582
583          featureNameSplit = featureName.split('.');
584
585
586
587          if (featureNameSplit.length === 1) {
588
589            Modernizr[featureNameSplit[0]] = result;
590
591          } else {
592
593            // cast to a Boolean, if not one already
594
595            /* jshint -W053 */
596
597            if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
598
599              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
600
601            }
602
603
604
605            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
606
607          }
608
609
610
611          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
612
613        }
614
615      }
616
617    }
618
619  }
620
621  ;
622
623
624
625  /**
626
627   * docElement is a convenience wrapper to grab the root element of the document
628
629   *
630
631   * @access private
632
633   * @returns {HTMLElement|SVGElement} The root element of the document
634
635   */
636
637
638
639  var docElement = document.documentElement;
640
641  
642
643
644
645  /**
646
647   * A convenience helper to check if the document we are running in is an SVG document
648
649   *
650
651   * @access private
652
653   * @returns {boolean}
654
655   */
656
657
658
659  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
660
661  
662
663
664
665  /**
666
667   * setClasses takes an array of class names and adds them to the root element
668
669   *
670
671   * @access private
672
673   * @function setClasses
674
675   * @param {string[]} classes - Array of class names
676
677   */
678
679
680
681  // Pass in an and array of class names, e.g.:
682
683  //  ['no-webp', 'borderradius', ...]
684
685  function setClasses(classes) {
686
687    var className = docElement.className;
688
689    var classPrefix = Modernizr._config.classPrefix || '';
690
691
692
693    if (isSVG) {
694
695      className = className.baseVal;
696
697    }
698
699
700
701    // Change `no-js` to `js` (independently of the `enableClasses` option)
702
703    // Handle classPrefix on this too
704
705    if (Modernizr._config.enableJSClass) {
706
707      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
708
709      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
710
711    }
712
713
714
715    if (Modernizr._config.enableClasses) {
716
717      // Add the new classes
718
719      className += ' ' + classPrefix + classes.join(' ' + classPrefix);
720
721      isSVG ? docElement.className.baseVal = className : docElement.className = className;
722
723    }
724
725
726
727  }
728
729
730
731  ;
732
733
734
735  /**
736
737   * createElement is a convenience wrapper around document.createElement. Since we
738
739   * use createElement all over the place, this allows for (slightly) smaller code
740
741   * as well as abstracting away issues with creating elements in contexts other than
742
743   * HTML documents (e.g. SVG documents).
744
745   *
746
747   * @access private
748
749   * @function createElement
750
751   * @returns {HTMLElement|SVGElement} An HTML or SVG element
752
753   */
754
755
756
757  function createElement() {
758
759    if (typeof document.createElement !== 'function') {
760
761      // This is the case in IE7, where the type of createElement is "object".
762
763      // For this reason, we cannot call apply() as Object is not a Function.
764
765      return document.createElement(arguments[0]);
766
767    } else if (isSVG) {
768
769      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
770
771    } else {
772
773      return document.createElement.apply(document, arguments);
774
775    }
776
777  }
778
779
780
781  ;
782
783
784
785  /**
786
787   * Modernizr.hasEvent() detects support for a given event
788
789   *
790
791   * @memberof Modernizr
792
793   * @name Modernizr.hasEvent
794
795   * @optionName Modernizr.hasEvent()
796
797   * @optionProp hasEvent
798
799   * @access public
800
801   * @function hasEvent
802
803   * @param  {string|*} eventName - the name of an event to test for (e.g. "resize")
804
805   * @param  {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
806
807   * @returns {boolean}
808
809   * @example
810
811   *  `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
812
813   *  By default, it does this detection on a div element
814
815   *
816
817   * ```js
818
819   *  hasEvent('blur') // true;
820
821   * ```
822
823   *
824
825   * However, you are able to give an object as a second argument to hasEvent to
826
827   * detect an event on something other than a div.
828
829   *
830
831   * ```js
832
833   *  hasEvent('devicelight', window) // true;
834
835   * ```
836
837   *
838
839   */
840
841
842
843  var hasEvent = (function() {
844
845
846
847    // Detect whether event support can be detected via `in`. Test on a DOM element
848
849    // using the "blur" event b/c it should always exist. bit.ly/event-detection
850
851    var needsFallback = !('onblur' in document.documentElement);
852
853
854
855    function inner(eventName, element) {
856
857
858
859      var isSupported;
860
861      if (!eventName) { return false; }
862
863      if (!element || typeof element === 'string') {
864
865        element = createElement(element || 'div');
866
867      }
868
869
870
871      // Testing via the `in` operator is sufficient for modern browsers and IE.
872
873      // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
874
875      // "resize", whereas `in` "catches" those.
876
877      eventName = 'on' + eventName;
878
879      isSupported = eventName in element;
880
881
882
883      // Fallback technique for old Firefox - bit.ly/event-detection
884
885      if (!isSupported && needsFallback) {
886
887        if (!element.setAttribute) {
888
889          // Switch to generic element if it lacks `setAttribute`.
890
891          // It could be the `document`, `window`, or something else.
892
893          element = createElement('div');
894
895        }
896
897
898
899        element.setAttribute(eventName, '');
900
901        isSupported = typeof element[eventName] === 'function';
902
903
904
905        if (element[eventName] !== undefined) {
906
907          // If property was created, "remove it" by setting value to `undefined`.
908
909          element[eventName] = undefined;
910
911        }
912
913        element.removeAttribute(eventName);
914
915      }
916
917
918
919      return isSupported;
920
921    }
922
923    return inner;
924
925  })();
926
927
928
929
930
931  ModernizrProto.hasEvent = hasEvent;
932
933  
934
935/*!
936
937{
938
939  "name": "Canvas",
940
941  "property": "canvas",
942
943  "caniuse": "canvas",
944
945  "tags": ["canvas", "graphics"],
946
947  "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
948
949}
950
951!*/
952
953/* DOC
954
955Detects support for the `<canvas>` element for 2D drawing.
956
957*/
958
959
960
961  // On the S60 and BB Storm, getContext exists, but always returns undefined
962
963  // so we actually have to call getContext() to verify
964
965  // github.com/Modernizr/Modernizr/issues/issue/97/
966
967  Modernizr.addTest('canvas', function() {
968
969    var elem = createElement('canvas');
970
971    return !!(elem.getContext && elem.getContext('2d'));
972
973  });
974
975
976
977/*!
978
979{
980
981  "name": "HTML5 Video",
982
983  "property": "video",
984
985  "caniuse": "video",
986
987  "tags": ["html5"],
988
989  "knownBugs": [
990
991    "Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546"
992
993  ],
994
995  "polyfills": [
996
997    "html5media",
998
999    "mediaelementjs",
1000
1001    "sublimevideo",
1002
1003    "videojs",
1004
1005    "leanbackplayer",
1006
1007    "videoforeverybody"
1008
1009  ]
1010
1011}
1012
1013!*/
1014
1015/* DOC
1016
1017Detects support for the video element, as well as testing what types of content it supports.
1018
1019
1020
1021Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.:
1022
1023
1024
1025```javascript
1026
1027Modernizr.video         // true
1028
1029Modernizr.video.ogg     // 'probably'
1030
1031```
1032
1033*/
1034
1035
1036
1037  // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
1038
1039  //                     thx to NielsLeenheer and zcorpan
1040
1041
1042
1043  // Note: in some older browsers, "no" was a return value instead of empty string.
1044
1045  //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
1046
1047  //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
1048
1049
1050
1051  Modernizr.addTest('video', function() {
1052
1053    /* jshint -W053 */
1054
1055    var elem = createElement('video');
1056
1057    var bool = false;
1058
1059
1060
1061    // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
1062
1063    try {
1064
1065      if (bool = !!elem.canPlayType) {
1066
1067        bool = new Boolean(bool);
1068
1069        bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');
1070
1071
1072
1073        // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
1074
1075        bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');
1076
1077
1078
1079        bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
1080
1081
1082
1083        bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, '');
1084
1085
1086
1087        bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, '');
1088
1089      }
1090
1091    } catch (e) {}
1092
1093
1094
1095    return bool;
1096
1097  });
1098
1099
1100
1101
1102
1103  /**
1104
1105   * List of property values to set for css tests. See ticket #21
1106
1107   * http://git.io/vUGl4
1108
1109   *
1110
1111   * @memberof Modernizr
1112
1113   * @name Modernizr._prefixes
1114
1115   * @optionName Modernizr._prefixes
1116
1117   * @optionProp prefixes
1118
1119   * @access public
1120
1121   * @example
1122
1123   *
1124
1125   * Modernizr._prefixes is the internal list of prefixes that we test against
1126
1127   * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
1128
1129   * an array of kebab-case vendor prefixes you can use within your code.
1130
1131   *
1132
1133   * Some common use cases include
1134
1135   *
1136
1137   * Generating all possible prefixed version of a CSS property
1138
1139   * ```js
1140
1141   * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
1142
1143   *
1144
1145   * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
1146
1147   * ```
1148
1149   *
1150
1151   * Generating all possible prefixed version of a CSS value
1152
1153   * ```js
1154
1155   * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
1156
1157   *
1158
1159   * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
1160
1161   * ```
1162
1163   */
1164
1165
1166
1167  // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
1168
1169  // values in feature detects to continue to work
1170
1171  var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
1172
1173
1174
1175  // expose these for the plugin API. Look in the source for how to join() them against your input
1176
1177  ModernizrProto._prefixes = prefixes;
1178
1179
1180
1181  
1182
1183
1184
1185  /**
1186
1187   * roundedEquals takes two integers and checks if the first is 
1187within 1 of the second
1188
1189   *
1190
1191   * @access private
1192
1193   * @function roundedEquals
1194
1195   * @param {number} a
1196
1197   * @param {number} b
1198
1199   * @returns {boolean}
1200
1201   */
1202
1203
1204
1205  function roundedEquals(a, b) {
1206
1207    return a - 1 === b || a === b || a + 1 === b;
1208
1209  }
1210
1211
1212
1213  ;
1214
1215
1216
1217  /**
1218
1219   * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
1220
1221   *
1222
1223   * @author kangax
1224
1225   * @access private
1226
1227   * @function hasOwnProp
1228
1229   * @param {object} object - The object to check for a property
1230
1231   * @param {string} property - The property to check for
1232
1233   * @returns {boolean}
1234
1235   */
1236
1237
1238
1239  // hasOwnProperty shim by kangax needed for Safari 2.0 support
1240
1241  var hasOwnProp;
1242
1243
1244
1245  (function() {
1246
1247    var _hasOwnProperty = ({}).hasOwnProperty;
1248
1249    /* istanbul ignore else */
1250
1251    /* we have no way of testing IE 5.5 or safari 2,
1252
1253     * so just assume the else gets hit */
1254
1255    if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
1256
1257      hasOwnProp = function(object, property) {
1258
1259        return _hasOwnProperty.call(object, property);
1260
1261      };
1262
1263    }
1264
1265    else {
1266
1267      hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
1268
1269        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
1270
1271      };
1272
1273    }
1274
1275  })();
1276
1277
1278
1279  
1280
1281
1282
1283
1284
1285   // _l tracks listeners for async tests, as well as tests that execute after the initial run
1286
1287  ModernizrProto._l = {};
1288
1289
1290
1291  /**
1292
1293   * Modernizr.on is a way to listen for the completion of async tests. Being
1294
1295   * asynchronous, they may not finish before your scripts run. As a result you
1296
1297   * will get a possibly false negative `undefined` value.
1298
1299   *
1300
1301   * @memberof Modernizr
1302
1303   * @name Modernizr.on
1304
1305   * @access public
1306
1307   * @function on
1308
1309   * @param {string} feature - String name of the feature detect
1310
1311   * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
1312
1313   * @example
1314
1315   *
1316
1317   * ```js
1318
1319   * Modernizr.on('flash', function( result ) {
1320
1321   *   if (result) {
1322
1323   *    // the browser has flash
1324
1325   *   } else {
1326
1327   *     // the browser does not have flash
1328
1329   *   }
1330
1331   * });
1332
1333   * ```
1334
1335   */
1336
1337
1338
1339  ModernizrProto.on = function(feature, cb) {
1340
1341    // Create the list of listeners if it doesn't exist
1342
1343    if (!this._l[feature]) {
1344
1345      this._l[feature] = [];
1346
1347    }
1348
1349
1350
1351    // Push this test on to the listener list
1352
1353    this._l[feature].push(cb);
1354
1355
1356
1357    // If it's already been resolved, trigger it on next tick
1358
1359    if (Modernizr.hasOwnProperty(feature)) {
1360
1361      // Next Tick
1362
1363      setTimeout(function() {
1364
1365        Modernizr._trigger(feature, Modernizr[feature]);
1366
1367      }, 0);
1368
1369    }
1370
1371  };
1372
1373
1374
1375  /**
1376
1377   * _trigger is the private function used to signal test completion and run any
1378
1379   * callbacks registered through [Modernizr.on](#modernizr-on)
1380
1381   *
1382
1383   * @memberof Modernizr
1384
1385   * @name Modernizr._trigger
1386
1387   * @access private
1388
1389   * @function _trigger
1390
1391   * @param {string} feature - string name of the feature detect
1392
1393   * @param {function|boolean} [res] - A feature detection function, or the boolean =
1394
1395   * result of a feature detection function
1396
1397   */
1398
1399
1400
1401  ModernizrProto._trigger = function(feature, res) {
1402
1403    if (!this._l[feature]) {
1404
1405      return;
1406
1407    }
1408
1409
1410
1411    var cbs = this._l[feature];
1412
1413
1414
1415    // Force async
1416
1417    setTimeout(function() {
1418
1419      var i, cb;
1420
1421      for (i = 0; i < cbs.length; i++) {
1422
1423        cb = cbs[i];
1424
1425        cb(res);
1426
1427      }
1428
1429    }, 0);
1430
1431
1432
1433    // Don't trigger these again
1434
1435    delete this._l[feature];
1436
1437  };
1438
1439
1440
1441  /**
1442
1443   * addTest allows you to define your own feature detects that are not currently
1444
1445   * included in Modernizr (under the covers it's the exact same code Modernizr
1446
1447   * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
1448
1449   * will be added onto the Modernizr object, as well as an appropriate className set on
1450
1451   * the html element when configured to do so
1452
1453   *
1454
1455   * @memberof Modernizr
1456
1457   * @name Modernizr.addTest
1458
1459   * @optionName Modernizr.addTest()
1460
1461   * @optionProp addTest
1462
1463   * @access public
1464
1465   * @function addTest
1466
1467   * @param {string|object} feature - The string name of the feature detect, or an
1468
1469   * object of feature detect names and test
1470
1471   * @param {function|boolean} test - Function returning true if feature is supported,
1472
1473   * false if not. Otherwise a boolean representing the results of a feature detection
1474
1475   * @example
1476
1477   *
1478
1479   * The most common way of creating your own feature detects is by calling
1480
1481   * `Modernizr.addTest` with a string (preferably just lowercase, without any
1482
1483   * punctuation), and a function you want executed that will return a boolean result
1484
1485   *
1486
1487   * ```js
1488
1489   * Modernizr.addTest('itsTuesday', function() {
1490
1491   *  var d = new Date();
1492
1493   *  return d.getDay() === 2;
1494
1495   * });
1496
1497   * ```
1498
1499   *
1500
1501   * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
1502
1503   * and to `false` every other day of the week. One thing to notice is that the names of
1504
1505   * feature detect functions are always lowercased when added to the Modernizr object. That
1506
1507   * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
1508
1509   *
1510
1511   *
1512
1513   *  Since we only look at the returned value from any feature detection function,
1514
1515   *  you do not need to actually use a function. For simple detections, just passing
1516
1517   *  in a statement that will return a boolean value works just fine.
1518
1519   *
1520
1521   * ```js
1522
1523   * Modernizr.addTest('hasJquery', 'jQuery' in window);
1524
1525   * ```
1526
1527   *
1528
1529   * Just like before, when the above runs `Modernizr.hasjquery` will be true if
1530
1531   * jQuery has been included on the page. Not using a function saves a small amount
1532
1533   * of overhead for the browser, as well as making your code much more readable.
1534
1535   *
1536
1537   * Finally, you also have the ability to pass in an object of feature names and
1538
1539   * their tests. This is handy if you want to add multiple detections in one go.
1540
1541   * The keys should always be a string, and the value can be either a boolean or
1542
1543   * function that returns a boolean.
1544
1545   *
1546
1547   * ```js
1548
1549   * var detects = {
1550
1551   *  'hasjquery': 'jQuery' in window,
1552
1553   *  'itstuesday': function() {
1554
1555   *    var d = new Date();
1556
1557   *    return d.getDay() === 2;
1558
1559   *  }
1560
1561   * }
1562
1563   *
1564
1565   * Modernizr.addTest(detects);
1566
1567   * ```
1568
1569   *
1570
1571   * There is really no difference between the first methods and this one, it is
1572
1573   * just a convenience to let you write more readable code.
1574
1575   */
1576
1577
1578
1579  function addTest(feature, test) {
1580
1581
1582
1583    if (typeof feature == 'object') {
1584
1585      for (var key in feature) {
1586
1587        if (hasOwnProp(feature, key)) {
1588
1589          addTest(key, feature[ key ]);
1590
1591        }
1592
1593      }
1594
1595    } else {
1596
1597
1598
1599      feature = feature.toLowerCase();
1600
1601      var featureNameSplit = feature.split('.');
1602
1603      var last = Modernizr[featureNameSplit[0]];
1604
1605
1606
1607      // Again, we don't check for parent test existence. Get that right, though.
1608
1609      if (featureNameSplit.length == 2) {
1610
1611        last = last[featureNameSplit[1]];
1612
1613      }
1614
1615
1616
1617      if (typeof last != 'undefined') {
1618
1619        // we're going to quit if you're trying to overwrite an existing test
1620
1621        // if we were to allow it, we'd do this:
1622
1623        //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
1624
1625        //   docElement.className = docElement.className.replace( re, '' );
1626
1627        // but, no rly, stuff 'em.
1628
1629        return Modernizr;
1630
1631      }
1632
1633
1634
1635      test = typeof test == 'function' ? test() : test;
1636
1637
1638
1639      // Set the value (this is the magic, right here).
1640
1641      if (featureNameSplit.length == 1) {
1642
1643        Modernizr[featureNameSplit[0]] = test;
1644
1645      } else {
1646
1647        // cast to a Boolean, if not one already
1648
1649        /* jshint -W053 */
1650
1651        if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
1652
1653          Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
1654
1655        }
1656
1657
1658
1659        Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
1660
1661      }
1662
1663
1664
1665      // Set a single class (either `feature` or `no-feature`)
1666
1667      /* jshint -W041 */
1668
1669      setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
1670
1671      /* jshint +W041 */
1672
1673
1674
1675      // Trigger the event
1676
1677      Modernizr._trigger(feature, test);
1678
1679    }
1680
1681
1682
1683    return Modernizr; // allow chaining.
1684
1685  }
1686
1687
1688
1689  // After all the tests are run, add self to the Modernizr prototype
1690
1691  Modernizr._q.push(function() {
1692
1693    ModernizrProto.addTest = addTest;
1694
1695  });
1696
1697
1698
1699  
1700
1701
1702
1703/*!
1704
1705{
1706
1707  "name": "Video Autoplay",
1708
1709  "property": "videoautoplay",
1710
1711  "tags": ["video"],
1712
1713  "async" : true,
1714
1715  "warnings": ["This test is very large ? only include it if you absolutely need it"],
1716
1717  "knownBugs": ["crashes with an alert on iOS7 when added to homescreen"]
1718
1719}
1720
1721!*/
1722
1723/* DOC
1724
1725Checks for support of the autoplay attribute of the video element.
1726
1727*/
1728
1729
1730
1731
1732
1733  Modernizr.addAsyncTest(function() {
1734
1735    var timeout;
1736
1737    var waitTime = 200;
1738
1739    var retries = 5;
1740
1741    var currentTry = 0;
1742
1743    var elem = createElement('video');
1744
1745    var elemStyle = elem.style;
1746
1747
1748
1749    function testAutoplay(arg) {
1750
1751      currentTry++;
1752
1753      clearTimeout(timeout);
1754
1755
1756
1757      var result = arg && arg.type === 'playing' || elem.currentTime !== 0;
1758
1759
1760
1761      if (!result && currentTry < retries) {
1762
1763        //Detection can be flaky if the browser is slow, so lets retry in a little bit
1764
1765        timeout = setTimeout(testAutoplay, waitTime);
1766
1767        return;
1768
1769      }
1770
1771
1772
1773      elem.removeEventListener('playing', testAutoplay, false);
1774
1775      addTest('videoautoplay', result);
1776
1777      elem.parentNode.removeChild(elem);
1778
1779    }
1780
1781
1782
1783    //skip the test if video itself, or the autoplay
1784
1785    //element on it isn't supported
1786
1787    if (!Modernizr.video || !('autoplay' in elem)) {
1788
1789      addTest('videoautoplay', false);
1790
1791      return;
1792
1793    }
1794
1795
1796
1797    elemStyle.position = 'absolute';
1798
1799    elemStyle.height = 0;
1800
1801    elemStyle.width = 0;
1802
1803
1804
1805    try {
1806
1807      if (Modernizr.video.ogg) {
1808
1809        elem.src = 'data:video/ogg;base64,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';
1810
1811      }
1812
1813      else if (Modernizr.video.h264) {
1814
1815        elem.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAs1tZGF0AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0OCByMjYwMSBhMGNkN2QzIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEwIHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAD2WIhAA3//728P4FNjuZQQAAAu5tb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAZAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACGHRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAgAAAAIAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAGQAAAAAAAEAAAAAAZBtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAACgAAAAEAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAE7bWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAA+3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAgACAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFkAAr/4QAYZ2QACqzZX4iIhAAAAwAEAAADAFA8SJZYAQAGaOvjyyLAAAAAGHN0dHMAAAAAAAAAAQAAAAEAAAQAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAABRzdHN6AAAAAAAAAsUAAAABAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU2LjQwLjEwMQ==';
1816
1817      }
1818
1819      else {
1820
1821        addTest('videoautoplay', false);
1822
1823        return;
1824
1825      }
1826
1827    }
1828
1829
1830
1831    catch (e) {
1832
1833      addTest('videoautoplay', false);
1834
1835      return;
1836
1837    }
1838
1839
1840
1841    elem.setAttribute('autoplay', '');
1842
1843    elem.style.cssText = 'display:none';
1844
1845    docElement.appendChild(elem);
1846
1847    // wait for the next tick to add the listener, otherwise the element may
1848
1849    // not have time to play in high load situations (e.g. the test suite)
1850
1851    setTimeout(function() {
1852
1853      elem.addEventListener('playing', testAutoplay, false);
1854
1855      timeout = setTimeout(testAutoplay, waitTime);
1856
1857    }, 0);
1858
1859  });
1860
1861
1862
1863
1864
1865  /**
1866
1867   * getBody returns the body of a document, or an element that can stand in for
1868
1869   * the body if a real body does not exist
1870
1871   *
1872
1873   * @access private
1874
1875   * @function getBody
1876
1877   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
1878
1879   * artificially created element that stands in for the body
1880
1881   */
1882
1883
1884
1885  function getBody() {
1886
1887    // After page load injecting a fake body doesn't work so check if body exists
1888
1889    var body = document.body;
1890
1891
1892
1893    if (!body) {
1894
1895      // Can't use the real body create a fake one.
1896
1897      body = createElement(isSVG ? 'svg' : 'body');
1898
1899      body.fake = true;
1900
1901    }
1902
1903
1904
1905    return body;
1906
1907  }
1908
1909
1910
1911  ;
1912
1913
1914
1915  /**
1916
1917   * injectElementWithStyles injects an element with style element and some CSS rules
1918
1919   *
1920
1921   * @access private
1922
1923   * @function injectElementWithStyles
1924
1925   * @param {string} rule - String representing a css rule
1926
1927   * @param {function} callback - A function that is used to test the injected element
1928
1929   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
1930
1931   * @param {string[]}
1931 [testnames] - An array of strings that are used as ids for the additional nodes
1932
1933   * @returns {boolean}
1934
1935   */
1936
1937
1938
1939  function injectElementWithStyles(rule, callback, nodes, testnames) {
1940
1941    var mod = 'modernizr';
1942
1943    var style;
1944
1945    var ret;
1946
1947    var node;
1948
1949    var docOverflow;
1950
1951    var div = createElement('div');
1952
1953    var body = getBody();
1954
1955
1956
1957    if (parseInt(nodes, 10)) {
1958
1959      // In order not to give false positives we create a node for each test
1960
1961      // This also allows the method to scale for unspecified uses
1962
1963      while (nodes--) {
1964
1965        node = createElement('div');
1966
1967        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
1968
1969        div.appendChild(node);
1970
1971      }
1972
1973    }
1974
1975
1976
1977    style = createElement('style');
1978
1979    style.type = 'text/css';
1980
1981    style.id = 's' + mod;
1982
1983
1984
1985    // 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.
1986
1987    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
1988
1989    (!body.fake ? div : body).appendChild(style);
1990
1991    body.appendChild(div);
1992
1993
1994
1995    if (style.styleSheet) {
1996
1997      style.styleSheet.cssText = rule;
1998
1999    } else {
2000
2001      style.appendChild(document.createTextNode(rule));
2002
2003    }
2004
2005    div.id = mod;
2006
2007
2008
2009    if (body.fake) {
2010
2011      //avoid crashing IE8, if background image is used
2012
2013      body.style.background = '';
2014
2015      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
2016
2017      body.style.overflow = 'hidden';
2018
2019      docOverflow = docElement.style.overflow;
2020
2021      docElement.style.overflow = 'hidden';
2022
2023      docElement.appendChild(body);
2024
2025    }
2026
2027
2028
2029    ret = callback(div, rule);
2030
2031    // If this is done after page load we don't want to remove the body so check if body exists
2032
2033    if (body.fake) {
2034
2035      body.parentNode.removeChild(body);
2036
2037      docElement.style.overflow = docOverflow;
2038
2039      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
2040
2041      docElement.offsetHeight;
2042
2043    } else {
2044
2045      div.parentNode.removeChild(div);
2046
2047    }
2048
2049
2050
2051    return !!ret;
2052
2053
2054
2055  }
2056
2057
2058
2059  ;
2060
2061
2062
2063  /**
2064
2065   * testStyles injects an element with style element and some CSS rules
2066
2067   *
2068
2069   * @memberof Modernizr
2070
2071   * @name Modernizr.testStyles
2072
2073   * @optionName Modernizr.testStyles()
2074
2075   * @optionProp testStyles
2076
2077   * @access public
2078
2079   * @function testStyles
2080
2081   * @param {string} rule - String representing a css rule
2082
2083   * @param {function} callback - A function that is used to test the injected element
2084
2085   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
2086
2087   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
2088
2089   * @returns {boolean}
2090
2091   * @example
2092
2093   *
2094
2095   * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
2096
2097   * along with (possibly multiple) DOM elements. This lets you check for features
2098
2099   * 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).
2100
2101   *
2102
2103   * ```js
2104
2105   * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
2106
2107   *   // elem is the first DOM node in the page (by default #modernizr)
2108
2109   *   // rule is the first argument you supplied - the CSS rule in string form
2110
2111   *
2112
2113   *   addTest('widthworks', elem.style.width === '9px')
2114
2115   * });
2116
2117   * ```
2118
2119   *
2120
2121   * If your test requires multiple nodes, you can include a third argument
2122
2123   * indicating how many additional div elements to include on the page. The
2124
2125   * additional nodes are injected as children of the `elem` that is returned as
2126
2127   * the first argument to the callback.
2128
2129   *
2130
2131   * ```js
2132
2133   * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
2134
2135   *   document.getElementById('modernizr').style.width === '1px'; // true
2136
2137   *   document.getElementById('modernizr2').style.width === '2px'; // true
2138
2139   *   elem.firstChild === document.getElementById('modernizr2'); // true
2140
2141   * }, 1);
2142
2143   * ```
2144
2145   *
2146
2147   * By default, all of the additional elements have an ID of `modernizr[n]`, where
2148
2149   * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
2150
2151   * the second additional is `#modernizr3`, etc.).
2152
2153   * If you want to have more meaningful IDs for your function, you can provide
2154
2155   * them as the fourth argument, as an array of strings
2156
2157   *
2158
2159   * ```js
2160
2161   * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
2162
2163   *   elem.firstChild === document.getElementById('foo'); // true
2164
2165   *   elem.lastChild === document.getElementById('bar'); // true
2166
2167   * }, 2, ['foo', 'bar']);
2168
2169   * ```
2170
2171   *
2172
2173   */
2174
2175
2176
2177  var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
2178
2179  
2180
2181/*!
2182
2183{
2184
2185  "name": "Touch Events",
2186
2187  "property": "touchevents",
2188
2189  "caniuse" : "touch",
2190
2191  "tags": ["media", "attribute"],
2192
2193  "notes": [{
2194
2195    "name": "Touch Events spec",
2196
2197    "href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/"
2198
2199  }],
2200
2201  "warnings": [
2202
2203    "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
2204
2205  ],
2206
2207  "knownBugs": [
2208
2209    "False-positive on some configurations of Nokia N900",
2210
2211    "False-positive on some BlackBerry 6.0 builds ? https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
2212
2213  ]
2214
2215}
2216
2217!*/
2218
2219/* DOC
2220
2221Indicates if the browser supports the W3C Touch Events API.
2222
2223
2224
2225This *does not* necessarily reflect a touchscreen device:
2226
2227
2228
2229* Older touchscreen devices only emulate mouse events
2230
2231* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
2232
2233* Some browsers & OS setups may enable touch APIs when no touchscreen is connected
2234
2235* Future browsers may implement other event models for touch interactions
2236
2237
2238
2239See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
2240
2241
2242
2243It's recommended to bind both mouse and touch/pointer events simultaneously ? see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/).
2244
2245
2246
2247This test will also return `true` for Firefox 4 Multitouch support.
2248
2249*/
2250
2251
2252
2253  // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
2254
2255  Modernizr.addTest('touchevents', function() {
2256
2257    var bool;
2258
2259    if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
2260
2261      bool = true;
2262
2263    } else {
2264
2265      // include the 'heartz' as a way to have a non matching MQ to help terminate the join
2266
2267      // https://git.io/vznFH
2268
2269      var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
2270
2271      testStyles(query, function(node) {
2272
2273        bool = node.offsetTop === 9;
2274
2275      });
2276
2277    }
2278
2279    return bool;
2280
2281  });
2282
2283
2284
2285/*! {
2286
2287  "name": "hairline",
2288
2289  "property": "csshairline",
2290
2291  "tags": ["css"],
2292
2293  "authors": ["strarsis"],
2294
2295  "notes": [{
2296
2297    "name": "Blog post about CSS retina hairlines",
2298
2299    "href": "http://dieulot.net/css-retina-hairline"
2300
2301  },{
2302
2303    "name": "Derived from",
2304
2305    "href": "https://gist.github.com/dieulot/520a49463f6058fbc8d1"
2306
2307  }]
2308
2309}
2310
2311!*/
2312
2313/* DOC
2314
2315Detects support for hidpi/retina hairlines, which are CSS borders with less than 1px in width, for being physically 1px on hidpi screens.
2316
2317*/
2318
2319
2320
2321
2322
2323  Modernizr.addTest('hairline', function() {
2324
2325    return testStyles('#modernizr {border:.5px solid transparent}', function(elem) {
2326
2327      return elem.offsetHeight === 1;
2328
2329    });
2330
2331  });
2332
2333
2334
2335/*!
2336
2337{
2338
2339  "name": "CSS vh unit",
2340
2341  "property": "cssvhunit",
2342
2343  "caniuse": "viewport-units",
2344
2345  "tags": ["css"],
2346
2347  "builderAliases": ["css_vhunit"],
2348
2349  "notes": [{
2350
2351    "name": "Related Modernizr Issue",
2352
2353    "href": "https://github.com/Modernizr/Modernizr/issues/572"
2354
2355  },{
2356
2357    "name": "Similar JSFiddle",
2358
2359    "href": "https://jsfiddle.net/FWeinb/etnYC/"
2360
2361  }]
2362
2363}
2364
2365!*/
2366
2367
2368
2369  testStyles('#modernizr { height: 50vh; }', function(elem) {
2370
2371    var height = parseInt(window.innerHeight / 2, 10);
2372
2373    var compStyle = parseInt((window.getComputedStyle ?
2374
2375                              getComputedStyle(elem, null) :
2376
2377                              elem.currentStyle).height, 10);
2378
2379    Modernizr.addTest('cssvhunit', compStyle == height);
2380
2381  });
2382
2383
2384
2385/*!
2386
2387{
2388
2389  "name": "CSS vmax unit",
2390
2391  "property": "cssvmaxunit",
2392
2393  "caniuse": "viewport-units",
2394
2395  "tags": ["css"],
2396
2397  "builderAliases": ["css_vmaxunit"],
2398
2399  "notes": [{
2400
2401    "name": "Related Modernizr Issue",
2402
2403    "href": "https://github.com/Modernizr/Modernizr/issues/572"
2404
2405  },{
2406
2407    "name": "JSFiddle Example",
2408
2409    "href": "https://jsfiddle.net/glsee/JDsWQ/4/"
2410
2411  }]
2412
2413}
2414
2415!*/
2416
2417
2418
2419  testStyles('#modernizr1{width: 50vmax}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
2420
2421    var elem = node.childNodes[2];
2422
2423    var scroller = node.childNodes[1];
2424
2425    var fullSizeElem = node.childNodes[0];
2426
2427    var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
2428
2429
2430
2431    var one_vw = fullSizeElem.clientWidth / 100;
2432
2433    var one_vh = fullSizeElem.clientHeight / 100;
2434
2435    var expectedWidth = parseInt(Math.max(one_vw, one_vh) * 50, 10);
2436
2437    var compWidth = parseInt((window.getComputedStyle ?
2438
2439                          getComputedStyle(elem, null) :
2440
2441                          elem.currentStyle).width, 10);
2442
2443
2444
2445    Modernizr.addTest('cssvmaxunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
2446
2447  }, 3);
2448
2449
2450
2451/*!
2452
2453{
2454
2455  "name": "CSS vmin unit",
2456
2457  "property": "cssvminunit",
2458
2459  "caniuse": "viewport-units",
2460
2461  "tags": ["css"],
2462
2463  "builderAliases": ["css_vminunit"],
2464
2465  "notes": [{
2466
2467    "name": "Related Modernizr Issue",
2468
2469    "href": "https://github.com/Modernizr/Modernizr/issues/572"
2470
2471  },{
2472
2473    "name": "JSFiddle Example",
2474
2475    "href": "https://jsfiddle.net/glsee/JRmdq/8/"
2476
2477  }]
2478
2479}
2480
2481!*/
2482
2483
2484
2485  testStyles('#modernizr1{width: 50vm;width:50vmin}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
2486
2487    var elem = node.childNodes[2];
2488
2489    var scroller = node.childNodes[1];
2490
2491    var fullSizeElem = node.childNodes[0];
2492
2493    var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
2494
2495
2496
2497    var one_vw = fullSizeElem.clientWidth / 100;
2498
2499    var one_vh = fullSizeElem.clientHeight / 100;
2500
2501    var expectedWidth = parseInt(Math.min(one_vw, one_vh) * 50, 10);
2502
2503    var compWidth = parseInt((window.getComputedStyle ?
2504
2505                          getComputedStyle(elem, null) :
2506
2507                          elem.currentStyle).width, 10);
2508
2509
2510
2511    Modernizr.addTest('cssvminunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
2512
2513  }, 3);
2514
2515
2516
2517/*!
2518
2519{
2520
2521  "name": "CSS vw unit",
2522
2523  "property": "cssvwunit",
2524
2525  "caniuse": "viewport-units",
2526
2527  "tags": ["css"],
2528
2529  "builderAliases": ["css_vwunit"],
2530
2531  "notes": [{
2532
2533    "name": "Related Modernizr Issue",
2534
2535    "href": "https://github.com/Modernizr/Modernizr/issues/572"
2536
2537  },{
2538
2539    "name": "JSFiddle Example",
2540
2541    "href": "https://jsfiddle.net/FWeinb/etnYC/"
2542
2543  }]
2544
2545}
2546
2547!*/
2548
2549
2550
2551  testStyles('#modernizr { width: 50vw; }', function(elem) {
2552
2553    var width = parseInt(window.innerWidth / 2, 10);
2554
2555    var compStyle = parseInt((window.getComputedStyle ?
2556
2557                              getComputedStyle(elem, null) :
2558
2559                              elem.currentStyle).width, 10);
2560
2561
2562
2563    Modernizr.addTest('cssvwunit', compStyle == width);
2564
2565  });
2566
2567
2568
2569
2570
2571  /**
2572
2573   * If the browsers follow the spec, then they would expose vendor-specific style as:
2574
2575   *   elem.style.WebkitBorderRadius
2576
2577   * instead of something like the following, which would be technically incorrect:
2578
2579   *   elem.style.webkitBorderRadius
2580
2581
2582
2583   * Webkit ghosts their properties in lowercase but Opera & Moz do not.
2584
2585   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
2586
2587   *   erik.eae.net/archives/2008/03/10/21.48.10/
2588
2589
2590
2591   * More here: github.com/Modernizr/Modernizr/issues/issue/21
2592
2593   *
2594
2595   * @access private
2596
2597   * @returns {string} The string representing the vendor-specific style properties
2598
2599   */
2600
2601
2602
2603  var omPrefixes = 'Moz O ms Webkit';
2604
2605  
2606
2607
2608
2609  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
2610
2611  ModernizrProto._cssomPrefixes = cssomPrefixes;
2612
2613  
2614
2615
2616
2617  /**
2618
2619   * List of JavaScript DOM values used for tests
2620
2621   *
2622
2623   * @memberof Modernizr
2624
2625   * @name Modernizr._domPrefixes
2626
2627   * @optionName Modernizr._domPrefixes
2628
2629   * @optionProp domPrefixes
2630
2631   * @access public
2632
2633   * @example
2634
2635   *
2636
2637   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
2638
2639   * than kebab-case properties, all properties are their Capitalized variant
2640
2641   *
2642
2643   * ```js
2644
2645   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
2646
2647   * ```
2648
2649   */
2650
2651
2652
2653  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
2654
2655  ModernizrProto._domPrefixes = domPrefixes;
2656
2657  
2658
2659
2660
2661
2662
2663  /**
2664
2665   * contains checks to see if a string contains another string
2666
2667   *
2668
2669   * @access private
2670
2671   * @function contains
2672
2673   * @param {string} str - The string we want to check for substrings
2674
2675   * @param {string} substr - The substring we want to search the first string for
2676
2677   * @returns {boolean}
2678
2679   */
2680
2681
2682
2683  function contains(str, substr) {
2684
2685    return !!~('' + str).indexOf(substr);
2686
2687  }
2688
2689
2690
2691  ;
2692
2693
2694
2695  /**
2696
2697   * cssToDOM takes a kebab-case string and converts it to camelCase
2698
2699   * e.g. box-sizing -> boxSizing
2700
2701   *
2702
2703   * @access private
2704
2705   * @function cssToDOM
2706
2707   * @param {string} name - String name of kebab-case prop we want to convert
2708
2709   * @returns {string} The camelCase version of the supplied name
2710
2711   */
2712
2713
2714
2715  function cssToDOM(name) {
2716
2717    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
2718
2719      return m1 + m2.toUpperCase();
2720
2721    }).replace(/^-/, '');
2722
2723  }
2724
2725  ;
2726
2727
2728
2729  /**
2730
2731   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
2732
2733   *
2734
2735   * @access private
2736
2737   * @function fnBind
2738
2739   * @param {function} fn - a function you want to change `this` reference to
2740
2741   * @param {object} that - the `this` you want to call the function with
2742
2743   * @returns {function} The wrapped version of the supplied function
2744
2745   */
2746
2747
2748
2749  function fnBind(fn, that) {
2750
2751    return function() {
2752
2753      return fn.apply(that, arguments);
2754
2755    };
2756
2757  }
2758
2759
2760
2761  ;
2762
2763
2764
2765  /**
2766
2767   * testDOMProps is a generic DOM property test; if a browser supports
2768
2769   *   a certain property, it won't return undefined for it.
2770
2771   *
2772
2773   * @access private
2774
2775   * @function testDOMProps
2776
2777   * @param {array.<string>} props - An array of properties to test for
2778
2779   * @param {object} obj - An object or Element you want to use to test the parameters again
2780
2781   * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
2782
2783   */
2784
2785  function testDOMProps(props, obj, elem) {
2786
2787    var item;
2788
2789
2790
2791    for (var i in props) {
2792
2793      if (props[i] in obj) {
2794
2795
2796
2797        // return the property name as a string
2798
2799        if (elem === false) {
2800
2801          return props[i];
2802
2803        }
2804
2805
2806
2807        item = obj[props[i]];
2808
2809
2810
2811        // let's bind a function
2812
2813        if (is(item, 'function')) {
2814
2815          // bind to obj unless overriden
2816
2817          return fnBind(item, elem || obj);
2818
2819        }
2820
2821
2822
2823        // return the unbound function or obj or value
2824
2825        return item;
2826
2827      }
2828
2829    }
2830
2831    return false;
2832
2833  }
2834
2835
2836
2837  ;
2838
2839
2840
2841  /**
2842
2843   * Create our "modernizr" element that we do most feature tests on.
2844
2845   *
2846
2847   * @access private
2848
2849   */
2850
2851
2852
2853  var modElem = {
2854
2855    elem: createElement('modernizr')
2856
2857  };
2858
2859
2860
2861  // Clean up this element
2862
2863  Modernizr._q.push(function() {
2864
2865    delete modElem.elem;
2866
2867  });
2868
2869
2870
2871  
2872
2873
2874
2875  var mStyle = {
2876
2877    style: modElem.elem.style
2878
2879  };
2880
2881
2882
2883  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
2884
2885  // the front of the queue.
2886
2887  Modernizr._q.unshift(function() {
2888
2889    delete mStyle.style;
2890
2891  });
2892
2893
2894
2895  
2896
2897
2898
2899  /**
2900
2901   * domToCSS takes a camelCase string and converts it to kebab-case
2902
2903   * e.g. boxSizing -> box-sizing
2904
2905   *
2906
2907   * @access private
2908
2909   * @function domToCSS
2910
2911   * @param {string} name - String name of camelCase prop we want to convert
2912
2913   * @returns {string} The kebab-case version of the supplied name
2914
2915   */
2916
2917
2918
2919  function domToCSS(name) {
2920
2921    return name.replace(/([A-Z])/g, function(str, m1) {
2922
2923      return '-' + m1.toLowerCase();
2924
2925    }).replace(/^ms-/, '-ms-');
2926
2927  }
2928
2929  ;
2930
2931
2932
2933  /**
2934
2935   * nativeTestProps allows for us to use native feature detection functionality if available.
2936
2937   * some prefixed form, or false, in the case of an unsupported rule
2938
2939   *
2940
2941   * @access private
2942
2943   * @function nativeTestProps
2944
2945   * @param {array} props - An array of property names
2946
2947   * @param {string} value - A string representing the value we want to check via @supports
2948
2949   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
2950
2951   */
2952
2953
2954
2955  // Accepts a list of property names and a single value
2956
2957  // Returns `undefined` if native detection not available
2958
2959  function nativeTestProps(props, value) {
2960
2961    var i = props.length;
2962
2963    // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
2964
2965    if ('CSS' in window && 'supports' in window.CSS) {
2966
2967      // Try every prefixed variant of the property
2968
2969      while (i--) {
2970
2971        if (window.CSS.supports(domToCSS(props[i]), value)) {
2972
2973          return true;
2974
2975        }
2976
2977      }
2978
2979      return false;
2980
2981    }
2982
2983    // Otherwise fall back to at-rule (for Opera 12.x)
2984
2985    else if ('CSSSupportsRule' in window) {
2986
2987      // Build a condition string for every prefixed variant
2988
2989      var conditionText = [];
2990
2991      while (i--) {
2992
2993        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
2994
2995      }
2996
2997      conditionText = conditionText.join(' or ');
2998
2999      return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
3000
3001        return getComputedStyle(node, null).position == 'absolute';
3002
3003      });
3004
3005    }
3006
3007    return undefined;
3008
3009  }
3010
3011  ;
3012
3013
3014
3015  // testProps is a generic CSS / DOM property test.
3016
3017
3018
3019  // In testing support for a given CSS property, it's legit to test:
3020
3021  //    `elem.style[styleName] !== undefined`
3022
3023  // If the property is supported it will return an empty string,
3024
3025  // if unsupported it will return undefined.
3026
3027
3028
3029  // We'll take advantage of this quick test and skip setting a style
3030
3031  // on our modernizr element, but instead just testing undefined vs
3032
3033  // empty string.
3034
3035
3036
3037  // Property names can be provided in either camelCase or kebab-case.
3038
3039
3040
3041  function testProps(props, prefixed, value, skipValueTest) {
3042
3043    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
3044
3045
3046
3047    // Try native detect first
3048
3049    if (!is(value, 'undefined')) {
3050
3051      var result = nativeTestProps(props, value);
3052
3053      if (!is(result, 'undefined')) {
3054
3055        return result;
3056
3057      }
3058
3059    }
3060
3061
3062
3063    // Otherwise do it properly
3064
3065    var afterInit, i, propsLength, prop, before;
3066
3067
3068
3069    // If we don't have a style element, that means we're running async or after
3070
3071    // the core tests, so we'll need to create our own elements to use
3072
3073
3074
3075    // inside of an SVG element, in certain browsers, the `style` element is only
3076
3077    // defined for valid tags. Therefore, if `modernizr` does not have one, we
3078
3079    // fall back to a less used element and hope for the best.
3080
3081    // for strict XHTML browsers the hardly used samp element is used
3082
3083    var elems = ['modernizr', 'tspan', 'samp'];
3084
3085    while (!mStyle.style && elems.length) {
3086
3087      afterInit = true;
3088
3089      mStyle.modElem = createElement(elems.shift());
3090
3091      mStyle.style = mStyle.modElem.style;
3092
3093    }
3094
3095
3096
3097    // Delete the objects if we created them.
3098
3099    function cleanElems() {
3100
3101      if (afterInit) {
3102
3103        delete mStyle.style;
3104
3105        delete mStyle.modElem;
3106
3107      }
3108
3109    }
3110
3111
3112
3113    propsLength = props.length;
3114
3115    for (i = 0; i < propsLength; i++) {
3116
3117      prop = props[i];
3118
3119      before = mStyle.style[prop];
3120
3121
3122
3123      if (contains(prop, '-')) {
3124
3125        prop = cssToDOM(prop);
3126
3127      }
3128
3129
3130
3131      if (mStyle.style[prop] !== undefined) {
3132
3133
3134
3135        // If value to test has been passed in, do a set-and-check test.
3136
3137        // 0 (integer) is a valid property value, so check that `value` isn't
3138
3139        // undefined, rather than just checking it's truthy.
3140
3141        if (!skipValueTest && !is(value, 'undefined')) {
3142
3143
3144
3145          // Needs a try catch block because of old IE. This is slow, but will
3146
3147          // be avoided in most cases because `skipValueTest` will be used.
3148
3149          try {
3150
3151            mStyle.style[prop] = value;
3152
3153          } catch (e) {}
3154
3155
3156
3157          // If the property value has changed, we assume the value used is
3158
3159          // supported. If `value` is empty string, it'll fail here (because
3160
3161          // it hasn't changed), which matches how browsers have implemented
3162
3163          // CSS.supports()
3164
3165          if (mStyle.style[prop] != before) {
3166
3167            cleanElems();
3168
3169            return prefixed == 'pfx' ? prop : true;
3170
3171          }
3172
3173        }
3174
3175        // Otherwise just return true, or the property name if this is a
3176
3177        // `prefixed()` call
3178
3179        else {
3180
3181          cleanElems();
3182
3183          return prefixed == 'pfx' ? prop : true;
3184
3185        }
3186
3187      }
3188
3189    }
3190
3191    cleanElems();
3192
3193    return false;
3194
3195  }
3196
3197
3198
3199  ;
3200
3201
3202
3203  /**
3204
3205   * testPropsAll tests a list of DOM properties we want to check against.
3206
3207   * We specify literally ALL possible (known and/or likely) properties on
3208
3209   * the element including the non-vendor prefixed one, for forward-
3210
3211   * compatibility.
3212
3213   *
3214
3215   * @access private
3216
3217   * @function testPropsAll
3218
3219   * @param {string} prop - A string of the property to test for
3220
3221   * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
3222
3223   * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
3224
3225   * @param {string} [value] - A string of a css value
3226
3227   * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
3228
3229   */
3230
3231  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
3232
3233
3234
3235    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
3236
3237    props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
3238
3239
3240
3241    // did they call .prefixed('boxSizing') or are we just testing a prop?
3242
3243    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
3244
3245      return testProps(props, prefixed, value, skipValueTest);
3246
3247
3248
3249      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
3250
3251    } else {
3252
3253      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
3254
3255      return testDOMProps(props, prefixed, elem);
3256
3257    }
3258
3259  }
3260
3261
3262
3263  // Modernizr.testAllProps() investigates whether a given style property,
3264
3265  // or any of its vendor-prefixed variants, is recognized
3266
3267  //
3268
3269  // Note that the property names must be provided in the camelCase variant.
3270
3271  // Modernizr.testAllProps('boxSizing')
3272
3273  ModernizrProto.testAllProps = testPropsAll;
3274
3275
3276
3277  
3278
3279
3280
3281  /**
3282
3283   * testAllProps determines whether a given CSS property is supported in the browser
3284
3285   *
3286
3287   * @memberof Modernizr
3288
3289   * @name Modernizr.testAllProps
3290
3291   * @optionName Modernizr.testAllProps()
3292
3293   * @optionProp testAllProps
3294
3295   * @access public
3296
3297   * @function testAllProps
3298
3299   * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
3300
3301   * @param {string} [value] - String of the value to test
3302
3303   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
3304
3305   * @example
3306
3307   *
3308
3309   * testAllProps determines whether a given CSS property, in some prefixed form,
3310
3311   * is supported by the browser.
3312
3313   *
3314
3315   * ```js
3316
3317   * testAllProps('boxSizing')  // true
3318
3319   * ```
3320
3321   *
3322
3323   * It can optionally be given a CSS value in string form to test if a property
3324
3325   * value is valid
3326
3327   *
3328
3329   * ```js
3330
3331   * testAllProps('display', 'block') // true
3332
3333   * testAllProps('display', 'penguin') // false
3334
3335   * ```
3336
3337   *
3338
3339   * A boolean can be passed as a third parameter to skip the value check when
3340
3341   * native detection (@supports) isn't available.
3342
3343   *
3344
3345   * ```js
3346
3347   * testAllProps('shapeOutside', 'content-box', true);
3348
3349   * ```
3350
3351   */
3352
3353
3354
3355  function testAllProps(prop, value, skipValueTest) {
3356
3357    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
3358
3359  }
3360
3361  ModernizrProto.testAllProps = testAllProps;
3362
3363  
3364
3365/*!
3366
3367{
3368
3369  "name": "Flexbox",
3370
3371  "property": "flexbox",
3372
3373  "caniuse": "flexbox",
3374
3375  "tags": ["css"],
3376
3377  "notes": [{
3378
3379    "name": "The _new_ flexbox",
3380
3381    "href": "http://dev.w3.org/csswg/css3-flexbox"
3382
3383  }],
3384
3385  "warnings": [
3386
3387    "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
3388
3389  ]
3390
3391}
3392
3393!*/
3394
3395/* DOC
3396
3397Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
3398
3399*/
3400
3401
3402
3403  Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
3404
3405
3406
3407/*!
3408
3409{
3410
3411  "name": "Flexbox (legacy)",
3412
3413  "property": "flexboxlegacy",
3414
3415  "tags": ["css"],
3416
3417  "polyfills": ["flexie"],
3418
3419  "notes": [{
3420
3421    "name": "The _old_ flexbox",
3422
3423    "href": "https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/"
3424
3425  }]
3426
3427}
3428
3429!*/
3430
3431
3432
3433  Modernizr.addTest('flexboxlegacy', testAllProps('boxDirection', 'reverse', true));
3434
3435
3436
3437/*!
3438
3439{
3440
3441  "name": "Flexbox (tweener)",
3442
3443  "property": "flexboxtweener",
3444
3445  "tags": ["css"],
3446
3447  "polyfills": ["flexie"],
3448
3449  "notes": [{
3450
3451    "name": "The _inbetween_ flexbox",
3452
3453    "href": "https://www.w3.org/TR/2011/WD-css3-flexbox-20111129/"
3454
3455  }],
3456
3457  "warnings": ["This represents an old syntax, not the latest standard syntax."]
3458
3459}
3460
3461!*/
3462
3463
3464
3465  Modernizr.addTest('flexboxtweener', testAllProps('flexAlign', 'end', true));
3466
3467
3468
3469/*!
3470
3471{
3472
3473  "name": "Flex Line Wrapping",
3474
3475  "property": "flexwrap",
3476
3477  "tags": ["css", "flexbox"],
3478
3479  "notes": [{
3480
3481    "name": "W3C Flexible Box Layout spec",
3482
3483    "href": "http://dev.w3.org/csswg/css3-flexbox"
3484
3485  }],
3486
3487  "warnings": [
3488
3489    "Does not imply a modern implementation ? see documentation."
3490
3491  ]
3492
3493}
3494
3495!*/
3496
3497/* DOC
3498
3499Detects support for the `flex-wrap` CSS property, part of Flexbox, which isnft present in all Flexbox implementations (notably Firefox).
3500
3501
3502
3503This featured in both the 'tweener' syntax (implemented by IE10) and the 'modern' syntax (implemented by others). This detect will return `true` for either of these implementations, as long as the `flex-wrap` property is supported. So to ensure the modern syntax is supported, use together with `Modernizr.flexbox`:
3504
3505
3506
3507```javascript
3508
3509if (Modernizr.flexbox && Modernizr.flexwrap) {
3510
3511  // Modern Flexbox with `flex-wrap` supported
3512
3513}
3514
3515else {
3516
3517  // Either old Flexbox syntax, or `flex-wrap` not supported
3518
3519}
3520
3521```
3522
3523*/
3524
3525
3526
3527  Modernizr.addTest('flexwrap', testAllProps('flexWrap', 'wrap', true));
3528
3529
3530
3531/*!
3532
3533{
3534
3535  "name": "CSS position: sticky",
3536
3537  "property": "csspositionsticky",
3538
3539  "tags": ["css"],
3540
3541  "builderAliases": ["css_positionsticky"],
3542
3543  "notes": [{
3544
3545    "name": "Chrome bug report",
3546
3547    "href":"https://code.google.com/p/chromium/issues/detail?id=322972"
3548
3549  }],
3550
3551  "warnings": [ "using position:sticky on anything but top aligned elements is buggy in Chrome < 37 and iOS <=7+" ]
3552
3553}
3554
3555!*/
3556
3557
3558
3559  // Sticky positioning - constrains an element to be positioned inside the
3560
3561  // intersection of its container box, and the viewport.
3562
3563  Modernizr.addTest('csspositionsticky', function() {
3564
3565    var prop = 'position:';
3566
3567    var value = 'sticky';
3568
3569    var el = createElement('a');
3570
3571    var mStyle = el.style;
3572
3573
3574
3575    mStyle.cssText = prop + prefixes.join(value + ';' + prop).slice(0, -prop.length);
3576
3577
3578
3579    return mStyle.position.indexOf(value) !== -1;
3580
3581  });
3582
3583
3584
3585
3586
3587  // Run each test
3588
3589  testRunner();
3590
3591
3592
3593  // Remove the "no-js" class if it exists
3594
3595  setClasses(classes);
3596
3597
3598
3599  delete ModernizrProto.addTest;
3600
3601  delete ModernizrProto.addAsyncTest;
3602
3603
3604
3605  // Run the things that are supposed to run after the tests
3606
3607  for (var i = 0; i < Modernizr._q.length; i++) {
3608
3609    Modernizr._q[i]();
3610
3611  }
3612
3613
3614
3615  // Leak Modernizr namespace
3616
3617  window.Modernizr = Modernizr;
3618
3619
3620
3621
3622
3623;
3624
3625
3626
3627})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.