Skip to content
This repository

Unit Tests for CDN/Cross-Domain hosted CSS #28

Closed
wants to merge 51 commits into from

5 participants

Richard Herrera Scott Jehl Adam Luikart Rick Davies Chris Jacob
Richard Herrera
Collaborator

Most of the patch below has been integrated, but the unit tests still need to be ported over. For that reason, I'm going to leave this open.

The patch enables downloading CSS from an external domain. It uses an external iframe proxy to perform the required Ajax duties on the external server, then transports the resulting CSS back to the origin domain via the window.name object.

The patch requires access to the external domain, so hotlinking is out of the equation.

Some setup is required, although I tried to keep it as simple as possible:

See test/test-x-domain.html for a demo:

  • Upload x-domain/respond-proxy.html to your external domain
  • Upload x-domain/favicon.ico to your origin domain (Optional)
    • Note: The remote proxy must redirect back to your origin domain after it completes its tasks. If none is set, it defaults to the current page.
    • The advantage to declaring a redirect is speed. Redirecting to favicon.ico is faster than re-loading the current page within the iframe.
  • Reference the file(s) via <link /> element(s):
    <!-- Respond.js proxy on external server -->
    <link href="http://externalcdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
    
    <!-- Respond.js redirect (optional, defaults to current page) -->
    <link href="/path/to/favicon.ico" id="respond-redirect" rel="respond-redirect" />

Feedback is welcome. An alternate solution to the link element(s) would be to define the proxy values inside of Respond.js. However, in the spirit of "minimal setup", I thought it'd be best to keep settable parameters outside the script.

I also kept an eye on file size. After several micro-edits this was the lowest increase I could muster:

Vanilla Respond.js: 3.1K (1.7K gzipped)
XDR'd Respond.js: 3.7K (1.9K gzipped)

The proxy retains cross-browser support, though if that were IE-only the file size could come down a bit. According to caniuse.com, browsers not supporting media queries are pretty much limited to the IE's.

Looking forward to your thoughts.

doctyper added some commits
Richard Herrera doctyper Moving RegExp to accessible variable for later use. defeda4
Richard Herrera doctyper Exposing variables to share between functions. 56ce21f
Richard Herrera doctyper Fallback URL is accessed via <meta name="respond-proxy" /> 8765ea9
Richard Herrera doctyper If proxyURL is defined, add to queue. 560eebd
Richard Herrera doctyper Move to named function for later access. 624820a
Richard Herrera doctyper Exposing semi-private variables (is that a thing?) accessed via ifram…
…e proxy.
b5375de
Richard Herrera doctyper - Branch the ajax function to handle external proxy.
- If URL is external and proxyURL exists, create a dummy iframe (if necessary) and access the proxy.
- Else if internal, proceed as normal.
67f92d5
Richard Herrera doctyper After completion, check for iframe and remove if needed. eca97d8
Richard Herrera doctyper Respond.js proxy. The iframe URL is constructed as follows:
http://cdnexample.com/respond-proxy.html?url=http://originalurl.com/x-domain-end-point.html&css=http://cdnexample.com/example.css

The URL is parsed, CSS file is extracted and stored in window.name. The file then redirects to the correct URL for MQ parsing.
e7a2a59
Richard Herrera doctyper Turns out IE treats two different protocols as same-domain, leading t…
…o a false positive on x-domain. Take two:

- Removing semi-private vars. No longer needed.
fabed6e
Richard Herrera doctyper Using the Apple-style meta syntax to avoid having multiple meta eleme…
…nts for Respond.js. Here I parse out both the proxy file and the end-point redirect.
353a29f
Richard Herrera doctyper The proxyInterval polls the iframe for a change in iframe.contentWind…
…ow.name. Once triggered it parses out the embedded CSS and resumes functionality.

It is wrapped in a try/catch statement due to access warnings.
34d0b0c
Richard Herrera doctyper Send the redirectURL along with the rest of the params. d3f40a6
Richard Herrera doctyper External check no longer needed. cb16091
Richard Herrera doctyper Adding a blank end-point redirect. Required for the iframe/window.nam…
…e hack.
b9e0fca
Richard Herrera doctyper Cross-domain test with Respond.js. e95a7f7
Richard Herrera doctyper Updating README. 96ea514
Richard Herrera doctyper Updating README. e460844
Richard Herrera doctyper Moving proxy files to project root. 0fd2c51
Richard Herrera doctyper Tweaking meta element. 3b6b740
Richard Herrera doctyper Updating README. 8f37fbf
Richard Herrera doctyper Minified response-proxy file. 32b5543
Richard Herrera doctyper Minified respond-proxy file. a758f30
Richard Herrera doctyper Merge branch 'master' of github.com:doctyper/Respond a3beea0
Richard Herrera doctyper Minor whitespace fixes. a063e44
Richard Herrera doctyper Missing semicolon. 67b7341
Richard Herrera doctyper All hail Google http://j.mp/iKMI19
Behold, an iframe proxy without annoying clicky noises.
3a2e324
Richard Herrera doctyper Going against the grain and using an AXO-first approach here. The XML…
…HttpRequest doesn't appear to fire inside an AXO HTMLFile. Since we're now using that approach to resolve UX issues, this method allows XHR to work by testing for AXO objects first.
6af4c5b
Richard Herrera doctyper Simply writing out an iframe seems to work here. Saves bytes. a56327e
Richard Herrera doctyper No need to encode the CSS code for window.name. Saving bytes. dc0afad
Richard Herrera doctyper Adding stricter checks for redirectURL parameter. 5b686dd
Richard Herrera doctyper Shaving bytes. 964c334
Richard Herrera doctyper Not sure it matters, but I'd rather pull as much code outside the try…
…/catch block as possible.
371d089
Richard Herrera doctyper Custom <meta> elements are not part of the HTML5 spec. Switching to <…
…link> elements. Making #respond-redirect an optional parameter (defaults to current page).

Via: http://www.w3.org/TR/html-markup/link.html#link
09292ba
Richard Herrera doctyper Switching to <link> elements for parameter retrieval. redirectURL def…
…aults to current page if none explicitly set.
2abcd4b
Richard Herrera doctyper Fixes bug where existing reference to iframe caused respond.update() …
…to fail.
4ecb98e
Richard Herrera doctyper Safeguard Respond.js from potential infinite-loop (loading the curren…
…t page in an iframe).
7c51756
Richard Herrera doctyper Updating README. c48ac66
Richard Herrera doctyper Updating README. 452585f
Richard Herrera doctyper Updating README. f2263f7
Richard Herrera doctyper Updating README. d94e62b
Richard Herrera doctyper Adding fix for loading stylesheets from multiple domains (My patch on…
…ly supports loading from one declared domain as of yet). Non-matching domains now silently fail.
c5f1847
Richard Herrera doctyper Reusing host check as matchDomain variable. b021d47
Richard Herrera doctyper Storing window.location variable. c013889
Richard Herrera doctyper Test should be against proxyURL variable. 4a5113f
Richard Herrera doctyper Adding comment. 921a6e8
Richard Herrera doctyper Adding x-domain unit test. 08828be
Richard Herrera doctyper Fixes conflict with x-domain test. 0571dba
Richard Herrera doctyper Stop the iframe from loading further content. All we need is its wind…
…ow.name object.
2f5c3c1
Richard Herrera doctyper Updating README. f9b20b5
Richard Herrera doctyper Fixes false positive dealing with CSS load order. Fixes conflict when…
… attempting to load from multiple external domains.
ac20cef
Scott Jehl
Owner

Awesome work, Doctyper! I'll take a look at this asap.

Scott Jehl
Owner

Quick question while I'm reading through this: do you think it'd be worthwhile to instead consider offering an external proxy adapter script that Respond.js can reference locally to make the request on the server side? Basically, if some sort of "parseExternalCSS" option was set to true, and Respond.js encountered a link with an external url, it could just make its normal ajax request to that url with a proxy prefix like "respond.external.php?url=...". That proxy would simply curl that url, prefix any relative asset urls it contains, and echo it out.

Just a thought, as it seems this approach would potentially allow for CDN-hosted CSS, which is a primary concern of those who have requested this feature in the past.

Richard Herrera
Collaborator

Well, my goal was for a back-end-agnostic solution. Going down that route will get pretty branched since you'll need solutions for several languages.

Proxying the call internally also means you're taking on the extra bandwidth, not the CDN.

I don't think this solution necessarily excludes CDN content. As long as the developer has access to the hosted files (presumably), it shouldn't be a problem. Think of the proxy as an incredibly hacky crossdomain.xml.

Adam Luikart

FWIW, it seems like if you have to proxy a CDN request through your own domain, you might as well have just hosted it there to begin with. I'm not sure that a local proxy is a win if your use-case involves a CDN.

Scott Jehl
Owner

Well, the proxy would only be used for IE's ajax request for the CSS to get the media queries. Otherwise, you'd get the benefits of the CDN.

Rick Davies

I have a specific case -- a Shopify theme (Shopify is a Ruby ecommerce app).
To summarize:

I have set up a repo with all of my source files here: https://github.com/rickydazla/Respondify
(my html background-color should change from white (@320px) to other garish colors with screen width.)

Scott's respond script is not working for me, nor this unfortunately. IE is still showing white background from initial CSS.

Input appreciated. Rick

Scott Jehl scottjehl closed this pull request from a commit
scottjehl Added a new external cross-domain proxy script for those who need it.…
… Instructions are included in the README file. Huge, Huge thanks to @doctyper, who crafted the majority of the logic behind this workaround. Fixes #28. Fixes #24.
3500e86
Scott Jehl scottjehl reopened this
Scott Jehl
Owner

@doctyper: Thanks so much for this patch! I've finally gotten around to applying most of this as an external patch that can be used in a addition to respond.js. In doing so, I've modified a good deal of it to make it work without modifying respond itself, and I'd really appreciate any feedback you have on the implementation, as it's just a first pass.

One thing I'm noticing is that it's only working in IE8 currently. Was yours working in 6 and 7? Maybe I missed something...

I also still need to update your unit tests and get them into the suite.

The readme is updated, mostly using your text. :)

Lastly, the latest git snapshot is up here http://scottjehl.github.com/Respond/cross-domain/example.html

So, thanks again!
Scott

Chris Jacob

I haven't dug to deep into the cross domain solution you've implemented just yet... but as soon as I heard the host needed to implement a proxy html file it made me think of this awesome Stackoverflow answer...

Cross Domain: Resizing an iframe based on content
http://stackoverflow.com/questions/153152/resizing-an-iframe-based-on-content/362564#362564

I have implemented it for resizing an iframe ... not sure if it has any use in regard to requesting assets like CSS/Images cross domain; but still thought I would mention it incase it does ^_^

Richard Herrera
Collaborator

@scottjehl Madness. Fixed in #47

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

Showing 51 unique commits by 1 author.

Jun 03, 2011
Richard Herrera doctyper Moving RegExp to accessible variable for later use. defeda4
Richard Herrera doctyper Exposing variables to share between functions. 56ce21f
Richard Herrera doctyper Fallback URL is accessed via <meta name="respond-proxy" /> 8765ea9
Richard Herrera doctyper If proxyURL is defined, add to queue. 560eebd
Richard Herrera doctyper Move to named function for later access. 624820a
Richard Herrera doctyper Exposing semi-private variables (is that a thing?) accessed via ifram…
…e proxy.
b5375de
Richard Herrera doctyper - Branch the ajax function to handle external proxy.
- If URL is external and proxyURL exists, create a dummy iframe (if necessary) and access the proxy.
- Else if internal, proceed as normal.
67f92d5
Richard Herrera doctyper After completion, check for iframe and remove if needed. eca97d8
Richard Herrera doctyper Respond.js proxy. The iframe URL is constructed as follows:
http://cdnexample.com/respond-proxy.html?url=http://originalurl.com/x-domain-end-point.html&css=http://cdnexample.com/example.css

The URL is parsed, CSS file is extracted and stored in window.name. The file then redirects to the correct URL for MQ parsing.
e7a2a59
Richard Herrera doctyper Turns out IE treats two different protocols as same-domain, leading t…
…o a false positive on x-domain. Take two:

- Removing semi-private vars. No longer needed.
fabed6e
Richard Herrera doctyper Using the Apple-style meta syntax to avoid having multiple meta eleme…
…nts for Respond.js. Here I parse out both the proxy file and the end-point redirect.
353a29f
Richard Herrera doctyper The proxyInterval polls the iframe for a change in iframe.contentWind…
…ow.name. Once triggered it parses out the embedded CSS and resumes functionality.

It is wrapped in a try/catch statement due to access warnings.
34d0b0c
Richard Herrera doctyper Send the redirectURL along with the rest of the params. d3f40a6
Richard Herrera doctyper External check no longer needed. cb16091
Richard Herrera doctyper Adding a blank end-point redirect. Required for the iframe/window.nam…
…e hack.
b9e0fca
Richard Herrera doctyper Cross-domain test with Respond.js. e95a7f7
Richard Herrera doctyper Updating README. 96ea514
Richard Herrera doctyper Updating README. e460844
Richard Herrera doctyper Moving proxy files to project root. 0fd2c51
Richard Herrera doctyper Tweaking meta element. 3b6b740
Richard Herrera doctyper Updating README. 8f37fbf
Richard Herrera doctyper Minified response-proxy file. 32b5543
Richard Herrera doctyper Minified respond-proxy file. a758f30
Richard Herrera doctyper Merge branch 'master' of github.com:doctyper/Respond a3beea0
Jun 04, 2011
Richard Herrera doctyper Minor whitespace fixes. a063e44
Richard Herrera doctyper Missing semicolon. 67b7341
Richard Herrera doctyper All hail Google http://j.mp/iKMI19
Behold, an iframe proxy without annoying clicky noises.
3a2e324
Richard Herrera doctyper Going against the grain and using an AXO-first approach here. The XML…
…HttpRequest doesn't appear to fire inside an AXO HTMLFile. Since we're now using that approach to resolve UX issues, this method allows XHR to work by testing for AXO objects first.
6af4c5b
Richard Herrera doctyper Simply writing out an iframe seems to work here. Saves bytes. a56327e
Richard Herrera doctyper No need to encode the CSS code for window.name. Saving bytes. dc0afad
Richard Herrera doctyper Adding stricter checks for redirectURL parameter. 5b686dd
Richard Herrera doctyper Shaving bytes. 964c334
Richard Herrera doctyper Not sure it matters, but I'd rather pull as much code outside the try…
…/catch block as possible.
371d089
Richard Herrera doctyper Custom <meta> elements are not part of the HTML5 spec. Switching to <…
…link> elements. Making #respond-redirect an optional parameter (defaults to current page).

Via: http://www.w3.org/TR/html-markup/link.html#link
09292ba
Richard Herrera doctyper Switching to <link> elements for parameter retrieval. redirectURL def…
…aults to current page if none explicitly set.
2abcd4b
Richard Herrera doctyper Fixes bug where existing reference to iframe caused respond.update() …
…to fail.
4ecb98e
Richard Herrera doctyper Safeguard Respond.js from potential infinite-loop (loading the curren…
…t page in an iframe).
7c51756
Richard Herrera doctyper Updating README. c48ac66
Richard Herrera doctyper Updating README. 452585f
Richard Herrera doctyper Updating README. f2263f7
Richard Herrera doctyper Updating README. d94e62b
Richard Herrera doctyper Adding fix for loading stylesheets from multiple domains (My patch on…
…ly supports loading from one declared domain as of yet). Non-matching domains now silently fail.
c5f1847
Jun 05, 2011
Richard Herrera doctyper Reusing host check as matchDomain variable. b021d47
Richard Herrera doctyper Storing window.location variable. c013889
Richard Herrera doctyper Test should be against proxyURL variable. 4a5113f
Richard Herrera doctyper Adding comment. 921a6e8
Richard Herrera doctyper Adding x-domain unit test. 08828be
Richard Herrera doctyper Fixes conflict with x-domain test. 0571dba
Richard Herrera doctyper Stop the iframe from loading further content. All we need is its wind…
…ow.name object.
2f5c3c1
Richard Herrera doctyper Updating README. f9b20b5
Richard Herrera doctyper Fixes false positive dealing with CSS load order. Fixes conflict when…
… attempting to load from multiple external domains.
ac20cef
This page is out of date. Refresh to see the latest.
23 README.md
Source Rendered
@@ -27,6 +27,26 @@ Usage Instructions
27 27
28 28 # Crack open Internet Explorer and pump fists in delight
29 29
  30 +CDN/X-Domain Setup
  31 +======
  32 +
  33 +Respond.js works by requesting a pristine copy of your CSS via AJAX, so if you host your stylesheets on a CDN (or a subdomain), you'll need to upload a proxy page to enable cross-domain communication.
  34 +
  35 +See `test/test-x-domain.html` for a demo:
  36 +
  37 +- Upload `x-domain/respond-proxy.html` to your external domain
  38 +- Upload `x-domain/favicon.ico` to your origin domain (Optional)
  39 + - Note: The remote proxy must redirect back to your origin domain after it completes its tasks. If none is set, it defaults to the current page.
  40 + - The advantage to declaring a redirect is speed. Redirecting to `favicon.ico` is faster than re-loading the current page within the iframe.
  41 +- Reference the file(s) via `<link />` element(s):
  42 +
  43 +<pre>
  44 + &lt;!-- Respond.js proxy on external server --&gt;
  45 + &lt;link href=&quot;http://externalcdn.com/respond-proxy.html&quot; id=&quot;respond-proxy&quot; rel=&quot;respond-proxy&quot; /&gt;
  46 +
  47 + &lt;!-- Respond.js redirect (optional, defaults to current page) --&gt;
  48 + &lt;link href=&quot;/path/to/favicon.ico&quot; id=&quot;respond-redirect&quot; rel=&quot;respond-redirect&quot; /&gt;
  49 +</pre>
30 50
31 51 Support & Caveats
32 52 ======
@@ -45,9 +65,6 @@ Some notes to keep in mind:
45 65
46 66 - Due to security restrictions, some browsers may not allow this script to work on file:// urls (because it uses xmlHttpRequest). Run it on a web server.
47 67
48   -- Due to its use of Ajax, this script will only work with same-domain CSS files, though I may patch that up soon.
49   -
50   -
51 68 - Currently, media attributes on link elements are supported, but only if the linked stylesheet contains no media queries. If it does contain queries, the media attribute will be ignored and the internal queries will be parsed normally.
52 69
53 70 - WARNING: Do not include @font-face rules inside a media query. This will crash IE7 and IE8. Simply place @font-face rules in the wide open, as a sibling to other media queries. Isolated test here to demostrate (note: test crashes IE 7&8): http://jsfiddle.net/scottjehl/Ejyj5/1/
117 respond.src.js
@@ -15,6 +15,8 @@
15 15 //define vars
16 16 var doc = win.document,
17 17 docElem = doc.documentElement,
  18 + location = win.location,
  19 + host = location.host,
18 20 mediastyles = [],
19 21 rules = [],
20 22 appendedEls = [],
@@ -23,6 +25,13 @@
23 25 head = doc.getElementsByTagName( "head" )[0] || docElem,
24 26 links = head.getElementsByTagName( "link" ),
25 27 requestQueue = [],
  28 + isExtRegExp = /^([a-zA-Z]+?:(\/\/)?(www\.)?)/,
  29 + proxyURL = (doc.getElementById("respond-proxy") || {}).href,
  30 + redirectURL = (doc.getElementById("respond-redirect") || location).href,
  31 + proxyInterval,
  32 + thisRequest,
  33 + iframe,
  34 + AXO,
26 35
27 36 //loop stylesheets, send text content to translate
28 37 ripCSS = function(){
@@ -30,7 +39,8 @@
30 39 sl = sheets.length,
31 40 i = 0,
32 41 //vars for loop:
33   - sheet, href, media, isCSS;
  42 + sheet, href, media, isCSS,
  43 + matchDomain, isProxyable;
34 44
35 45 for( ; i < sl; i++ ){
36 46 sheet = sheets[ i ],
@@ -40,11 +50,13 @@
40 50
41 51 //only links plz and prevent re-parsing
42 52 if( !!href && isCSS && !parsedSheets[ href ] ){
43   - if( !/^([a-zA-Z]+?:(\/\/)?(www\.)?)/.test( href )
44   - || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
  53 + if( !isExtRegExp.test( href )
  54 + || (matchDomain = href.replace( RegExp.$1, "" ).split( "/" )[0]) === host
  55 + || (isProxyable = proxyURL && (win.top === win.self) && ~ proxyURL.indexOf(matchDomain)) ){
45 56 requestQueue.push( {
46 57 href: href,
47   - media: media
  58 + media: media,
  59 + proxy: isProxyable && matchDomain !== host
48 60 } );
49 61 }
50 62 else{
@@ -56,16 +68,38 @@
56 68
57 69 },
58 70
  71 + // Parse CSS Text
  72 + receiveCSSText = function( styles ){
  73 + translate( styles, thisRequest.href, thisRequest.media );
  74 + parsedSheets[ thisRequest.href ] = true;
  75 + makeRequests();
  76 + },
  77 +
59 78 //recurse through request queue, get css text
60 79 makeRequests = function(){
61 80 if( requestQueue.length ){
62   - var thisRequest = requestQueue.shift();
  81 + thisRequest = requestQueue.shift();
  82 +
  83 + ajax( thisRequest.href, thisRequest.proxy, receiveCSSText );
  84 + } else if (iframe) {
  85 +
  86 + // Remove iframe
  87 + iframe.parentNode.removeChild(iframe);
  88 + iframe = null;
  89 +
  90 + // Per http://j.mp/kn9EPh, not taking any chances. Flushing the ActiveXObject
  91 + if (AXO) {
  92 + AXO = null;
  93 +
  94 + if (win.CollectGarbage) {
  95 + win.CollectGarbage();
  96 + }
  97 + }
63 98
64   - ajax( thisRequest.href, function( styles ){
65   - translate( styles, thisRequest.href, thisRequest.media );
66   - parsedSheets[ thisRequest.href ] = true;
67   - makeRequests();
68   - } );
  99 + // Kill proxy interval check
  100 + if (proxyInterval) {
  101 + win.clearInterval(proxyInterval);
  102 + }
69 103 }
70 104 },
71 105
@@ -192,22 +226,61 @@
192 226 head.insertBefore( dFrag, lastLink.nextSibling );
193 227 },
194 228 //tweaked Ajax functions from Quirksmode
195   - ajax = function( url, callback ) {
196   - var req = xmlHttp();
197   - if (!req){
  229 + ajax = function( url, proxy, callback ) {
  230 + if (proxy) {
  231 + var refNode = docElem.firstElementChild || docElem.firstChild;
  232 +
  233 + if (!iframe) {
  234 +
  235 + // All hail Google http://j.mp/iKMI19
  236 + // Behold, an iframe proxy without annoying clicky noises.
  237 + if ("ActiveXObject" in win) {
  238 + AXO = new ActiveXObject("htmlfile");
  239 + AXO.open();
  240 + AXO.write('<iframe id="x"></iframe>');
  241 + AXO.close();
  242 + iframe = AXO.getElementById("x");
  243 + } else {
  244 + iframe = doc.createElement("iframe");
  245 + iframe.style.cssText = "position:absolute;top:-99em";
  246 + docElem.insertBefore(iframe, refNode);
  247 + }
  248 +
  249 + proxyInterval = win.setInterval(function () {
  250 + var cssText;
  251 +
  252 + try {
  253 + cssText = iframe.contentWindow.name;
  254 + } catch (e) {}
  255 +
  256 + if (cssText) {
  257 + // We've got what we need. Stop the iframe from loading further content.
  258 + iframe.src = "about:blank";
  259 +
  260 + callback(cssText);
  261 + }
  262 + }, 50);
  263 + }
  264 +
  265 + iframe.src = proxyURL + "?url=" + redirectURL + "&css=" + url;
198 266 return;
199   - }
200   - req.open( "GET", url, true );
201   - req.onreadystatechange = function () {
202   - if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
  267 + } else {
  268 + var req = xmlHttp();
  269 + if (!req){
203 270 return;
  271 + }
  272 + req.open( "GET", url, true );
  273 + req.onreadystatechange = function () {
  274 + if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
  275 + return;
  276 + }
  277 + callback( req.responseText );
204 278 }
205   - callback( req.responseText );
206   - }
207   - if ( req.readyState == 4 ){
208   - return;
  279 + if ( req.readyState == 4 ){
  280 + return;
  281 + }
  282 + req.send();
209 283 }
210   - req.send();
211 284 },
212 285 //define ajax obj
213 286 xmlHttp = (function() {
27 test/test-x-domain.html
... ... @@ -0,0 +1,27 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <meta charset="utf-8" />
  5 + <title>Respond JS Test Page</title>
  6 +
  7 + <!-- Respond.js proxy on external server -->
  8 + <link href="http://doctyper.com/stuff/respond/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
  9 +
  10 + <!-- Respond.js redirect (optional, defaults to current page) -->
  11 + <link href="/x-domain/favicon.ico" id="respond-redirect" rel="respond-redirect" />
  12 +
  13 + <link href="http://doctyper.com/stuff/respond/test.css" rel="stylesheet"/>
  14 + <link href="http://doctyper.com/stuff/respond/test2.css" media="screen and (min-width: 600px)" rel="stylesheet"/>
  15 + <script src="../respond.src.js"></script>
  16 +</head>
  17 +<body>
  18 + <p>This is just a visual test file, and an ugly one at that!</p>
  19 +
  20 +<p>The media queries in the included CSS file simply change the body's background color depending on the browser width. If you see any colors aside from black, then the media queries are working in your browser. You can resize your browser window to see it change on the fly.</p>
  21 +
  22 +<p>For a realistic use case for media queries: read up on <a href="http://www.alistapart.com/articles/responsive-web-design/">Responsive Web Design</a></p>
  23 +
  24 + <p id="attribute-test">Media-attributes are working too! This should be visible above 600px.</p>
  25 +
  26 +</body>
  27 +</html>
5 test/unit/index.html
@@ -2,11 +2,16 @@
2 2 <html>
3 3 <head>
4 4 <meta charset="utf-8" />
  5 +
  6 + <!-- Respond.js proxy on external server -->
  7 + <link href="http://doctyper.com/stuff/respond/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
  8 +
5 9 <title>Respond.js Test Suite</title>
6 10 <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" media="screen">
7 11 <script src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
8 12 <link href="test.css" rel="stylesheet" />
9 13 <link href="test2.css" media="screen and (min-width: 1200px)" rel="stylesheet" />
  14 + <link href="http://doctyper.com/stuff/respond/test3.css" rel="stylesheet" />
10 15 <script src="../../respond.src.js"></script>
11 16 <script src="tests.js"></script>
12 17
4 test/unit/test.css
@@ -15,8 +15,8 @@
15 15 width: 50px;
16 16 }
17 17
18   -/*styles for 480px and up */
19   -@media screen and (min-width: 480px) {
  18 +/*styles for 400px and up */
  19 +@media screen and (min-width: 400px) {
20 20 #testelem {
21 21 width: 150px;
22 22 }
5 test/unit/test3.css
... ... @@ -0,0 +1,5 @@
  1 +@media screen and (min-width: 1000px) and (max-width: 1200px) {
  2 + #testelem {
  3 + width: 32px;
  4 + }
  5 +}
8 test/unit/tests.js
@@ -92,6 +92,14 @@ window.onload = function(){
92 92 }, 900);
93 93 });
94 94
  95 + asyncTest( "stylesheets from an external domain apply properly", function() {
  96 + window.resizeTo(1100,600);
  97 + setTimeout(function(){
  98 + ok( widthApplied( 32 ), "testelem is 32px wide when window is 1100px wide" );
  99 + start();
  100 + }, 900);
  101 + });
  102 +
95 103 }
96 104
97 105 };
BIN  x-domain/favicon.ico
Binary file not shown
2  x-domain/respond-proxy-min.html
... ... @@ -0,0 +1,2 @@
  1 +<!DOCTYPE html><html><head><meta charset="utf-8" /><title>respond.js</title></head><body><script>(function(){var e,d,c,a,f,g;f=function(a,c){var b=g();if(b)b.open("GET",a,!0),b.onreadystatechange=function(){b.readyState!=4||b.status!=200&&b.status!=304||c(b.responseText)},b.readyState!=4&&b.send()};g=function(){for(var a=!1,c=[function(){return new XMLHttpRequest},function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new ActiveXObject("MSXML2.XMLHTTP.3.0")}],b=c.length;b--;){try{a=c[b]()}catch(d){continue}break}return function(){return a}}();if(c=window.location.href)(a=
  2 +/css\=(.*\.css)$/.exec(c.slice(c.indexOf("?")+1)))&&a[1]&&(d=a[1]),(a=/url\=([^&]+)/.exec(c))&&a[1]&&(e=a[1]);d&&f(d,function(a){window.name=a;window.location.href=e})})();</script></body></html>
79 x-domain/respond-proxy.html
... ... @@ -0,0 +1,79 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <meta charset="utf-8" />
  5 + <title>Respond JS Proxy</title>
  6 +</head>
  7 +<body>
  8 + <script>
  9 + (function () {
  10 + var domain, css, url, match, file, ajax, xmlHttp;
  11 +
  12 + ajax = function( url, callback ) {
  13 + var req = xmlHttp();
  14 + if (!req){
  15 + return;
  16 + }
  17 + req.open( "GET", url, true );
  18 + req.onreadystatechange = function () {
  19 + if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
  20 + return;
  21 + }
  22 + callback( req.responseText );
  23 + };
  24 + if ( req.readyState == 4 ){
  25 + return;
  26 + }
  27 + req.send();
  28 + };
  29 +
  30 + //define ajax obj
  31 + xmlHttp = (function() {
  32 + var xmlhttpmethod = false,
  33 + attempts = [
  34 + function(){ return new XMLHttpRequest(); },
  35 + function(){ return new ActiveXObject("Microsoft.XMLHTTP"); },
  36 + function(){ return new ActiveXObject("MSXML2.XMLHTTP.3.0"); }
  37 + ],
  38 + al = attempts.length;
  39 +
  40 + while( al-- ){
  41 + try {
  42 + xmlhttpmethod = attempts[ al ]();
  43 + }
  44 + catch(e) {
  45 + continue;
  46 + }
  47 + break;
  48 + }
  49 + return function(){
  50 + return xmlhttpmethod;
  51 + };
  52 + })();
  53 +
  54 + url = window.location.href;
  55 +
  56 + if (url) {
  57 + match = (/css\=(.*\.css)$/).exec(url.slice(url.indexOf('?') + 1));
  58 +
  59 + if (match && match[1]) {
  60 + css = match[1];
  61 + }
  62 +
  63 + match = (/url\=([^&]+)/).exec(url);
  64 +
  65 + if (match && match[1]) {
  66 + domain = match[1];
  67 + }
  68 + }
  69 +
  70 + if (css) {
  71 + ajax(css, function (response) {
  72 + window.name = response;
  73 + window.location.href = domain;
  74 + });
  75 + }
  76 + }());
  77 + </script>
  78 +</body>
  79 +</html>

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.