diff --git a/README.md b/README.md
index d96fe411..0415e9f9 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,15 @@ Usage Instructions
3. Crack open Internet Explorer and pump fists in delight
+Options
+======
+
+- Set `window.RESPOND_REPLACE_STYLES = true` before referencing this library to avoid altering the order of media queries in the CSS. NOTE: this is not as fast as the default, but still quick. See the notes below and #325.
+```html
+
+
+```
+
CDN/X-Domain Setup
======
@@ -46,6 +55,8 @@ Some notes to keep in mind:
- As you might guess, this implementation is quite dumb in regards to CSS parsing rules. This is a good thing, because that allows it to run really fast, but its looseness may also cause unexpected behavior. For example: if you enclose a whole media query in a comment intending to disable its rules, you'll probably find that those rules will end up enabled in non-media-query-supporting browsers.
+- Respond.js by default will change the order of media queries by moving them after the stylesheet they came from. This is the best performing method but does have a drawback: see #325. To fix that, but at a slight cost to performance, set `window.RESPOND_REPLACE_STYLES = true` before this script runs: each stylesheet is removed and replaced with a parsed `',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";if(a.matchMedia&&a.matchMedia("all").addListener)return!1;var b=a.matchMedia,c=b("only all").matches,d=!1,e=0,f=[],g=function(){a.clearTimeout(e),e=a.setTimeout(function(){for(var c=0,d=f.length;d>c;c++){var e=f[c].mql,g=f[c].listeners||[],h=b(e.media).matches;if(h!==e.matches){e.matches=h;for(var i=0,j=g.length;j>i;i++)g[i].call(a,e)}}},30)};a.matchMedia=function(e){var h=b(e),i=[],j=0;return h.addListener=function(b){c&&(d||(d=!0,a.addEventListener("resize",g,!0)),0===j&&(j=f.push({mql:h,listeners:i})),i.push(b))},h.removeListener=function(a){for(var b=0,c=i.length;c>b;b++)i[b]===a&&i.splice(b,1)},h}}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b #mq-test-1 { width: 42px; }',d.insertBefore(f,e),c=42===g.offsetWidth,d.removeChild(f),{matches:c,media:a}}}(a.document)}(this),function(a){"use strict";if(a.matchMedia&&a.matchMedia("all").addListener)return!1;var b=a.matchMedia,c=b("only all").matches,d=!1,e=0,f=[],g=function(c){a.clearTimeout(e),e=a.setTimeout(function(){for(var c=0,d=f.length;d>c;c++){var e=f[c].mql,g=f[c].listeners||[],h=b(e.media).matches;if(h!==e.matches){e.matches=h;for(var i=0,j=g.length;j>i;i++)g[i].call(a,e)}}},30)};a.matchMedia=function(e){var h=b(e),i=[],j=0;return h.addListener=function(b){c&&(d||(d=!0,a.addEventListener("resize",g,!0)),0===j&&(j=f.push({mql:h,listeners:i})),i.push(b))},h.removeListener=function(a){for(var b=0,c=i.length;c>b;b++)i[b]===a&&i.splice(b,1)},h}}(this),function(a){"use strict";function b(){y(!0)}a.RESPOND_REPLACE_STYLES=a.RESPOND_REPLACE_STYLES||!1;var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{(([^\{\}]*\{[^\}\{]*\})+)[^\}]*\}/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)\}$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q={},r=30,s=k.getElementsByTagName("head")[0]||l,t=k.getElementsByTagName("base")[0],u=s.getElementsByTagName("link"),v=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},w=function(a,b,c){var d="clientWidth",e=l[d],f="CSS1Compat"===k.compatMode&&e||k.body[d]||e,g=null===b,h=null===c,i="em";return b&&(b=parseFloat(b)*(b.indexOf(i)>-1?j||v():1)),c&&(c=parseFloat(c)*(c.indexOf(i)>-1?j||v():1)),!a||(!g||!h)&&(g||f>=b)&&(h||c>=f)},x=function(a,b,c,d){return a.substring(0,c)+b+a.substring(d)},y=function(b){var c,d=(new Date).getTime();return c=a.RESPOND_REPLACE_STYLES?A:B,b&&h&&r>d-h?(a.clearTimeout(i),void(i=a.setTimeout(c,r))):(h=d,void c())},z=function(){for(var a in o)o.hasOwnProperty(a)&&o[a]&&o[a].parentNode===s&&s.removeChild(o[a]);o.length=0},A=function(){u[u.length-1];z();for(var a in p)if(p.hasOwnProperty(a)){var b,c,d,e=p[a],f=e.styles,g=e.sheet,h=f,i={},j=[],k={};for(var l in e.mediastyles)e.mediastyles.hasOwnProperty(l)&&(b=e.mediastyles[l],c=b.minw,d=b.maxw,"all"===b.media?j.push(b):w(b.hasquery,c,d)&&(i[b.media]||(i[b.media]=[]),i[b.media].push(n[b.rules])));for(var m=j.length-1;m>=0;m--){b=j[m],c=b.minw,d=b.maxw;var o=n[b.rules],q=b.replaceIndexStart,r=b.replaceIndexEnd,t="";k[o]||(w(b.hasquery,c,d)&&(t=o),h=x(h,t,q,r),k[o]=!0)}C(h,"all",e.insertBefore),null!==g.parentElement&&s.removeChild(g);for(var v in i)i.hasOwnProperty(v)&&C(i[v].join("\n"),"all",e.insertBefore)}},B=function(){var a={},b=u[u.length-1];for(var c in m)if(m.hasOwnProperty(c)){var d=m[c],e=d.minw,f=d.maxw;w(d.hasquery,e,f)&&(a[d.media]||(a[d.media]=[]),a[d.media].push(n[d.rules]))}z();for(var g in a)a.hasOwnProperty(g)&&C(a[g].join("\n"),g,b.nextSibling)},C=function(a,b,c){var d=k.createElement("style");d.type="text/css",d.media=b,s.insertBefore(d,c),d.styleSheet?d.styleSheet.cssText=a:d.appendChild(k.createTextNode(a)),o.push(d)},D=function(a,b){return b=b.substring(0,b.lastIndexOf("/")),b.length&&(b+="/"),a.replace(c.regex.urls,"$1"+b+"$2$3")},E=function(b,d,e){a.RESPOND_REPLACE_STYLES&&(b=D(b,d),p[d].styles=b,p[d].mediastyles=[]);var f=b.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),h=f&&f.length||0,i=!h&&e;i&&(h=1);for(var j=0;h>j;j++){var k,l,o,q,r;i?(k=e,r=b):(k=f[j].match(c.regex.findStyles)&&RegExp.$1,r=RegExp.$2),a.RESPOND_REPLACE_STYLES?n.push(r):n.push(r&&D(r,d)),o=k.split(","),q=o.length;for(var s=0;q>s;s++)if(l=o[s],!g(l)){var t={media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")};a.RESPOND_REPLACE_STYLES?(t.replaceIndexStart=p[d].styles.indexOf(f[j]),t.replaceIndexEnd=t.replaceIndexStart+f[j].length,p[d].mediastyles.push(t)):m.push(t)}}y()},F=function(){if(d.length){var b=d.shift();f(b.href,function(c){a.RESPOND_REPLACE_STYLES&&(p[b.href]={sheet:b.sheet,insertBefore:b.sheet.nextSibling,styles:c}),E(c,b.href,b.media),q[b.href]=!0,a.setTimeout(function(){F()},0)})}},G=function(){for(var b=0;b -1 ? eminpx || getEmValue() : 1);
+ }
+ if (!!max) {
+ max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ }
+ return !hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max);
+ }, replaceStringBetween = function(source, replacement, start, end) {
+ return source.substring(0, start) + replacement + source.substring(end);
}, applyMedia = function(fromResize) {
- 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();
+ var method, now = new Date().getTime();
+ if (w.RESPOND_REPLACE_STYLES) {
+ method = applyMediaReplace;
+ } else {
+ method = applyMediaAppend;
+ }
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
w.clearTimeout(resizeDefer);
- resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
+ resizeDefer = w.setTimeout(method, resizeThrottle);
return;
} else {
lastCall = now;
}
- for (var i in mediastyles) {
- if (mediastyles.hasOwnProperty(i)) {
- var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
- if (!!min) {
- min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ method();
+ }, removeAppendEls = function() {
+ for (var j in appendedEls) {
+ if (appendedEls.hasOwnProperty(j)) {
+ if (appendedEls[j] && appendedEls[j].parentNode === head) {
+ head.removeChild(appendedEls[j]);
+ }
+ }
+ }
+ appendedEls.length = 0;
+ }, applyMediaReplace = function() {
+ var lastLink = links[links.length - 1];
+ removeAppendEls();
+ for (var l in storedSheets) {
+ if (storedSheets.hasOwnProperty(l)) {
+ var stored = storedSheets[l], styles = stored.styles, sheet = stored.sheet, css = styles, styleBlocks = {}, styleBlocksAll = [], alreadyReplaced = {}, thisstyle, min, max;
+ for (var m in stored.mediastyles) {
+ if (stored.mediastyles.hasOwnProperty(m)) {
+ thisstyle = stored.mediastyles[m];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+ if (thisstyle.media === "all") {
+ styleBlocksAll.push(thisstyle);
+ } else if (isRuleActive(thisstyle.hasquery, min, max)) {
+ if (!styleBlocks[thisstyle.media]) {
+ styleBlocks[thisstyle.media] = [];
+ }
+ styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
+ }
+ }
+ }
+ for (var n = styleBlocksAll.length - 1; n >= 0; n--) {
+ thisstyle = styleBlocksAll[n];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+ var rule = rules[thisstyle.rules], start = thisstyle.replaceIndexStart, end = thisstyle.replaceIndexEnd, replacement = "";
+ if (alreadyReplaced[rule]) {
+ continue;
+ }
+ if (isRuleActive(thisstyle.hasquery, min, max)) {
+ replacement = rule;
+ }
+ css = replaceStringBetween(css, replacement, start, end);
+ alreadyReplaced[rule] = true;
}
- if (!!max) {
- max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ insertCss(css, "all", stored.insertBefore);
+ if (sheet.parentElement !== null) {
+ head.removeChild(sheet);
}
- if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
- if (!styleBlocks[thisstyle.media]) {
- styleBlocks[thisstyle.media] = [];
+ for (var o in styleBlocks) {
+ if (styleBlocks.hasOwnProperty(o)) {
+ insertCss(styleBlocks[o].join("\n"), "all", stored.insertBefore);
}
- styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
- for (var j in appendedEls) {
- if (appendedEls.hasOwnProperty(j)) {
- if (appendedEls[j] && appendedEls[j].parentNode === head) {
- head.removeChild(appendedEls[j]);
+ }, applyMediaAppend = function() {
+ var styleBlocks = {}, lastLink = links[links.length - 1];
+ for (var i in mediastyles) {
+ if (mediastyles.hasOwnProperty(i)) {
+ var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw;
+ if (isRuleActive(thisstyle.hasquery, min, max)) {
+ if (!styleBlocks[thisstyle.media]) {
+ styleBlocks[thisstyle.media] = [];
+ }
+ styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
- appendedEls.length = 0;
+ removeAppendEls();
for (var k in styleBlocks) {
if (styleBlocks.hasOwnProperty(k)) {
- var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
- ss.type = "text/css";
- ss.media = k;
- head.insertBefore(ss, lastLink.nextSibling);
- if (ss.styleSheet) {
- ss.styleSheet.cssText = css;
- } else {
- ss.appendChild(doc.createTextNode(css));
- }
- appendedEls.push(ss);
+ insertCss(styleBlocks[k].join("\n"), k, lastLink.nextSibling);
}
}
- }, translate = function(styles, href, media) {
- var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
+ }, insertCss = function(css, media, insertBefore) {
+ var ss = doc.createElement("style");
+ ss.type = "text/css";
+ ss.media = media;
+ head.insertBefore(ss, insertBefore);
+ if (ss.styleSheet) {
+ ss.styleSheet.cssText = css;
+ } else {
+ ss.appendChild(doc.createTextNode(css));
+ }
+ appendedEls.push(ss);
+ }, replaceUrls = function(styles, href) {
href = href.substring(0, href.lastIndexOf("/"));
- var repUrls = function(css) {
- return css.replace(respond.regex.urls, "$1" + href + "$2$3");
- }, useMedia = !ql && media;
if (href.length) {
href += "/";
}
+ return styles.replace(respond.regex.urls, "$1" + href + "$2$3");
+ }, translate = function(styles, href, media) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ styles = replaceUrls(styles, href);
+ storedSheets[href].styles = styles;
+ storedSheets[href].mediastyles = [];
+ }
+ var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0, useMedia = !ql && media;
if (useMedia) {
ql = 1;
}
for (var i = 0; i < ql; i++) {
- var fullq, thisq, eachq, eql;
+ var fullq, thisq, eachq, eql, rule;
if (useMedia) {
fullq = media;
- rules.push(repUrls(styles));
+ rule = styles;
} else {
fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
- rules.push(RegExp.$2 && repUrls(RegExp.$2));
+ rule = RegExp.$2;
+ }
+ if (!w.RESPOND_REPLACE_STYLES) {
+ rules.push(rule && replaceUrls(rule, href));
+ } else {
+ rules.push(rule);
}
eachq = fullq.split(",");
eql = eachq.length;
@@ -229,13 +302,20 @@
if (isUnsupportedMediaQuery(thisq)) {
continue;
}
- mediastyles.push({
+ var thisstyle = {
media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
rules: rules.length - 1,
hasquery: thisq.indexOf("(") > -1,
minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
- });
+ };
+ if (w.RESPOND_REPLACE_STYLES) {
+ thisstyle.replaceIndexStart = storedSheets[href].styles.indexOf(qs[i]);
+ thisstyle.replaceIndexEnd = thisstyle.replaceIndexStart + qs[i].length;
+ storedSheets[href].mediastyles.push(thisstyle);
+ } else {
+ mediastyles.push(thisstyle);
+ }
}
}
applyMedia();
@@ -243,6 +323,13 @@
if (requestQueue.length) {
var thisRequest = requestQueue.shift();
ajax(thisRequest.href, function(styles) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ storedSheets[thisRequest.href] = {
+ sheet: thisRequest.sheet,
+ insertBefore: thisRequest.sheet.nextSibling,
+ styles: styles
+ };
+ }
translate(styles, thisRequest.href, thisRequest.media);
parsedSheets[thisRequest.href] = true;
w.setTimeout(function() {
@@ -255,6 +342,13 @@
var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
if (!!href && isCSS && !parsedSheets[href]) {
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ storedSheets[href] = {
+ sheet: sheet,
+ insertBefore: sheet.nextSibling,
+ styles: sheet.styleSheet.rawCssText
+ };
+ }
translate(sheet.styleSheet.rawCssText, href, media);
parsedSheets[href] = true;
} else {
@@ -263,6 +357,7 @@
href = w.location.protocol + href;
}
requestQueue.push({
+ sheet: sheet,
href: href,
media: media
});
diff --git a/dest/respond.min.js b/dest/respond.min.js
index e8d6207f..5c897c1e 100644
--- a/dest/respond.min.js
+++ b/dest/respond.min.js
@@ -1,6 +1,6 @@
/*! Respond.js v1.4.2: min/max-width media query polyfill
- * Copyright 2014 Scott Jehl
+ * Copyright 2015 Scott Jehl
* Licensed under MIT
* http://j.mp/respondjs */
-!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b #mq-test-1 { width: 42px; }',d.insertBefore(f,e),c=42===g.offsetWidth,d.removeChild(f),{matches:c,media:a}}}(a.document)}(this),function(a){"use strict";function b(){y(!0)}a.RESPOND_REPLACE_STYLES=a.RESPOND_REPLACE_STYLES||!1;var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{(([^\{\}]*\{[^\}\{]*\})+)[^\}]*\}/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)\}$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q={},r=30,s=k.getElementsByTagName("head")[0]||l,t=k.getElementsByTagName("base")[0],u=s.getElementsByTagName("link"),v=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},w=function(a,b,c){var d="clientWidth",e=l[d],f="CSS1Compat"===k.compatMode&&e||k.body[d]||e,g=null===b,h=null===c,i="em";return b&&(b=parseFloat(b)*(b.indexOf(i)>-1?j||v():1)),c&&(c=parseFloat(c)*(c.indexOf(i)>-1?j||v():1)),!a||(!g||!h)&&(g||f>=b)&&(h||c>=f)},x=function(a,b,c,d){return a.substring(0,c)+b+a.substring(d)},y=function(b){var c,d=(new Date).getTime();return c=a.RESPOND_REPLACE_STYLES?A:B,b&&h&&r>d-h?(a.clearTimeout(i),void(i=a.setTimeout(c,r))):(h=d,void c())},z=function(){for(var a in o)o.hasOwnProperty(a)&&o[a]&&o[a].parentNode===s&&s.removeChild(o[a]);o.length=0},A=function(){u[u.length-1];z();for(var a in p)if(p.hasOwnProperty(a)){var b,c,d,e=p[a],f=e.styles,g=e.sheet,h=f,i={},j=[],k={};for(var l in e.mediastyles)e.mediastyles.hasOwnProperty(l)&&(b=e.mediastyles[l],c=b.minw,d=b.maxw,"all"===b.media?j.push(b):w(b.hasquery,c,d)&&(i[b.media]||(i[b.media]=[]),i[b.media].push(n[b.rules])));for(var m=j.length-1;m>=0;m--){b=j[m],c=b.minw,d=b.maxw;var o=n[b.rules],q=b.replaceIndexStart,r=b.replaceIndexEnd,t="";k[o]||(w(b.hasquery,c,d)&&(t=o),h=x(h,t,q,r),k[o]=!0)}C(h,"all",e.insertBefore),null!==g.parentElement&&s.removeChild(g);for(var v in i)i.hasOwnProperty(v)&&C(i[v].join("\n"),"all",e.insertBefore)}},B=function(){var a={},b=u[u.length-1];for(var c in m)if(m.hasOwnProperty(c)){var d=m[c],e=d.minw,f=d.maxw;w(d.hasquery,e,f)&&(a[d.media]||(a[d.media]=[]),a[d.media].push(n[d.rules]))}z();for(var g in a)a.hasOwnProperty(g)&&C(a[g].join("\n"),g,b.nextSibling)},C=function(a,b,c){var d=k.createElement("style");d.type="text/css",d.media=b,s.insertBefore(d,c),d.styleSheet?d.styleSheet.cssText=a:d.appendChild(k.createTextNode(a)),o.push(d)},D=function(a,b){return b=b.substring(0,b.lastIndexOf("/")),b.length&&(b+="/"),a.replace(c.regex.urls,"$1"+b+"$2$3")},E=function(b,d,e){a.RESPOND_REPLACE_STYLES&&(b=D(b,d),p[d].styles=b,p[d].mediastyles=[]);var f=b.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),h=f&&f.length||0,i=!h&&e;i&&(h=1);for(var j=0;h>j;j++){var k,l,o,q,r;i?(k=e,r=b):(k=f[j].match(c.regex.findStyles)&&RegExp.$1,r=RegExp.$2),a.RESPOND_REPLACE_STYLES?n.push(r):n.push(r&&D(r,d)),o=k.split(","),q=o.length;for(var s=0;q>s;s++)if(l=o[s],!g(l)){var t={media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")};a.RESPOND_REPLACE_STYLES?(t.replaceIndexStart=p[d].styles.indexOf(f[j]),t.replaceIndexEnd=t.replaceIndexStart+f[j].length,p[d].mediastyles.push(t)):m.push(t)}}y()},F=function(){if(d.length){var b=d.shift();f(b.href,function(c){a.RESPOND_REPLACE_STYLES&&(p[b.href]={sheet:b.sheet,insertBefore:b.sheet.nextSibling,styles:c}),E(c,b.href,b.media),q[b.href]=!0,a.setTimeout(function(){F()},0)})}},G=function(){for(var b=0;b -1 ? eminpx || getEmValue() : 1);
+ }
+ if (!!max) {
+ max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ }
+ return !hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max);
+ }, replaceStringBetween = function(source, replacement, start, end) {
+ return source.substring(0, start) + replacement + source.substring(end);
}, applyMedia = function(fromResize) {
- 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();
+ var method, now = new Date().getTime();
+ if (w.RESPOND_REPLACE_STYLES) {
+ method = applyMediaReplace;
+ } else {
+ method = applyMediaAppend;
+ }
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
w.clearTimeout(resizeDefer);
- resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
+ resizeDefer = w.setTimeout(method, resizeThrottle);
return;
} else {
lastCall = now;
}
- for (var i in mediastyles) {
- if (mediastyles.hasOwnProperty(i)) {
- var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
- if (!!min) {
- min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ method();
+ }, removeAppendEls = function() {
+ for (var j in appendedEls) {
+ if (appendedEls.hasOwnProperty(j)) {
+ if (appendedEls[j] && appendedEls[j].parentNode === head) {
+ head.removeChild(appendedEls[j]);
}
- if (!!max) {
- max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ }
+ }
+ appendedEls.length = 0;
+ }, applyMediaReplace = function() {
+ var lastLink = links[links.length - 1];
+ removeAppendEls();
+ for (var l in storedSheets) {
+ if (storedSheets.hasOwnProperty(l)) {
+ var stored = storedSheets[l], styles = stored.styles, sheet = stored.sheet, css = styles, styleBlocks = {}, styleBlocksAll = [], alreadyReplaced = {}, thisstyle, min, max;
+ for (var m in stored.mediastyles) {
+ if (stored.mediastyles.hasOwnProperty(m)) {
+ thisstyle = stored.mediastyles[m];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+ if (thisstyle.media === "all") {
+ styleBlocksAll.push(thisstyle);
+ } else if (isRuleActive(thisstyle.hasquery, min, max)) {
+ if (!styleBlocks[thisstyle.media]) {
+ styleBlocks[thisstyle.media] = [];
+ }
+ styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
+ }
+ }
}
- if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
- if (!styleBlocks[thisstyle.media]) {
- styleBlocks[thisstyle.media] = [];
+ for (var n = styleBlocksAll.length - 1; n >= 0; n--) {
+ thisstyle = styleBlocksAll[n];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+ var rule = rules[thisstyle.rules], start = thisstyle.replaceIndexStart, end = thisstyle.replaceIndexEnd, replacement = "";
+ if (alreadyReplaced[rule]) {
+ continue;
+ }
+ if (isRuleActive(thisstyle.hasquery, min, max)) {
+ replacement = rule;
+ }
+ css = replaceStringBetween(css, replacement, start, end);
+ alreadyReplaced[rule] = true;
+ }
+ insertCss(css, "all", stored.insertBefore);
+ if (sheet.parentElement !== null) {
+ head.removeChild(sheet);
+ }
+ for (var o in styleBlocks) {
+ if (styleBlocks.hasOwnProperty(o)) {
+ insertCss(styleBlocks[o].join("\n"), "all", stored.insertBefore);
}
- styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
- for (var j in appendedEls) {
- if (appendedEls.hasOwnProperty(j)) {
- if (appendedEls[j] && appendedEls[j].parentNode === head) {
- head.removeChild(appendedEls[j]);
+ }, applyMediaAppend = function() {
+ var styleBlocks = {}, lastLink = links[links.length - 1];
+ for (var i in mediastyles) {
+ if (mediastyles.hasOwnProperty(i)) {
+ var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw;
+ if (isRuleActive(thisstyle.hasquery, min, max)) {
+ if (!styleBlocks[thisstyle.media]) {
+ styleBlocks[thisstyle.media] = [];
+ }
+ styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
- appendedEls.length = 0;
+ removeAppendEls();
for (var k in styleBlocks) {
if (styleBlocks.hasOwnProperty(k)) {
- var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
- ss.type = "text/css";
- ss.media = k;
- head.insertBefore(ss, lastLink.nextSibling);
- if (ss.styleSheet) {
- ss.styleSheet.cssText = css;
- } else {
- ss.appendChild(doc.createTextNode(css));
- }
- appendedEls.push(ss);
+ insertCss(styleBlocks[k].join("\n"), k, lastLink.nextSibling);
}
}
- }, translate = function(styles, href, media) {
- var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
+ }, insertCss = function(css, media, insertBefore) {
+ var ss = doc.createElement("style");
+ ss.type = "text/css";
+ ss.media = media;
+ head.insertBefore(ss, insertBefore);
+ if (ss.styleSheet) {
+ ss.styleSheet.cssText = css;
+ } else {
+ ss.appendChild(doc.createTextNode(css));
+ }
+ appendedEls.push(ss);
+ }, replaceUrls = function(styles, href) {
href = href.substring(0, href.lastIndexOf("/"));
- var repUrls = function(css) {
- return css.replace(respond.regex.urls, "$1" + href + "$2$3");
- }, useMedia = !ql && media;
if (href.length) {
href += "/";
}
+ return styles.replace(respond.regex.urls, "$1" + href + "$2$3");
+ }, translate = function(styles, href, media) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ styles = replaceUrls(styles, href);
+ storedSheets[href].styles = styles;
+ storedSheets[href].mediastyles = [];
+ }
+ var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0, useMedia = !ql && media;
if (useMedia) {
ql = 1;
}
for (var i = 0; i < ql; i++) {
- var fullq, thisq, eachq, eql;
+ var fullq, thisq, eachq, eql, rule;
if (useMedia) {
fullq = media;
- rules.push(repUrls(styles));
+ rule = styles;
} else {
fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
- rules.push(RegExp.$2 && repUrls(RegExp.$2));
+ rule = RegExp.$2;
+ }
+ if (!w.RESPOND_REPLACE_STYLES) {
+ rules.push(rule && replaceUrls(rule, href));
+ } else {
+ rules.push(rule);
}
eachq = fullq.split(",");
eql = eachq.length;
@@ -180,13 +253,20 @@
if (isUnsupportedMediaQuery(thisq)) {
continue;
}
- mediastyles.push({
+ var thisstyle = {
media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
rules: rules.length - 1,
hasquery: thisq.indexOf("(") > -1,
minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
- });
+ };
+ if (w.RESPOND_REPLACE_STYLES) {
+ thisstyle.replaceIndexStart = storedSheets[href].styles.indexOf(qs[i]);
+ thisstyle.replaceIndexEnd = thisstyle.replaceIndexStart + qs[i].length;
+ storedSheets[href].mediastyles.push(thisstyle);
+ } else {
+ mediastyles.push(thisstyle);
+ }
}
}
applyMedia();
@@ -194,6 +274,13 @@
if (requestQueue.length) {
var thisRequest = requestQueue.shift();
ajax(thisRequest.href, function(styles) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ storedSheets[thisRequest.href] = {
+ sheet: thisRequest.sheet,
+ insertBefore: thisRequest.sheet.nextSibling,
+ styles: styles
+ };
+ }
translate(styles, thisRequest.href, thisRequest.media);
parsedSheets[thisRequest.href] = true;
w.setTimeout(function() {
@@ -206,6 +293,13 @@
var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
if (!!href && isCSS && !parsedSheets[href]) {
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
+ if (w.RESPOND_REPLACE_STYLES) {
+ storedSheets[href] = {
+ sheet: sheet,
+ insertBefore: sheet.nextSibling,
+ styles: sheet.styleSheet.rawCssText
+ };
+ }
translate(sheet.styleSheet.rawCssText, href, media);
parsedSheets[href] = true;
} else {
@@ -214,6 +308,7 @@
href = w.location.protocol + href;
}
requestQueue.push({
+ sheet: sheet,
href: href,
media: media
});
diff --git a/src/respond.js b/src/respond.js
index 58883e4b..d7989559 100644
--- a/src/respond.js
+++ b/src/respond.js
@@ -3,6 +3,9 @@
"use strict";
+ //when set to true, linked stylesheets will be replaced entirely with style elements for "all" media whilst other media are appended in individual styles, to ensure the cascade is not altered
+ w.RESPOND_REPLACE_STYLES = w.RESPOND_REPLACE_STYLES || false;
+
//exposed namespace
var respond = {};
w.respond = respond;
@@ -52,11 +55,11 @@
respond.queue = requestQueue;
respond.unsupportedmq = isUnsupportedMediaQuery;
respond.regex = {
- media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
+ media: /@media[^\{]+\{(([^\{\}]*\{[^\}\{]*\})+)[^\}]*\}/gi,
keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,
urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
- findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
+ findStyles: /@media *([^\{]+)\{([\S\s]+?)\}$/,
only: /(only\s+)?([a-zA-Z]+)\s?/,
minw: /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
maxw: /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
@@ -78,6 +81,7 @@
mediastyles = [],
rules = [],
appendedEls = [],
+ storedSheets = {},
parsedSheets = {},
resizeThrottle = 30,
head = doc.getElementsByTagName( "head" )[0] || docElem,
@@ -139,43 +143,154 @@
return ret;
},
- //enable/disable styles
- applyMedia = function( fromResize ){
+ isRuleActive = function( hasquery, min, max ){
var name = "clientWidth",
docElemProp = docElem[ name ],
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
- styleBlocks = {},
- lastLink = links[ links.length-1 ],
+ minnull = min === null,
+ maxnull = max === null,
+ em = "em";
+
+ if( !!min ){
+ min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ }
+ if( !!max ){
+ max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ }
+
+ // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
+ return !hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max );
+ },
+
+ replaceStringBetween = function( source, replacement, start, end ){
+ //replace the content between a start and end index
+ return source.substring( 0, start ) + replacement + source.substring( end );
+ },
+
+ applyMedia = function( fromResize ){
+ var method,
now = (new Date()).getTime();
+ if( w.RESPOND_REPLACE_STYLES ){
+ method = applyMediaReplace;
+ }
+ else{
+ method = applyMediaAppend;
+ }
+
//throttle resize calls
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
w.clearTimeout( resizeDefer );
- resizeDefer = w.setTimeout( applyMedia, resizeThrottle );
+ resizeDefer = w.setTimeout( method, resizeThrottle );
return;
}
else {
lastCall = now;
}
+ method();
+ },
+
+ removeAppendEls = function(){
+ //remove any existing respond style element(s)
+ for( var j in appendedEls ){
+ if( appendedEls.hasOwnProperty( j ) ){
+ if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
+ head.removeChild( appendedEls[ j ] );
+ }
+ }
+ }
+ appendedEls.length = 0;
+ },
+
+ applyMediaReplace = function(){
+ var lastLink = links[ links.length-1 ];
+
+ removeAppendEls();
+
+ //inject active styles, replacing current stylesheet
+ for( var l in storedSheets ){
+ if( storedSheets.hasOwnProperty( l ) ){
+ var stored = storedSheets[ l ],
+ styles = stored.styles,
+ sheet = stored.sheet,
+ css = styles,
+ styleBlocks = {},
+ styleBlocksAll = [],
+ alreadyReplaced = {},
+ thisstyle, min, max;
+
+ for( var m in stored.mediastyles ){
+ if( stored.mediastyles.hasOwnProperty( m ) ){
+ thisstyle = stored.mediastyles[ m ];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+
+ if( thisstyle.media === "all" ){
+ styleBlocksAll.push(thisstyle);
+ }
+ else if( isRuleActive( thisstyle.hasquery, min, max ) ){
+ //group by media type
+ if( !styleBlocks[ thisstyle.media ] ){
+ styleBlocks[ thisstyle.media ] = [];
+ }
+ styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
+ }
+ }
+ }
+
+ //replace active rules with @media stripped and remove inactive rules, in reverse order so replace index won't change
+ for( var n = styleBlocksAll.length - 1; n >= 0; n-- ){
+ thisstyle = styleBlocksAll[ n ];
+ min = thisstyle.minw;
+ max = thisstyle.maxw;
+ var rule = rules[ thisstyle.rules ],
+ start = thisstyle.replaceIndexStart,
+ end = thisstyle.replaceIndexEnd,
+ replacement = '';
+
+ if( alreadyReplaced[ rule ] ){
+ //this rule has already been applied for "all" media, we don't need to add it again for the other media queries it is under
+ continue;
+ }
+
+ if( isRuleActive( thisstyle.hasquery, min, max ) ){
+ replacement = rule;
+ }
+
+ css = replaceStringBetween( css, replacement, start, end );
+ alreadyReplaced[ rule ] = true;
+ }
+
+ insertCss( css, "all", stored.insertBefore );
+
+ //remove original stylesheet
+ if( sheet.parentElement !== null ){
+ head.removeChild( sheet );
+ }
+
+ //inject active styles, grouped by media type
+ for( var o in styleBlocks ){
+ if( styleBlocks.hasOwnProperty( o ) ){
+ insertCss( styleBlocks[ o ].join( "\n" ), "all", stored.insertBefore );
+ }
+ }
+ }
+ }
+ },
+
+ //enable/disable styles
+ applyMediaAppend = function(){
+ var styleBlocks = {},
+ lastLink = links[ links.length-1 ];
+
for( var i in mediastyles ){
if( mediastyles.hasOwnProperty( i ) ){
var thisstyle = mediastyles[ i ],
min = thisstyle.minw,
- max = thisstyle.maxw,
- minnull = min === null,
- maxnull = max === null,
- em = "em";
+ max = thisstyle.maxw;
- if( !!min ){
- min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
- }
- if( !!max ){
- max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
- }
-
- // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
- if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
+ if( isRuleActive( thisstyle.hasquery, min, max ) ){
if( !styleBlocks[ thisstyle.media ] ){
styleBlocks[ thisstyle.media ] = [];
}
@@ -184,59 +299,61 @@
}
}
- //remove any existing respond style element(s)
- for( var j in appendedEls ){
- if( appendedEls.hasOwnProperty( j ) ){
- if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
- head.removeChild( appendedEls[ j ] );
- }
- }
- }
- appendedEls.length = 0;
+ removeAppendEls();
//inject active styles, grouped by media type
for( var k in styleBlocks ){
if( styleBlocks.hasOwnProperty( k ) ){
- var ss = doc.createElement( "style" ),
- css = styleBlocks[ k ].join( "\n" );
+ insertCss( styleBlocks[ k ].join( "\n" ), k, lastLink.nextSibling );
+ }
+ }
+ },
- ss.type = "text/css";
- ss.media = k;
+ insertCss = function( css, media, insertBefore ){
+ var ss = doc.createElement( "style" );
- //originally, ss was appended to a documentFragment and sheets were appended in bulk.
- //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
- head.insertBefore( ss, lastLink.nextSibling );
+ ss.type = "text/css";
+ ss.media = media;
- if ( ss.styleSheet ){
- ss.styleSheet.cssText = css;
- }
- else {
- ss.appendChild( doc.createTextNode( css ) );
- }
+ //originally, ss was appended to a documentFragment and sheets were appended in bulk.
+ //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
+ head.insertBefore( ss, insertBefore );
- //push to appendedEls to track for later removal
- appendedEls.push( ss );
- }
+ if ( ss.styleSheet ){
+ ss.styleSheet.cssText = css;
+ }
+ else {
+ ss.appendChild( doc.createTextNode( css ) );
}
+
+ //push to appendedEls to track for later removal
+ appendedEls.push( ss );
},
- //find media blocks in css text, convert to style blocks
- translate = function( styles, href, media ){
- var qs = styles.replace( respond.regex.comments, '' )
- .replace( respond.regex.keyframes, '' )
- .match( respond.regex.media ),
- ql = qs && qs.length || 0;
+ replaceUrls = function( styles, href ){
//try to get CSS path
href = href.substring( 0, href.lastIndexOf( "/" ) );
- var repUrls = function( css ){
- return css.replace( respond.regex.urls, "$1" + href + "$2$3" );
- },
- useMedia = !ql && media;
-
//if path exists, tack on trailing slash
if( href.length ){ href += "/"; }
+ return styles.replace( respond.regex.urls, "$1" + href + "$2$3" );
+ },
+
+ //find media blocks in css text, convert to style blocks
+ translate = function( styles, href, media ){
+ if( w.RESPOND_REPLACE_STYLES ){
+ styles = replaceUrls( styles, href );
+ storedSheets[ href ].styles = styles;
+ storedSheets[ href ].mediastyles = [];
+ }
+
+ var qs = styles.replace( respond.regex.comments, '' )
+ .replace( respond.regex.keyframes, '' )
+ .match( respond.regex.media ),
+ ql = qs && qs.length || 0,
+ useMedia = !ql && media;
+
//if no internal queries exist, but media attr does, use that
//note: this currently lacks support for situations where a media attr is specified on a link AND
//its associated stylesheet has internal CSS media queries.
@@ -246,17 +363,24 @@
}
for( var i = 0; i < ql; i++ ){
- var fullq, thisq, eachq, eql;
+ var fullq, thisq, eachq, eql, rule;
//media attr
if( useMedia ){
fullq = media;
- rules.push( repUrls( styles ) );
+ rule = styles;
}
//parse for styles
else{
fullq = qs[ i ].match( respond.regex.findStyles ) && RegExp.$1;
- rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
+ rule = RegExp.$2;
+ }
+
+ if( !w.RESPOND_REPLACE_STYLES ){
+ rules.push( rule && replaceUrls( rule, href ) );
+ }
+ else {
+ rules.push( rule );
}
eachq = fullq.split( "," );
@@ -269,13 +393,21 @@
continue;
}
- mediastyles.push( {
+ var thisstyle = {
media : thisq.split( "(" )[ 0 ].match( respond.regex.only ) && RegExp.$2 || "all",
rules : rules.length - 1,
hasquery : thisq.indexOf("(") > -1,
minw : thisq.match( respond.regex.minw ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
maxw : thisq.match( respond.regex.maxw ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
- } );
+ };
+ if( w.RESPOND_REPLACE_STYLES ){
+ thisstyle.replaceIndexStart = storedSheets[ href ].styles.indexOf( qs[ i ] );
+ thisstyle.replaceIndexEnd = thisstyle.replaceIndexStart + qs[ i ].length;
+ storedSheets[ href ].mediastyles.push( thisstyle );
+ }
+ else {
+ mediastyles.push( thisstyle );
+ }
}
}
@@ -288,6 +420,13 @@
var thisRequest = requestQueue.shift();
ajax( thisRequest.href, function( styles ){
+ if( w.RESPOND_REPLACE_STYLES ){
+ storedSheets[ thisRequest.href ] = {
+ sheet: thisRequest.sheet,
+ insertBefore: thisRequest.sheet.nextSibling,
+ styles: styles
+ };
+ }
translate( styles, thisRequest.href, thisRequest.media );
parsedSheets[ thisRequest.href ] = true;
@@ -311,6 +450,13 @@
if( !!href && isCSS && !parsedSheets[ href ] ){
// selectivizr exposes css through the rawCssText expando
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
+ if( w.RESPOND_REPLACE_STYLES ){
+ storedSheets[ href ] = {
+ sheet: sheet,
+ insertBefore: sheet.nextSibling,
+ styles: sheet.styleSheet.rawCssText
+ };
+ }
translate( sheet.styleSheet.rawCssText, href, media );
parsedSheets[ href ] = true;
} else {
@@ -320,6 +466,7 @@
// manually add in the protocol
if ( href.substring(0,2) === "//" ) { href = w.location.protocol + href; }
requestQueue.push( {
+ sheet: sheet,
href: href,
media: media
} );