modernizr-select.js 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850
  1. /*!
  2. * modernizr v3.7.0
  3. * Build https://modernizr.com/download?-siblinggeneral-svg-webintents-addtest-printshiv-setclasses-testprop-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. * MIT License
  14. */
  15. /*
  16. * Modernizr tests which native CSS3 and HTML5 features are available in the
  17. * current UA and makes the results available to you in two ways: as properties on
  18. * a global `Modernizr` object, and as classes on the `<html>` element. This
  19. * information allows you to progressively enhance your pages with a granular level
  20. * of control over the experience.
  21. */
  22. ;(function(window, document, undefined){
  23. var tests = [];
  24. /**
  25. * ModernizrProto is the constructor for Modernizr
  26. *
  27. * @class
  28. * @access public
  29. */
  30. var ModernizrProto = {
  31. // The current version, dummy
  32. _version: '3.7.0',
  33. // Any settings that don't work as separate modules
  34. // can go in here as configuration.
  35. _config: {
  36. 'classPrefix': '',
  37. 'enableClasses': true,
  38. 'enableJSClass': true,
  39. 'usePrefixes': true
  40. },
  41. // Queue of tests
  42. _q: [],
  43. // Stub these for people who are listening
  44. on: function(test, cb) {
  45. // I don't really think people should do this, but we can
  46. // safe guard it a bit.
  47. // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
  48. // This is in case people listen to synchronous tests. I would leave it out,
  49. // but the code to *disallow* sync tests in the real version of this
  50. // function is actually larger than this.
  51. var self = this;
  52. setTimeout(function() {
  53. cb(self[test]);
  54. }, 0);
  55. },
  56. addTest: function(name, fn, options) {
  57. tests.push({name: name, fn: fn, options: options});
  58. },
  59. addAsyncTest: function(fn) {
  60. tests.push({name: null, fn: fn});
  61. }
  62. };
  63. // Fake some of Object.create so we can force non test results to be non "own" properties.
  64. var Modernizr = function() {};
  65. Modernizr.prototype = ModernizrProto;
  66. // Leak modernizr globally when you `require` it rather than force it here.
  67. // Overwrite name so constructor name is nicer :D
  68. Modernizr = new Modernizr();
  69. var classes = [];
  70. /**
  71. * is returns a boolean if the typeof an obj is exactly type.
  72. *
  73. * @access private
  74. * @function is
  75. * @param {*} obj - A thing we want to check the type of
  76. * @param {string} type - A string to compare the typeof against
  77. * @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise
  78. */
  79. function is(obj, type) {
  80. return typeof obj === type;
  81. }
  82. ;
  83. /**
  84. * Run through all tests and detect their support in the current UA.
  85. *
  86. * @access private
  87. * @returns {void}
  88. */
  89. function testRunner() {
  90. var featureNames;
  91. var feature;
  92. var aliasIdx;
  93. var result;
  94. var nameIdx;
  95. var featureName;
  96. var featureNameSplit;
  97. for (var featureIdx in tests) {
  98. if (tests.hasOwnProperty(featureIdx)) {
  99. featureNames = [];
  100. feature = tests[featureIdx];
  101. // run the test, throw the return value into the Modernizr,
  102. // then based on that boolean, define an appropriate className
  103. // and push it into an array of classes we'll join later.
  104. //
  105. // If there is no name, it's an 'async' test that is run,
  106. // but not directly added to the object. That should
  107. // be done with a post-run addTest call.
  108. if (feature.name) {
  109. featureNames.push(feature.name.toLowerCase());
  110. if (feature.options && feature.options.aliases && feature.options.aliases.length) {
  111. // Add all the aliases into the names list
  112. for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
  113. featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
  114. }
  115. }
  116. }
  117. // Run the test, or use the raw value if it's not a function
  118. result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
  119. // Set each of the names on the Modernizr object
  120. for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
  121. featureName = featureNames[nameIdx];
  122. // Support dot properties as sub tests. We don't do checking to make sure
  123. // that the implied parent tests have been added. You must call them in
  124. // order (either in the test, or make the parent test a dependency).
  125. //
  126. // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
  127. // hashtag famous last words
  128. featureNameSplit = featureName.split('.');
  129. if (featureNameSplit.length === 1) {
  130. Modernizr[featureNameSplit[0]] = result;
  131. } else {
  132. // cast to a Boolean, if not one already
  133. if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
  134. Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
  135. }
  136. Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
  137. }
  138. classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
  139. }
  140. }
  141. }
  142. }
  143. ;
  144. /**
  145. * docElement is a convenience wrapper to grab the root element of the document
  146. *
  147. * @access private
  148. * @returns {HTMLElement|SVGElement} The root element of the document
  149. */
  150. var docElement = document.documentElement;
  151. /**
  152. * A convenience helper to check if the document we are running in is an SVG document
  153. *
  154. * @access private
  155. * @returns {boolean}
  156. */
  157. var isSVG = docElement.nodeName.toLowerCase() === 'svg';
  158. /**
  159. * setClasses takes an array of class names and adds them to the root element
  160. *
  161. * @access private
  162. * @function setClasses
  163. * @param {string[]} classes - Array of class names
  164. */
  165. // Pass in an and array of class names, e.g.:
  166. // ['no-webp', 'borderradius', ...]
  167. function setClasses(classes) {
  168. var className = docElement.className;
  169. var classPrefix = Modernizr._config.classPrefix || '';
  170. if (isSVG) {
  171. className = className.baseVal;
  172. }
  173. // Change `no-js` to `js` (independently of the `enableClasses` option)
  174. // Handle classPrefix on this too
  175. if (Modernizr._config.enableJSClass) {
  176. var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
  177. className = className.replace(reJS, '$1' + classPrefix + 'js$2');
  178. }
  179. if (Modernizr._config.enableClasses) {
  180. // Add the new classes
  181. if (classes.length > 0) {
  182. className += ' ' + classPrefix + classes.join(' ' + classPrefix);
  183. }
  184. if (isSVG) {
  185. docElement.className.baseVal = className;
  186. } else {
  187. docElement.className = className;
  188. }
  189. }
  190. }
  191. ;
  192. /**
  193. * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
  194. *
  195. * @author kangax
  196. * @access private
  197. * @function hasOwnProp
  198. * @param {object} object - The object to check for a property
  199. * @param {string} property - The property to check for
  200. * @returns {boolean}
  201. */
  202. // hasOwnProperty shim by kangax needed for Safari 2.0 support
  203. var hasOwnProp;
  204. (function() {
  205. var _hasOwnProperty = ({}).hasOwnProperty;
  206. /* istanbul ignore else */
  207. /* we have no way of testing IE 5.5 or safari 2,
  208. * so just assume the else gets hit */
  209. if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
  210. hasOwnProp = function(object, property) {
  211. return _hasOwnProperty.call(object, property);
  212. };
  213. }
  214. else {
  215. hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
  216. return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
  217. };
  218. }
  219. })();
  220. // _l tracks listeners for async tests, as well as tests that execute after the initial run
  221. ModernizrProto._l = {};
  222. /**
  223. * Modernizr.on is a way to listen for the completion of async tests. Being
  224. * asynchronous, they may not finish before your scripts run. As a result you
  225. * will get a possibly false negative `undefined` value.
  226. *
  227. * @memberOf Modernizr
  228. * @name Modernizr.on
  229. * @access public
  230. * @function on
  231. * @param {string} feature - String name of the feature detect
  232. * @param {Function} cb - Callback function returning a Boolean - true if feature is supported, false if not
  233. * @returns {void}
  234. * @example
  235. *
  236. * ```js
  237. * Modernizr.on('flash', function( result ) {
  238. * if (result) {
  239. * // the browser has flash
  240. * } else {
  241. * // the browser does not have flash
  242. * }
  243. * });
  244. * ```
  245. */
  246. ModernizrProto.on = function(feature, cb) {
  247. // Create the list of listeners if it doesn't exist
  248. if (!this._l[feature]) {
  249. this._l[feature] = [];
  250. }
  251. // Push this test on to the listener list
  252. this._l[feature].push(cb);
  253. // If it's already been resolved, trigger it on next tick
  254. if (Modernizr.hasOwnProperty(feature)) {
  255. // Next Tick
  256. setTimeout(function() {
  257. Modernizr._trigger(feature, Modernizr[feature]);
  258. }, 0);
  259. }
  260. };
  261. /**
  262. * _trigger is the private function used to signal test completion and run any
  263. * callbacks registered through [Modernizr.on](#modernizr-on)
  264. *
  265. * @memberOf Modernizr
  266. * @name Modernizr._trigger
  267. * @access private
  268. * @function _trigger
  269. * @param {string} feature - string name of the feature detect
  270. * @param {Function|boolean} [res] - A feature detection function, or the boolean =
  271. * result of a feature detection function
  272. * @returns {void}
  273. */
  274. ModernizrProto._trigger = function(feature, res) {
  275. if (!this._l[feature]) {
  276. return;
  277. }
  278. var cbs = this._l[feature];
  279. // Force async
  280. setTimeout(function() {
  281. var i, cb;
  282. for (i = 0; i < cbs.length; i++) {
  283. cb = cbs[i];
  284. cb(res);
  285. }
  286. }, 0);
  287. // Don't trigger these again
  288. delete this._l[feature];
  289. };
  290. /**
  291. * addTest allows you to define your own feature detects that are not currently
  292. * included in Modernizr (under the covers it's the exact same code Modernizr
  293. * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)).
  294. * Just like the official detects, the result
  295. * will be added onto the Modernizr object, as well as an appropriate className set on
  296. * the html element when configured to do so
  297. *
  298. * @memberOf Modernizr
  299. * @name Modernizr.addTest
  300. * @optionName Modernizr.addTest()
  301. * @optionProp addTest
  302. * @access public
  303. * @function addTest
  304. * @param {string|Object} feature - The string name of the feature detect, or an
  305. * object of feature detect names and test
  306. * @param {Function|boolean} test - Function returning true if feature is supported,
  307. * false if not. Otherwise a boolean representing the results of a feature detection
  308. * @returns {Object} the Modernizr object to allow chaining
  309. * @example
  310. *
  311. * The most common way of creating your own feature detects is by calling
  312. * `Modernizr.addTest` with a string (preferably just lowercase, without any
  313. * punctuation), and a function you want executed that will return a boolean result
  314. *
  315. * ```js
  316. * Modernizr.addTest('itsTuesday', function() {
  317. * var d = new Date();
  318. * return d.getDay() === 2;
  319. * });
  320. * ```
  321. *
  322. * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
  323. * and to `false` every other day of the week. One thing to notice is that the names of
  324. * feature detect functions are always lowercased when added to the Modernizr object. That
  325. * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
  326. *
  327. *
  328. * Since we only look at the returned value from any feature detection function,
  329. * you do not need to actually use a function. For simple detections, just passing
  330. * in a statement that will return a boolean value works just fine.
  331. *
  332. * ```js
  333. * Modernizr.addTest('hasjquery', 'jQuery' in window);
  334. * ```
  335. *
  336. * Just like before, when the above runs `Modernizr.hasjquery` will be true if
  337. * jQuery has been included on the page. Not using a function saves a small amount
  338. * of overhead for the browser, as well as making your code much more readable.
  339. *
  340. * Finally, you also have the ability to pass in an object of feature names and
  341. * their tests. This is handy if you want to add multiple detections in one go.
  342. * The keys should always be a string, and the value can be either a boolean or
  343. * function that returns a boolean.
  344. *
  345. * ```js
  346. * var detects = {
  347. * 'hasjquery': 'jQuery' in window,
  348. * 'itstuesday': function() {
  349. * var d = new Date();
  350. * return d.getDay() === 2;
  351. * }
  352. * }
  353. *
  354. * Modernizr.addTest(detects);
  355. * ```
  356. *
  357. * There is really no difference between the first methods and this one, it is
  358. * just a convenience to let you write more readable code.
  359. */
  360. function addTest(feature, test) {
  361. if (typeof feature === 'object') {
  362. for (var key in feature) {
  363. if (hasOwnProp(feature, key)) {
  364. addTest(key, feature[ key ]);
  365. }
  366. }
  367. } else {
  368. feature = feature.toLowerCase();
  369. var featureNameSplit = feature.split('.');
  370. var last = Modernizr[featureNameSplit[0]];
  371. // Again, we don't check for parent test existence. Get that right, though.
  372. if (featureNameSplit.length === 2) {
  373. last = last[featureNameSplit[1]];
  374. }
  375. if (typeof last !== 'undefined') {
  376. // we're going to quit if you're trying to overwrite an existing test
  377. // if we were to allow it, we'd do this:
  378. // var re = new RegExp("\\b(no-)?" + feature + "\\b");
  379. // docElement.className = docElement.className.replace( re, '' );
  380. // but, no rly, stuff 'em.
  381. return Modernizr;
  382. }
  383. test = typeof test === 'function' ? test() : test;
  384. // Set the value (this is the magic, right here).
  385. if (featureNameSplit.length === 1) {
  386. Modernizr[featureNameSplit[0]] = test;
  387. } else {
  388. // cast to a Boolean, if not one already
  389. if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
  390. Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
  391. }
  392. Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
  393. }
  394. // Set a single class (either `feature` or `no-feature`)
  395. setClasses([(!!test && test !== false ? '' : 'no-') + featureNameSplit.join('-')]);
  396. // Trigger the event
  397. Modernizr._trigger(feature, test);
  398. }
  399. return Modernizr; // allow chaining.
  400. }
  401. // After all the tests are run, add self to the Modernizr prototype
  402. Modernizr._q.push(function() {
  403. ModernizrProto.addTest = addTest;
  404. });
  405. /**
  406. * @optionName html5printshiv
  407. * @optionProp html5printshiv
  408. */
  409. // Take the html5 variable out of the html5shiv scope so we can return it.
  410. var html5;
  411. if (!isSVG) {
  412. /**
  413. * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
  414. */
  415. ;(function(window, document) {
  416. /*jshint evil:true */
  417. /** version */
  418. var version = '3.7.3';
  419. /** Preset options */
  420. var options = window.html5 || {};
  421. /** Used to skip problem elements */
  422. var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
  423. /** Not all elements can be cloned in IE **/
  424. var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
  425. /** Detect whether the browser supports default html5 styles */
  426. var supportsHtml5Styles;
  427. /** Name of the expando, to work with multiple documents or to re-shiv one document */
  428. var expando = '_html5shiv';
  429. /** The id for the the documents expando */
  430. var expanID = 0;
  431. /** Cached data for each document */
  432. var expandoData = {};
  433. /** Detect whether the browser supports unknown elements */
  434. var supportsUnknownElements;
  435. (function() {
  436. try {
  437. var a = document.createElement('a');
  438. a.innerHTML = '<xyz></xyz>';
  439. //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
  440. supportsHtml5Styles = ('hidden' in a);
  441. supportsUnknownElements = a.childNodes.length == 1 || (function() {
  442. // assign a false positive if unable to shiv
  443. (document.createElement)('a');
  444. var frag = document.createDocumentFragment();
  445. return (
  446. typeof frag.cloneNode == 'undefined' ||
  447. typeof frag.createDocumentFragment == 'undefined' ||
  448. typeof frag.createElement == 'undefined'
  449. );
  450. }());
  451. } catch(e) {
  452. // assign a false positive if detection fails => unable to shiv
  453. supportsHtml5Styles = true;
  454. supportsUnknownElements = true;
  455. }
  456. }());
  457. /*--------------------------------------------------------------------------*/
  458. /**
  459. * Creates a style sheet with the given CSS text and adds it to the document.
  460. * @private
  461. * @param {Document} ownerDocument The document.
  462. * @param {String} cssText The CSS text.
  463. * @returns {StyleSheet} The style element.
  464. */
  465. function addStyleSheet(ownerDocument, cssText) {
  466. var p = ownerDocument.createElement('p'),
  467. parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
  468. p.innerHTML = 'x<style>' + cssText + '</style>';
  469. return parent.insertBefore(p.lastChild, parent.firstChild);
  470. }
  471. /**
  472. * Returns the value of `html5.elements` as an array.
  473. * @private
  474. * @returns {Array} An array of shived element node names.
  475. */
  476. function getElements() {
  477. var elements = html5.elements;
  478. return typeof elements == 'string' ? elements.split(' ') : elements;
  479. }
  480. /**
  481. * Extends the built-in list of html5 elements
  482. * @memberOf html5
  483. * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
  484. * @param {Document} ownerDocument The context document.
  485. */
  486. function addElements(newElements, ownerDocument) {
  487. var elements = html5.elements;
  488. if(typeof elements != 'string'){
  489. elements = elements.join(' ');
  490. }
  491. if(typeof newElements != 'string'){
  492. newElements = newElements.join(' ');
  493. }
  494. html5.elements = elements +' '+ newElements;
  495. shivDocument(ownerDocument);
  496. }
  497. /**
  498. * Returns the data associated to the given document
  499. * @private
  500. * @param {Document} ownerDocument The document.
  501. * @returns {Object} An object of data.
  502. */
  503. function getExpandoData(ownerDocument) {
  504. var data = expandoData[ownerDocument[expando]];
  505. if (!data) {
  506. data = {};
  507. expanID++;
  508. ownerDocument[expando] = expanID;
  509. expandoData[expanID] = data;
  510. }
  511. return data;
  512. }
  513. /**
  514. * returns a shived element for the given nodeName and document
  515. * @memberOf html5
  516. * @param {String} nodeName name of the element
  517. * @param {Document} ownerDocument The context document.
  518. * @returns {Object} The shived element.
  519. */
  520. function createElement(nodeName, ownerDocument, data){
  521. if (!ownerDocument) {
  522. ownerDocument = document;
  523. }
  524. if(supportsUnknownElements){
  525. return ownerDocument.createElement(nodeName);
  526. }
  527. if (!data) {
  528. data = getExpandoData(ownerDocument);
  529. }
  530. var node;
  531. if (data.cache[nodeName]) {
  532. node = data.cache[nodeName].cloneNode();
  533. } else if (saveClones.test(nodeName)) {
  534. node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
  535. } else {
  536. node = data.createElem(nodeName);
  537. }
  538. // Avoid adding some elements to fragments in IE < 9 because
  539. // * Attributes like `name` or `type` cannot be set/changed once an element
  540. // is inserted into a document/fragment
  541. // * Link elements with `src` attributes that are inaccessible, as with
  542. // a 403 response, will cause the tab/window to crash
  543. // * Script elements appended to fragments will execute when their `src`
  544. // or `text` property is set
  545. return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
  546. }
  547. /**
  548. * returns a shived DocumentFragment for the given document
  549. * @memberOf html5
  550. * @param {Document} ownerDocument The context document.
  551. * @returns {Object} The shived DocumentFragment.
  552. */
  553. function createDocumentFragment(ownerDocument, data){
  554. if (!ownerDocument) {
  555. ownerDocument = document;
  556. }
  557. if(supportsUnknownElements){
  558. return ownerDocument.createDocumentFragment();
  559. }
  560. data = data || getExpandoData(ownerDocument);
  561. var clone = data.frag.cloneNode(),
  562. i = 0,
  563. elems = getElements(),
  564. l = elems.length;
  565. for(;i<l;i++){
  566. clone.createElement(elems[i]);
  567. }
  568. return clone;
  569. }
  570. /**
  571. * Shivs the `createElement` and `createDocumentFragment` methods of the document.
  572. * @private
  573. * @param {Document|DocumentFragment} ownerDocument The document.
  574. * @param {Object} data of the document.
  575. */
  576. function shivMethods(ownerDocument, data) {
  577. if (!data.cache) {
  578. data.cache = {};
  579. data.createElem = ownerDocument.createElement;
  580. data.createFrag = ownerDocument.createDocumentFragment;
  581. data.frag = data.createFrag();
  582. }
  583. ownerDocument.createElement = function(nodeName) {
  584. //abort shiv
  585. if (!html5.shivMethods) {
  586. return data.createElem(nodeName);
  587. }
  588. return createElement(nodeName, ownerDocument, data);
  589. };
  590. ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
  591. 'var n=f.cloneNode(),c=n.createElement;' +
  592. 'h.shivMethods&&(' +
  593. // unroll the `createElement` calls
  594. getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
  595. data.createElem(nodeName);
  596. data.frag.createElement(nodeName);
  597. return 'c("' + nodeName + '")';
  598. }) +
  599. ');return n}'
  600. )(html5, data.frag);
  601. }
  602. /*--------------------------------------------------------------------------*/
  603. /**
  604. * Shivs the given document.
  605. * @memberOf html5
  606. * @param {Document} ownerDocument The document to shiv.
  607. * @returns {Document} The shived document.
  608. */
  609. function shivDocument(ownerDocument) {
  610. if (!ownerDocument) {
  611. ownerDocument = document;
  612. }
  613. var data = getExpandoData(ownerDocument);
  614. if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
  615. data.hasCSS = !!addStyleSheet(ownerDocument,
  616. // corrects block display not defined in IE6/7/8/9
  617. 'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
  618. // adds styling not present in IE6/7/8/9
  619. 'mark{background:#FF0;color:#000}' +
  620. // hides non-rendered elements
  621. 'template{display:none}'
  622. );
  623. }
  624. if (!supportsUnknownElements) {
  625. shivMethods(ownerDocument, data);
  626. }
  627. return ownerDocument;
  628. }
  629. /*--------------------------------------------------------------------------*/
  630. /**
  631. * The `html5` object is exposed so that more elements can be shived and
  632. * existing shiving can be detected on iframes.
  633. * @type Object
  634. * @example
  635. *
  636. * // options can be changed before the script is included
  637. * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
  638. */
  639. var html5 = {
  640. /**
  641. * An array or space separated string of node names of the elements to shiv.
  642. * @memberOf html5
  643. * @type Array|String
  644. */
  645. 'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
  646. /**
  647. * current version of html5shiv
  648. */
  649. 'version': version,
  650. /**
  651. * A flag to indicate that the HTML5 style sheet should be inserted.
  652. * @memberOf html5
  653. * @type Boolean
  654. */
  655. 'shivCSS': (options.shivCSS !== false),
  656. /**
  657. * Is equal to true if a browser supports creating unknown/HTML5 elements
  658. * @memberOf html5
  659. * @type boolean
  660. */
  661. 'supportsUnknownElements': supportsUnknownElements,
  662. /**
  663. * A flag to indicate that the document's `createElement` and `createDocumentFragment`
  664. * methods should be overwritten.
  665. * @memberOf html5
  666. * @type Boolean
  667. */
  668. 'shivMethods': (options.shivMethods !== false),
  669. /**
  670. * A string to describe the type of `html5` object ("default" or "default print").
  671. * @memberOf html5
  672. * @type String
  673. */
  674. 'type': 'default',
  675. // shivs the document according to the specified `html5` object options
  676. 'shivDocument': shivDocument,
  677. //creates a shived element
  678. createElement: createElement,
  679. //creates a shived documentFragment
  680. createDocumentFragment: createDocumentFragment,
  681. //extends list of elements
  682. addElements: addElements
  683. };
  684. /*--------------------------------------------------------------------------*/
  685. // expose html5
  686. window.html5 = html5;
  687. // shiv the document
  688. shivDocument(document);
  689. /*------------------------------- Print Shiv -------------------------------*/
  690. /** Used to filter media types */
  691. var reMedia = /^$|\b(?:all|print)\b/;
  692. /** Used to namespace printable elements */
  693. var shivNamespace = 'html5shiv';
  694. /** Detect whether the browser supports shivable style sheets */
  695. var supportsShivableSheets = !supportsUnknownElements && (function() {
  696. // assign a false negative if unable to shiv
  697. var docEl = document.documentElement;
  698. return !(
  699. typeof document.namespaces == 'undefined' ||
  700. typeof document.parentWindow == 'undefined' ||
  701. typeof docEl.applyElement == 'undefined' ||
  702. typeof docEl.removeNode == 'undefined' ||
  703. typeof window.attachEvent == 'undefined'
  704. );
  705. }());
  706. /*--------------------------------------------------------------------------*/
  707. /**
  708. * Wraps all HTML5 elements in the given document with printable elements.
  709. * (eg. the "header" element is wrapped with the "html5shiv:header" element)
  710. * @private
  711. * @param {Document} ownerDocument The document.
  712. * @returns {Array} An array wrappers added.
  713. */
  714. function addWrappers(ownerDocument) {
  715. var node,
  716. nodes = ownerDocument.getElementsByTagName('*'),
  717. index = nodes.length,
  718. reElements = RegExp('^(?:' + getElements().join('|') + ')$', 'i'),
  719. result = [];
  720. while (index--) {
  721. node = nodes[index];
  722. if (reElements.test(node.nodeName)) {
  723. result.push(node.applyElement(createWrapper(node)));
  724. }
  725. }
  726. return result;
  727. }
  728. /**
  729. * Creates a printable wrapper for the given element.
  730. * @private
  731. * @param {Element} element The element.
  732. * @returns {Element} The wrapper.
  733. */
  734. function createWrapper(element) {
  735. var node,
  736. nodes = element.attributes,
  737. index = nodes.length,
  738. wrapper = element.ownerDocument.createElement(shivNamespace + ':' + element.nodeName);
  739. // copy element attributes to the wrapper
  740. while (index--) {
  741. node = nodes[index];
  742. node.specified && wrapper.setAttribute(node.nodeName, node.nodeValue);
  743. }
  744. // copy element styles to the wrapper
  745. wrapper.style.cssText = element.style.cssText;
  746. return wrapper;
  747. }
  748. /**
  749. * Shivs the given CSS text.
  750. * (eg. header{} becomes html5shiv\:header{})
  751. * @private
  752. * @param {String} cssText The CSS text to shiv.
  753. * @returns {String} The shived CSS text.
  754. */
  755. function shivCssText(cssText) {
  756. var pair,
  757. parts = cssText.split('{'),
  758. index = parts.length,
  759. reElements = RegExp('(^|[\\s,>+~])(' + getElements().join('|') + ')(?=[[\\s,>+~#.:]|$)', 'gi'),
  760. replacement = '$1' + shivNamespace + '\\:$2';
  761. while (index--) {
  762. pair = parts[index] = parts[index].split('}');
  763. pair[pair.length - 1] = pair[pair.length - 1].replace(reElements, replacement);
  764. parts[index] = pair.join('}');
  765. }
  766. return parts.join('{');
  767. }
  768. /**
  769. * Removes the given wrappers, leaving the original elements.
  770. * @private
  771. * @params {Array} wrappers An array of printable wrappers.
  772. */
  773. function removeWrappers(wrappers) {
  774. var index = wrappers.length;
  775. while (index--) {
  776. wrappers[index].removeNode();
  777. }
  778. }
  779. /*--------------------------------------------------------------------------*/
  780. /**
  781. * Shivs the given document for print.
  782. * @memberOf html5
  783. * @param {Document} ownerDocument The document to shiv.
  784. * @returns {Document} The shived document.
  785. */
  786. function shivPrint(ownerDocument) {
  787. var shivedSheet,
  788. wrappers,
  789. data = getExpandoData(ownerDocument),
  790. namespaces = ownerDocument.namespaces,
  791. ownerWindow = ownerDocument.parentWindow;
  792. if (!supportsShivableSheets || ownerDocument.printShived) {
  793. return ownerDocument;
  794. }
  795. if (typeof namespaces[shivNamespace] == 'undefined') {
  796. namespaces.add(shivNamespace);
  797. }
  798. function removeSheet() {
  799. clearTimeout(data._removeSheetTimer);
  800. if (shivedSheet) {
  801. shivedSheet.removeNode(true);
  802. }
  803. shivedSheet= null;
  804. }
  805. ownerWindow.attachEvent('onbeforeprint', function() {
  806. removeSheet();
  807. var imports,
  808. length,
  809. sheet,
  810. collection = ownerDocument.styleSheets,
  811. cssText = [],
  812. index = collection.length,
  813. sheets = Array(index);
  814. // convert styleSheets collection to an array
  815. while (index--) {
  816. sheets[index] = collection[index];
  817. }
  818. // concat all style sheet CSS text
  819. while ((sheet = sheets.pop())) {
  820. // IE does not enforce a same origin policy for external style sheets...
  821. // but has trouble with some dynamically created stylesheets
  822. if (!sheet.disabled && reMedia.test(sheet.media)) {
  823. try {
  824. imports = sheet.imports;
  825. length = imports.length;
  826. } catch(er){
  827. length = 0;
  828. }
  829. for (index = 0; index < length; index++) {
  830. sheets.push(imports[index]);
  831. }
  832. try {
  833. cssText.push(sheet.cssText);
  834. } catch(er){}
  835. }
  836. }
  837. // wrap all HTML5 elements with printable elements and add the shived style sheet
  838. cssText = shivCssText(cssText.reverse().join(''));
  839. wrappers = addWrappers(ownerDocument);
  840. shivedSheet = addStyleSheet(ownerDocument, cssText);
  841. });
  842. ownerWindow.attachEvent('onafterprint', function() {
  843. // remove wrappers, leaving the original elements, and remove the shived style sheet
  844. removeWrappers(wrappers);
  845. clearTimeout(data._removeSheetTimer);
  846. data._removeSheetTimer = setTimeout(removeSheet, 500);
  847. });
  848. ownerDocument.printShived = true;
  849. return ownerDocument;
  850. }
  851. /*--------------------------------------------------------------------------*/
  852. // expose API
  853. html5.type += ' print';
  854. html5.shivPrint = shivPrint;
  855. // shiv for print
  856. shivPrint(document);
  857. if(typeof module == 'object' && module.exports){
  858. module.exports = html5;
  859. }
  860. }(typeof window !== "undefined" ? window : this, document));
  861. }
  862. ;
  863. /**
  864. * contains checks to see if a string contains another string
  865. *
  866. * @access private
  867. * @function contains
  868. * @param {string} str - The string we want to check for substrings
  869. * @param {string} substr - The substring we want to search the first string for
  870. * @returns {boolean} true if and only if the first string 'str' contains the second string 'substr'
  871. */
  872. function contains(str, substr) {
  873. return !!~('' + str).indexOf(substr);
  874. }
  875. ;
  876. /**
  877. * createElement is a convenience wrapper around document.createElement. Since we
  878. * use createElement all over the place, this allows for (slightly) smaller code
  879. * as well as abstracting away issues with creating elements in contexts other than
  880. * HTML documents (e.g. SVG documents).
  881. *
  882. * @access private
  883. * @function createElement
  884. * @returns {HTMLElement|SVGElement} An HTML or SVG element
  885. */
  886. function createElement() {
  887. if (typeof document.createElement !== 'function') {
  888. // This is the case in IE7, where the type of createElement is "object".
  889. // For this reason, we cannot call apply() as Object is not a Function.
  890. return document.createElement(arguments[0]);
  891. } else if (isSVG) {
  892. return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
  893. } else {
  894. return document.createElement.apply(document, arguments);
  895. }
  896. }
  897. ;
  898. /**
  899. * Create our "modernizr" element that we do most feature tests on.
  900. *
  901. * @access private
  902. */
  903. var modElem = {
  904. elem: createElement('modernizr')
  905. };
  906. // Clean up this element
  907. Modernizr._q.push(function() {
  908. delete modElem.elem;
  909. });
  910. var mStyle = {
  911. style: modElem.elem.style
  912. };
  913. // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
  914. // the front of the queue.
  915. Modernizr._q.unshift(function() {
  916. delete mStyle.style;
  917. });
  918. /**
  919. * getBody returns the body of a document, or an element that can stand in for
  920. * the body if a real body does not exist
  921. *
  922. * @access private
  923. * @function getBody
  924. * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
  925. * artificially created element that stands in for the body
  926. */
  927. function getBody() {
  928. // After page load injecting a fake body doesn't work so check if body exists
  929. var body = document.body;
  930. if (!body) {
  931. // Can't use the real body create a fake one.
  932. body = createElement(isSVG ? 'svg' : 'body');
  933. body.fake = true;
  934. }
  935. return body;
  936. }
  937. ;
  938. /**
  939. * injectElementWithStyles injects an element with style element and some CSS rules
  940. *
  941. * @access private
  942. * @function injectElementWithStyles
  943. * @param {string} rule - String representing a css rule
  944. * @param {Function} callback - A function that is used to test the injected element
  945. * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
  946. * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
  947. * @returns {boolean} the result of the specified callback test
  948. */
  949. function injectElementWithStyles(rule, callback, nodes, testnames) {
  950. var mod = 'modernizr';
  951. var style;
  952. var ret;
  953. var node;
  954. var docOverflow;
  955. var div = createElement('div');
  956. var body = getBody();
  957. if (parseInt(nodes, 10)) {
  958. // In order not to give false positives we create a node for each test
  959. // This also allows the method to scale for unspecified uses
  960. while (nodes--) {
  961. node = createElement('div');
  962. node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
  963. div.appendChild(node);
  964. }
  965. }
  966. style = createElement('style');
  967. style.type = 'text/css';
  968. style.id = 's' + mod;
  969. // 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.
  970. // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
  971. (!body.fake ? div : body).appendChild(style);
  972. body.appendChild(div);
  973. if (style.styleSheet) {
  974. style.styleSheet.cssText = rule;
  975. } else {
  976. style.appendChild(document.createTextNode(rule));
  977. }
  978. div.id = mod;
  979. if (body.fake) {
  980. //avoid crashing IE8, if background image is used
  981. body.style.background = '';
  982. //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
  983. body.style.overflow = 'hidden';
  984. docOverflow = docElement.style.overflow;
  985. docElement.style.overflow = 'hidden';
  986. docElement.appendChild(body);
  987. }
  988. ret = callback(div, rule);
  989. // If this is done after page load we don't want to remove the body so check if body exists
  990. if (body.fake) {
  991. body.parentNode.removeChild(body);
  992. docElement.style.overflow = docOverflow;
  993. // Trigger layout so kinetic scrolling isn't disabled in iOS6+
  994. // eslint-disable-next-line
  995. docElement.offsetHeight;
  996. } else {
  997. div.parentNode.removeChild(div);
  998. }
  999. return !!ret;
  1000. }
  1001. ;
  1002. /**
  1003. * domToCSS takes a camelCase string and converts it to kebab-case
  1004. * e.g. boxSizing -> box-sizing
  1005. *
  1006. * @access private
  1007. * @function domToCSS
  1008. * @param {string} name - String name of camelCase prop we want to convert
  1009. * @returns {string} The kebab-case version of the supplied name
  1010. */
  1011. function domToCSS(name) {
  1012. return name.replace(/([A-Z])/g, function(str, m1) {
  1013. return '-' + m1.toLowerCase();
  1014. }).replace(/^ms-/, '-ms-');
  1015. }
  1016. ;
  1017. /**
  1018. * wrapper around getComputedStyle, to fix issues with Firefox returning null when
  1019. * called inside of a hidden iframe
  1020. *
  1021. * @access private
  1022. * @function computedStyle
  1023. * @param {HTMLElement|SVGElement} elem - The element we want to find the computed styles of
  1024. * @param {string|null} [pseudo] - An optional pseudo element selector (e.g. :before), of null if none
  1025. * @param {string} prop - A CSS property
  1026. * @returns {CSSStyleDeclaration} the value of the specified CSS property
  1027. */
  1028. function computedStyle(elem, pseudo, prop) {
  1029. var result;
  1030. if ('getComputedStyle' in window) {
  1031. result = getComputedStyle.call(window, elem, pseudo);
  1032. var console = window.console;
  1033. if (result !== null) {
  1034. if (prop) {
  1035. result = result.getPropertyValue(prop);
  1036. }
  1037. } else {
  1038. if (console) {
  1039. var method = console.error ? 'error' : 'log';
  1040. console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate');
  1041. }
  1042. }
  1043. } else {
  1044. result = !pseudo && elem.currentStyle && elem.currentStyle[prop];
  1045. }
  1046. return result;
  1047. }
  1048. ;
  1049. /**
  1050. * nativeTestProps allows for us to use native feature detection functionality if available.
  1051. * some prefixed form, or false, in the case of an unsupported rule
  1052. *
  1053. * @access private
  1054. * @function nativeTestProps
  1055. * @param {array} props - An array of property names
  1056. * @param {string} value - A string representing the value we want to check via @supports
  1057. * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
  1058. */
  1059. // Accepts a list of property names and a single value
  1060. // Returns `undefined` if native detection not available
  1061. function nativeTestProps(props, value) {
  1062. var i = props.length;
  1063. // Start with the JS API: https://www.w3.org/TR/css3-conditional/#the-css-interface
  1064. if ('CSS' in window && 'supports' in window.CSS) {
  1065. // Try every prefixed variant of the property
  1066. while (i--) {
  1067. if (window.CSS.supports(domToCSS(props[i]), value)) {
  1068. return true;
  1069. }
  1070. }
  1071. return false;
  1072. }
  1073. // Otherwise fall back to at-rule (for Opera 12.x)
  1074. else if ('CSSSupportsRule' in window) {
  1075. // Build a condition string for every prefixed variant
  1076. var conditionText = [];
  1077. while (i--) {
  1078. conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
  1079. }
  1080. conditionText = conditionText.join(' or ');
  1081. return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
  1082. return computedStyle(node, null, 'position') === 'absolute';
  1083. });
  1084. }
  1085. return undefined;
  1086. }
  1087. ;
  1088. /**
  1089. * cssToDOM takes a kebab-case string and converts it to camelCase
  1090. * e.g. box-sizing -> boxSizing
  1091. *
  1092. * @access private
  1093. * @function cssToDOM
  1094. * @param {string} name - String name of kebab-case prop we want to convert
  1095. * @returns {string} The camelCase version of the supplied name
  1096. */
  1097. function cssToDOM(name) {
  1098. return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
  1099. return m1 + m2.toUpperCase();
  1100. }).replace(/^-/, '');
  1101. }
  1102. ;
  1103. // testProps is a generic CSS / DOM property test.
  1104. // In testing support for a given CSS property, it's legit to test:
  1105. // `elem.style[styleName] !== undefined`
  1106. // If the property is supported it will return an empty string,
  1107. // if unsupported it will return undefined.
  1108. // We'll take advantage of this quick test and skip setting a style
  1109. // on our modernizr element, but instead just testing undefined vs
  1110. // empty string.
  1111. // Property names can be provided in either camelCase or kebab-case.
  1112. function testProps(props, prefixed, value, skipValueTest) {
  1113. skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
  1114. // Try native detect first
  1115. if (!is(value, 'undefined')) {
  1116. var result = nativeTestProps(props, value);
  1117. if (!is(result, 'undefined')) {
  1118. return result;
  1119. }
  1120. }
  1121. // Otherwise do it properly
  1122. var afterInit, i, propsLength, prop, before;
  1123. // If we don't have a style element, that means we're running async or after
  1124. // the core tests, so we'll need to create our own elements to use
  1125. // inside of an SVG element, in certain browsers, the `style` element is only
  1126. // defined for valid tags. Therefore, if `modernizr` does not have one, we
  1127. // fall back to a less used element and hope for the best.
  1128. // for strict XHTML browsers the hardly used samp element is used
  1129. var elems = ['modernizr', 'tspan', 'samp'];
  1130. while (!mStyle.style && elems.length) {
  1131. afterInit = true;
  1132. mStyle.modElem = createElement(elems.shift());
  1133. mStyle.style = mStyle.modElem.style;
  1134. }
  1135. // Delete the objects if we created them.
  1136. function cleanElems() {
  1137. if (afterInit) {
  1138. delete mStyle.style;
  1139. delete mStyle.modElem;
  1140. }
  1141. }
  1142. propsLength = props.length;
  1143. for (i = 0; i < propsLength; i++) {
  1144. prop = props[i];
  1145. before = mStyle.style[prop];
  1146. if (contains(prop, '-')) {
  1147. prop = cssToDOM(prop);
  1148. }
  1149. if (mStyle.style[prop] !== undefined) {
  1150. // If value to test has been passed in, do a set-and-check test.
  1151. // 0 (integer) is a valid property value, so check that `value` isn't
  1152. // undefined, rather than just checking it's truthy.
  1153. if (!skipValueTest && !is(value, 'undefined')) {
  1154. // Needs a try catch block because of old IE. This is slow, but will
  1155. // be avoided in most cases because `skipValueTest` will be used.
  1156. try {
  1157. mStyle.style[prop] = value;
  1158. } catch (e) {}
  1159. // If the property value has changed, we assume the value used is
  1160. // supported. If `value` is empty string, it'll fail here (because
  1161. // it hasn't changed), which matches how browsers have implemented
  1162. // CSS.supports()
  1163. if (mStyle.style[prop] !== before) {
  1164. cleanElems();
  1165. return prefixed === 'pfx' ? prop : true;
  1166. }
  1167. }
  1168. // Otherwise just return true, or the property name if this is a
  1169. // `prefixed()` call
  1170. else {
  1171. cleanElems();
  1172. return prefixed === 'pfx' ? prop : true;
  1173. }
  1174. }
  1175. }
  1176. cleanElems();
  1177. return false;
  1178. }
  1179. ;
  1180. /**
  1181. * testProp() investigates whether a given style property is recognized
  1182. * Property names can be provided in either camelCase or kebab-case.
  1183. *
  1184. * @memberOf Modernizr
  1185. * @name Modernizr.testProp
  1186. * @access public
  1187. * @optionName Modernizr.testProp()
  1188. * @optionProp testProp
  1189. * @function testProp
  1190. * @param {string} prop - Name of the CSS property to check
  1191. * @param {string} [value] - Name of the CSS value to check
  1192. * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
  1193. * @returns {boolean} an empty string if the property is supported, undefined if its unsupported
  1194. * @example
  1195. *
  1196. * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
  1197. * version of the string.
  1198. *
  1199. * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
  1200. *
  1201. * ```js
  1202. * Modernizr.testProp('pointerEvents') // true
  1203. * ```
  1204. *
  1205. * You can also provide a value as an optional second argument to check if a
  1206. * specific value is supported
  1207. *
  1208. * ```js
  1209. * Modernizr.testProp('pointerEvents', 'none') // true
  1210. * Modernizr.testProp('pointerEvents', 'penguin') // false
  1211. * ```
  1212. */
  1213. var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
  1214. return testProps([prop], undefined, value, useValue);
  1215. };
  1216. /**
  1217. * If the browsers follow the spec, then they would expose vendor-specific styles as:
  1218. * elem.style.WebkitBorderRadius
  1219. * instead of something like the following (which is technically incorrect):
  1220. * elem.style.webkitBorderRadius
  1221. * WebKit ghosts their properties in lowercase but Opera & Moz do not.
  1222. * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
  1223. * erik.eae.net/archives/2008/03/10/21.48.10/
  1224. * More here: github.com/Modernizr/Modernizr/issues/issue/21
  1225. *
  1226. * @access private
  1227. * @returns {string} The string representing the vendor-specific style properties
  1228. */
  1229. var omPrefixes = 'Moz O ms Webkit';
  1230. var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
  1231. ModernizrProto._cssomPrefixes = cssomPrefixes;
  1232. /**
  1233. * List of JavaScript DOM values used for tests
  1234. *
  1235. * @memberOf Modernizr
  1236. * @name Modernizr._domPrefixes
  1237. * @optionName Modernizr._domPrefixes
  1238. * @optionProp domPrefixes
  1239. * @access public
  1240. * @example
  1241. *
  1242. * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
  1243. * than kebab-case properties, all properties are their Capitalized variant
  1244. *
  1245. * ```js
  1246. * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
  1247. * ```
  1248. */
  1249. var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
  1250. ModernizrProto._domPrefixes = domPrefixes;
  1251. /**
  1252. * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
  1253. *
  1254. * @access private
  1255. * @function fnBind
  1256. * @param {Function} fn - a function you want to change `this` reference to
  1257. * @param {Object} that - the `this` you want to call the function with
  1258. * @returns {Function} The wrapped version of the supplied function
  1259. */
  1260. function fnBind(fn, that) {
  1261. return function() {
  1262. return fn.apply(that, arguments);
  1263. };
  1264. }
  1265. ;
  1266. /**
  1267. * testDOMProps is a generic DOM property test; if a browser supports
  1268. * a certain property, it won't return undefined for it.
  1269. *
  1270. * @access private
  1271. * @function testDOMProps
  1272. * @param {Array<string>} props - An array of properties to test for
  1273. * @param {Object} obj - An object or Element you want to use to test the parameters again
  1274. * @param {boolean|Object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
  1275. * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported
  1276. */
  1277. function testDOMProps(props, obj, elem) {
  1278. var item;
  1279. for (var i in props) {
  1280. if (props[i] in obj) {
  1281. // return the property name as a string
  1282. if (elem === false) {
  1283. return props[i];
  1284. }
  1285. item = obj[props[i]];
  1286. // let's bind a function
  1287. if (is(item, 'function')) {
  1288. // bind to obj unless overridden
  1289. return fnBind(item, elem || obj);
  1290. }
  1291. // return the unbound function or obj or value
  1292. return item;
  1293. }
  1294. }
  1295. return false;
  1296. }
  1297. ;
  1298. /**
  1299. * testPropsAll tests a list of DOM properties we want to check against.
  1300. * We specify literally ALL possible (known and/or likely) properties on
  1301. * the element including the non-vendor prefixed one, for forward-
  1302. * compatibility.
  1303. *
  1304. * @access private
  1305. * @function testPropsAll
  1306. * @param {string} prop - A string of the property to test for
  1307. * @param {string|Object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
  1308. * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
  1309. * @param {string} [value] - A string of a css value
  1310. * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
  1311. * @returns {false|string} returns the string version of the property, or false if it is unsupported
  1312. */
  1313. function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
  1314. var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
  1315. props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
  1316. // did they call .prefixed('boxSizing') or are we just testing a prop?
  1317. if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
  1318. return testProps(props, prefixed, value, skipValueTest);
  1319. // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
  1320. } else {
  1321. props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
  1322. return testDOMProps(props, prefixed, elem);
  1323. }
  1324. }
  1325. // Modernizr.testAllProps() investigates whether a given style property,
  1326. // or any of its vendor-prefixed variants, is recognized
  1327. //
  1328. // Note that the property names must be provided in the camelCase variant.
  1329. // Modernizr.testAllProps('boxSizing')
  1330. ModernizrProto.testAllProps = testPropsAll;
  1331. /**
  1332. * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
  1333. * some prefixed form, or false, in the case of an unsupported rule
  1334. *
  1335. * @memberOf Modernizr
  1336. * @name Modernizr.atRule
  1337. * @optionName Modernizr.atRule()
  1338. * @optionProp atRule
  1339. * @access public
  1340. * @function atRule
  1341. * @param {string} prop - String name of the @-rule to test for
  1342. * @returns {string|boolean} The string representing the (possibly prefixed)
  1343. * valid version of the @-rule, or `false` when it is unsupported.
  1344. * @example
  1345. * ```js
  1346. * var keyframes = Modernizr.atRule('@keyframes');
  1347. *
  1348. * if (keyframes) {
  1349. * // keyframes are supported
  1350. * // could be `@-webkit-keyframes` or `@keyframes`
  1351. * } else {
  1352. * // keyframes === `false`
  1353. * }
  1354. * ```
  1355. */
  1356. var atRule = function(prop) {
  1357. var length = prefixes.length;
  1358. var cssrule = window.CSSRule;
  1359. var rule;
  1360. if (typeof cssrule === 'undefined') {
  1361. return undefined;
  1362. }
  1363. if (!prop) {
  1364. return false;
  1365. }
  1366. // remove literal @ from beginning of provided property
  1367. prop = prop.replace(/^@/, '');
  1368. // CSSRules use underscores instead of dashes
  1369. rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
  1370. if (rule in cssrule) {
  1371. return '@' + prop;
  1372. }
  1373. for (var i = 0; i < length; i++) {
  1374. // prefixes gives us something like -o-, and we want O_
  1375. var prefix = prefixes[i];
  1376. var thisRule = prefix.toUpperCase() + '_' + rule;
  1377. if (thisRule in cssrule) {
  1378. return '@-' + prefix.toLowerCase() + '-' + prop;
  1379. }
  1380. }
  1381. return false;
  1382. };
  1383. ModernizrProto.atRule = atRule;
  1384. /**
  1385. * prefixed returns the prefixed or nonprefixed property name variant of your input
  1386. *
  1387. * @memberOf Modernizr
  1388. * @name Modernizr.prefixed
  1389. * @optionName Modernizr.prefixed()
  1390. * @optionProp prefixed
  1391. * @access public
  1392. * @function prefixed
  1393. * @param {string} prop - String name of the property to test for
  1394. * @param {Object} [obj] - An object to test for the prefixed properties on
  1395. * @param {HTMLElement} [elem] - An element used to test specific properties against
  1396. * @returns {string|false} The string representing the (possibly prefixed) valid
  1397. * version of the property, or `false` when it is unsupported.
  1398. * @example
  1399. *
  1400. * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
  1401. * opposed to the css style kebab-case) form and returns the (possibly prefixed)
  1402. * version of that property that the browser actually supports.
  1403. *
  1404. * For example, in older Firefox...
  1405. * ```js
  1406. * prefixed('boxSizing')
  1407. * ```
  1408. * returns 'MozBoxSizing'
  1409. *
  1410. * In newer Firefox, as well as any other browser that support the unprefixed
  1411. * version would simply return `boxSizing`. Any browser that does not support
  1412. * the property at all, it will return `false`.
  1413. *
  1414. * By default, prefixed is checked against a DOM element. If you want to check
  1415. * for a property on another object, just pass it as a second argument
  1416. *
  1417. * ```js
  1418. * var rAF = prefixed('requestAnimationFrame', window);
  1419. *
  1420. * raf(function() {
  1421. * renderFunction();
  1422. * })
  1423. * ```
  1424. *
  1425. * Note that this will return _the actual function_ - not the name of the function.
  1426. * If you need the actual name of the property, pass in `false` as a third argument
  1427. *
  1428. * ```js
  1429. * var rAFProp = prefixed('requestAnimationFrame', window, false);
  1430. *
  1431. * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
  1432. * ```
  1433. *
  1434. * One common use case for prefixed is if you're trying to determine which transition
  1435. * end event to bind to, you might do something like...
  1436. * ```js
  1437. * var transEndEventNames = {
  1438. * 'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
  1439. * 'MozTransition' : 'transitionend', * only for FF < 15
  1440. * 'transition' : 'transitionend' * IE10, Opera, Chrome, FF 15+, Saf 7+
  1441. * };
  1442. *
  1443. * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
  1444. * ```
  1445. *
  1446. * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
  1447. */
  1448. var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
  1449. if (prop.indexOf('@') === 0) {
  1450. return atRule(prop);
  1451. }
  1452. if (prop.indexOf('-') !== -1) {
  1453. // Convert kebab-case to camelCase
  1454. prop = cssToDOM(prop);
  1455. }
  1456. if (!obj) {
  1457. return testPropsAll(prop, 'pfx');
  1458. } else {
  1459. // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
  1460. return testPropsAll(prop, obj, elem);
  1461. }
  1462. };
  1463. /*!
  1464. {
  1465. "name": "Web Intents",
  1466. "property": "webintents",
  1467. "authors": ["Eric Bidelman"],
  1468. "notes": [{
  1469. "name": "Web Intents project site",
  1470. "href": "http://www.webintents.org/"
  1471. }],
  1472. "polyfills": ["webintents"],
  1473. "builderAliases": ["web_intents"]
  1474. }
  1475. !*/
  1476. /* DOC
  1477. Detects native support for the Web Intents APIs for service discovery and inter-application communication.
  1478. Chrome added support for this in v19, but [removed it again in v24](https://lists.w3.org/Archives/Public/public-web-intents/2012Nov/0000.html) because of "a number of areas for
  1479. development in both the API and specific user experience in Chrome". No other browsers currently support it, however a [JavaScript shim](http://www.webintents.org/#javascriptshim) is available.
  1480. */
  1481. Modernizr.addTest('webintents', !!prefixed('startActivity', navigator));
  1482. /**
  1483. * testStyles injects an element with style element and some CSS rules
  1484. *
  1485. * @memberOf Modernizr
  1486. * @name Modernizr.testStyles
  1487. * @optionName Modernizr.testStyles()
  1488. * @optionProp testStyles
  1489. * @access public
  1490. * @function testStyles
  1491. * @param {string} rule - String representing a css rule
  1492. * @param {function} callback - A function that is used to test the injected element
  1493. * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
  1494. * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
  1495. * @returns {boolean}
  1496. * @example
  1497. *
  1498. * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
  1499. * along with (possibly multiple) DOM elements. This lets you check for features
  1500. * 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).
  1501. *
  1502. * ```js
  1503. * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
  1504. * // elem is the first DOM node in the page (by default #modernizr)
  1505. * // rule is the first argument you supplied - the CSS rule in string form
  1506. *
  1507. * addTest('widthworks', elem.style.width === '9px')
  1508. * });
  1509. * ```
  1510. *
  1511. * If your test requires multiple nodes, you can include a third argument
  1512. * indicating how many additional div elements to include on the page. The
  1513. * additional nodes are injected as children of the `elem` that is returned as
  1514. * the first argument to the callback.
  1515. *
  1516. * ```js
  1517. * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
  1518. * document.getElementById('modernizr').style.width === '1px'; // true
  1519. * document.getElementById('modernizr2').style.width === '2px'; // true
  1520. * elem.firstChild === document.getElementById('modernizr2'); // true
  1521. * }, 1);
  1522. * ```
  1523. *
  1524. * By default, all of the additional elements have an ID of `modernizr[n]`, where
  1525. * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
  1526. * the second additional is `#modernizr3`, etc.).
  1527. * If you want to have more meaningful IDs for your function, you can provide
  1528. * them as the fourth argument, as an array of strings
  1529. *
  1530. * ```js
  1531. * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
  1532. * elem.firstChild === document.getElementById('foo'); // true
  1533. * elem.lastChild === document.getElementById('bar'); // true
  1534. * }, 2, ['foo', 'bar']);
  1535. * ```
  1536. */
  1537. var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
  1538. /*!
  1539. {
  1540. "name": "CSS general sibling selector",
  1541. "caniuse": "css-sel3",
  1542. "property": "siblinggeneral",
  1543. "tags": ["css"],
  1544. "notes": [{
  1545. "name": "Related Github Issue",
  1546. "href": "https://github.com/Modernizr/Modernizr/pull/889"
  1547. }]
  1548. }
  1549. !*/
  1550. Modernizr.addTest('siblinggeneral', function() {
  1551. return testStyles('#modernizr div {width:100px} #modernizr div ~ div {width:200px;display:block}', function(elem) {
  1552. return elem.lastChild.offsetWidth === 200;
  1553. }, 2);
  1554. });
  1555. /*!
  1556. {
  1557. "name": "SVG",
  1558. "property": "svg",
  1559. "caniuse": "svg",
  1560. "tags": ["svg"],
  1561. "authors": ["Erik Dahlstrom"],
  1562. "polyfills": [
  1563. "svgweb",
  1564. "raphael",
  1565. "amplesdk",
  1566. "canvg",
  1567. "svg-boilerplate",
  1568. "sie",
  1569. "dojogfx",
  1570. "fabricjs"
  1571. ]
  1572. }
  1573. !*/
  1574. /* DOC
  1575. Detects support for SVG in `<embed>` or `<object>` elements.
  1576. */
  1577. Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
  1578. // Run each test
  1579. testRunner();
  1580. // Remove the "no-js" class if it exists
  1581. setClasses(classes);
  1582. delete ModernizrProto.addTest;
  1583. delete ModernizrProto.addAsyncTest;
  1584. // Run the things that are supposed to run after the tests
  1585. for (var i = 0; i < Modernizr._q.length; i++) {
  1586. Modernizr._q[i]();
  1587. }
  1588. // Leak Modernizr namespace
  1589. window.Modernizr = Modernizr;
  1590. ;
  1591. })(window, document);