From 19b021cf1dd4cfbb150bce985e75b427c0fd57de Mon Sep 17 00:00:00 2001 From: Henry Blyth Date: Fri, 27 Nov 2015 15:31:54 +0000 Subject: [PATCH] Allow replacing stylesheet to preserve the cascade Usually this library will append media queries in separate ',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 } );