Skip to content

Instantly share code, notes, and snippets.

@gavinballard
Last active August 29, 2015 14:04
Show Gist options
  • Save gavinballard/e8272673f9e155464151 to your computer and use it in GitHub Desktop.
Save gavinballard/e8272673f9e155464151 to your computer and use it in GitHub Desktop.
Potential selectivizr.js + respond.js combination for Shopify.
/*! Respond.js: min/max-width media query polyfill. Remote proxy (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
(function(win, doc, undefined) {
// Add a modified version of selectivizr.js here. Could remove the methods
// that fetch remote stylesheets (as Respond.js would be doing that for us
// via the proxy method), but expose the code that parses and applies
// patches as a public method - something like Selectivizr.parseStyleSheets().
var docElem = doc.documentElement,
proxyURL = doc.getElementById("respond-proxy").href,
redirectURL = (doc.getElementById("respond-redirect") || location).href,
baseElem = doc.getElementsByTagName("base")[0],
urls = [],
refNode;
function encode(url){
return win.encodeURIComponent(url);
}
function fakejax( url, callback ){
var iframe,
AXO;
// All hail Google http://j.mp/iKMI19
// Behold, an iframe proxy without annoying clicky noises.
if ( "ActiveXObject" in win ) {
AXO = new ActiveXObject( "htmlfile" );
AXO.open();
AXO.write( '<iframe id="x"></iframe>' );
AXO.close();
iframe = AXO.getElementById( "x" );
} else {
iframe = doc.createElement( "iframe" );
iframe.style.cssText = "position:absolute;top:-99em";
docElem.insertBefore(iframe, docElem.firstElementChild || docElem.firstChild );
}
iframe.src = checkBaseURL(proxyURL) + "?url=" + encode(redirectURL) + "&css=" + encode(checkBaseURL(url));
function checkFrameName() {
var cssText;
try {
cssText = iframe.contentWindow.name;
}
catch (e) { }
if (cssText) {
// We've got what we need. Stop the iframe from loading further content.
iframe.src = "about:blank";
iframe.parentNode.removeChild(iframe);
iframe = null;
// Per http://j.mp/kn9EPh, not taking any chances. Flushing the ActiveXObject
if (AXO) {
AXO = null;
if (win.CollectGarbage) {
win.CollectGarbage();
}
}
callback(cssText);
}
else{
win.setTimeout(checkFrameName, 100);
}
}
win.setTimeout(checkFrameName, 500);
}
function checkBaseURL(href) {
if (baseElem && href.indexOf(baseElem.href) === -1) {
bref = (/\/$/).test(baseElem.href) ? baseElem.href : (baseElem.href + "/");
href = bref + href;
}
return href;
}
function checkRedirectURL() {
// IE6 & IE7 don't build out absolute urls in <link /> attributes.
// So respond.proxy.gif remains relative instead of http://example.com/respond.proxy.gif.
// This trickery resolves that issue.
if (~ !redirectURL.indexOf(location.host)) {
var fakeLink = doc.createElement("div");
fakeLink.innerHTML = '<a href="' + redirectURL + '"></a>';
docElem.insertBefore(fakeLink, docElem.firstElementChild || docElem.firstChild );
// Grab the parsed URL from that dummy object
redirectURL = fakeLink.firstChild.href;
// Clean up
fakeLink.parentNode.removeChild(fakeLink);
fakeLink = null;
}
}
function buildUrls(){
var links = doc.getElementsByTagName( "link" );
for( var i = 0, linkl = links.length; i < linkl; i++ ){
var thislink = links[i],
href = links[i].href,
extreg = (/^([a-zA-Z:]*\/\/(www\.)?)/).test( href ),
ext = (baseElem && !extreg) || extreg;
//make sure it's an external stylesheet
if( thislink.rel.indexOf( "stylesheet" ) >= 0 && ext ){
(function( link ){
fakejax( href, function( css ){
// Instead of the line below, you'd have:
// link.styleSheet.rawCssText = Selectivizr.parseStyleSheet(css);
//
// Would have to investigate how Selectivizr handles media queries
// to make sure there aren't any conflicts but I don't think that
// would be an issue.
link.styleSheet.rawCssText = css;
respond.update();
} );
})( thislink );
}
}
}
if( !respond.mediaQueriesSupported ){
checkRedirectURL();
buildUrls();
}
})( window, document );
@gavinballard
Copy link
Author

Hey @cshold, not sure how much time you have to look at this (selectivizr.js + respond.js on Shopify), but
this would be what I'm thinking - basically;

  1. Incorporate a version of Selectivizr.js into the top of the above script (this is the script that drives Respond.js's proxy fetching, stored as respond.liquid if using my Respond.js workaround - see comments added at lines #L4-L7;
  2. Strip out the stuff that's not needed from Selectivizr (such as the code to fetch stylesheets using AJAX, as we'll leave that to Respond.js);
  3. Expose the parseStylesheets() method from Selectivizr to the Respond.js code;
  4. Call that method from within the buildUrls() method of Respond.js when setting the rawCssText property on link.styleSheet (see comments at #L118-123).

I think that would work - Respond.js does the fetching through the proxy as normal, then Selectivizr patches it before Respond.js interprets it.

Thoughts welcome!

@cshold
Copy link

cshold commented Jul 21, 2014

That looks good to me. I don't see anything specific in selectivizr that deals with media queries so that shouldn't be an issue.

Let me know if there is anything I can do to help out or test. As mentioned in my tweet, some of the JS going on in respond and selectivizr are over my head but your flow seems to have things covered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment