respond.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*! Respond.js v1.4.2: min/max-width media query polyfill
  2. * Copyright 2014 Scott Jehl
  3. * Licensed under MIT
  4. * https://j.mp/respondjs */
  5. /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
  6. /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
  7. (function(w) {
  8. "use strict";
  9. w.matchMedia = w.matchMedia || function(doc, undefined) {
  10. var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
  11. div.id = "mq-test-1";
  12. div.style.cssText = "position:absolute;top:-100em";
  13. fakeBody.style.background = "none";
  14. fakeBody.appendChild(div);
  15. return function(q) {
  16. div.innerHTML = '&shy;<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
  17. docElem.insertBefore(fakeBody, refNode);
  18. bool = div.offsetWidth === 42;
  19. docElem.removeChild(fakeBody);
  20. return {
  21. matches: bool,
  22. media: q
  23. };
  24. };
  25. }(w.document);
  26. })(this);
  27. (function(w) {
  28. "use strict";
  29. var respond = {};
  30. w.respond = respond;
  31. respond.update = function() {};
  32. var requestQueue = [], xmlHttp = function() {
  33. var xmlhttpmethod = false;
  34. try {
  35. xmlhttpmethod = new w.XMLHttpRequest();
  36. } catch (e) {
  37. xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
  38. }
  39. return function() {
  40. return xmlhttpmethod;
  41. };
  42. }(), ajax = function(url, callback) {
  43. var req = xmlHttp();
  44. if (!req) {
  45. return;
  46. }
  47. req.open("GET", url, true);
  48. req.onreadystatechange = function() {
  49. if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
  50. return;
  51. }
  52. callback(req.responseText);
  53. };
  54. if (req.readyState === 4) {
  55. return;
  56. }
  57. req.send(null);
  58. }, isUnsupportedMediaQuery = function(query) {
  59. return query.replace(respond.regex.minmaxwh, "").match(respond.regex.other);
  60. };
  61. respond.ajax = ajax;
  62. respond.queue = requestQueue;
  63. respond.unsupportedmq = isUnsupportedMediaQuery;
  64. respond.regex = {
  65. media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
  66. keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
  67. comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,
  68. urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
  69. findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
  70. only: /(only\s+)?([a-zA-Z]+)\s?/,
  71. minw: /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
  72. maxw: /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
  73. minmaxwh: /\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,
  74. other: /\([^\)]*\)/g
  75. };
  76. respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
  77. if (respond.mediaQueriesSupported) {
  78. return;
  79. }
  80. var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
  81. var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
  82. div.style.cssText = "position:absolute;font-size:1em;width:1em";
  83. if (!body) {
  84. body = fakeUsed = doc.createElement("body");
  85. body.style.background = "none";
  86. }
  87. docElem.style.fontSize = "100%";
  88. body.style.fontSize = "100%";
  89. body.appendChild(div);
  90. if (fakeUsed) {
  91. docElem.insertBefore(body, docElem.firstChild);
  92. }
  93. ret = div.offsetWidth;
  94. if (fakeUsed) {
  95. docElem.removeChild(body);
  96. } else {
  97. body.removeChild(div);
  98. }
  99. docElem.style.fontSize = originalHTMLFontSize;
  100. if (originalBodyFontSize) {
  101. body.style.fontSize = originalBodyFontSize;
  102. }
  103. ret = eminpx = parseFloat(ret);
  104. return ret;
  105. }, applyMedia = function(fromResize) {
  106. var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
  107. if (fromResize && lastCall && now - lastCall < resizeThrottle) {
  108. w.clearTimeout(resizeDefer);
  109. resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
  110. return;
  111. } else {
  112. lastCall = now;
  113. }
  114. for (var i in mediastyles) {
  115. if (mediastyles.hasOwnProperty(i)) {
  116. var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
  117. if (!!min) {
  118. min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
  119. }
  120. if (!!max) {
  121. max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
  122. }
  123. if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
  124. if (!styleBlocks[thisstyle.media]) {
  125. styleBlocks[thisstyle.media] = [];
  126. }
  127. styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
  128. }
  129. }
  130. }
  131. for (var j in appendedEls) {
  132. if (appendedEls.hasOwnProperty(j)) {
  133. if (appendedEls[j] && appendedEls[j].parentNode === head) {
  134. head.removeChild(appendedEls[j]);
  135. }
  136. }
  137. }
  138. appendedEls.length = 0;
  139. for (var k in styleBlocks) {
  140. if (styleBlocks.hasOwnProperty(k)) {
  141. var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
  142. ss.type = "text/css";
  143. ss.media = k;
  144. head.insertBefore(ss, lastLink.nextSibling);
  145. if (ss.styleSheet) {
  146. ss.styleSheet.cssText = css;
  147. } else {
  148. ss.appendChild(doc.createTextNode(css));
  149. }
  150. appendedEls.push(ss);
  151. }
  152. }
  153. }, translate = function(styles, href, media) {
  154. var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
  155. href = href.substring(0, href.lastIndexOf("/"));
  156. var repUrls = function(css) {
  157. return css.replace(respond.regex.urls, "$1" + href + "$2$3");
  158. }, useMedia = !ql && media;
  159. if (href.length) {
  160. href += "/";
  161. }
  162. if (useMedia) {
  163. ql = 1;
  164. }
  165. for (var i = 0; i < ql; i++) {
  166. var fullq, thisq, eachq, eql;
  167. if (useMedia) {
  168. fullq = media;
  169. rules.push(repUrls(styles));
  170. } else {
  171. fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
  172. rules.push(RegExp.$2 && repUrls(RegExp.$2));
  173. }
  174. eachq = fullq.split(",");
  175. eql = eachq.length;
  176. for (var j = 0; j < eql; j++) {
  177. thisq = eachq[j];
  178. if (isUnsupportedMediaQuery(thisq)) {
  179. continue;
  180. }
  181. mediastyles.push({
  182. media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
  183. rules: rules.length - 1,
  184. hasquery: thisq.indexOf("(") > -1,
  185. minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
  186. maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
  187. });
  188. }
  189. }
  190. applyMedia();
  191. }, makeRequests = function() {
  192. if (requestQueue.length) {
  193. var thisRequest = requestQueue.shift();
  194. ajax(thisRequest.href, function(styles) {
  195. translate(styles, thisRequest.href, thisRequest.media);
  196. parsedSheets[thisRequest.href] = true;
  197. w.setTimeout(function() {
  198. makeRequests();
  199. }, 0);
  200. });
  201. }
  202. }, ripCSS = function() {
  203. for (var i = 0; i < links.length; i++) {
  204. var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
  205. if (!!href && isCSS && !parsedSheets[href]) {
  206. if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
  207. translate(sheet.styleSheet.rawCssText, href, media);
  208. parsedSheets[href] = true;
  209. } else {
  210. if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
  211. if (href.substring(0, 2) === "//") {
  212. href = w.location.protocol + href;
  213. }
  214. requestQueue.push({
  215. href: href,
  216. media: media
  217. });
  218. }
  219. }
  220. }
  221. }
  222. makeRequests();
  223. };
  224. ripCSS();
  225. respond.update = ripCSS;
  226. respond.getEmValue = getEmValue;
  227. function callMedia() {
  228. applyMedia(true);
  229. }
  230. if (w.addEventListener) {
  231. w.addEventListener("resize", callMedia, false);
  232. } else if (w.attachEvent) {
  233. w.attachEvent("onresize", callMedia);
  234. }
  235. })(this);