Cross-domain Partial Page Updates with JavaScript
Untill now we've kept the news here strictly Ariadne related, but from now on we'll make an exception once in a while for cool stuff that might be usefull for other web developers. Here's a javascript technique which opens a lot of possibilities for easy content 'syndication'.
Ajax is the new cool kid on the block. And there’s nothing wrong with that, it is cool technology, and the hype surrounding it has at least the bonus of re-introducing people with javascript. The modern, mature and super flexible javascript that is.
But there are a few problems with Ajax, which can be overcome by stepping back from the cool kid and take a look around at the ‘old’ techniques. The most obvious problem is a feature of the XmlHttpRequest method or object (depending on your browser flavour of choice). Its called the same-origin security feature. This is the built-in safety check, which prevents a script to get content from a different host than the host that served the script, or page.
Here's a technique which gets around that limitation, and should work on almost any browser.
The way the same-origin policy works is that a page cannot access or change anything in another page, unless that page is from the same host. There is one exception to this rule, if both pages come from the same root domain, and both set ‘document.domain’ to this root domain, access between the two is allowed.
The XmlHttpRequest works the same, except for a small problem: Mozilla’s XmlHttpRequest method doesn’t acknowledge the document.domain setting. So there is no way to communicate between different servers directly through it. You can create a workaround by installing a cgi script on each server which does the cross-domain communication for you, but that requires a lot more access to the server environment.
There is one exception to the same-origin rule however. Any script directly included on a page, is assumed to come from the same domain as the page it is included in. The javascript security guru’s probably decided that if the author of a page includes a script from a different server, he or she probably knows what they’re doing. You might think, fine, so from that script we can do an XmlHttpRequest to the server the script came from, but you’d be wrong. The script is considered to come from the same host as the rest of the page is from, not from the host in the src attribute of the script tag.
But still, you can do a lot with just this knowledge. Say for example, that you have a portal with lots of different and fast changing content. And there are a lot of affiliate sites which might want to use that content on their websites, but the technology used in those sites varies wildly, from frontpage sites to lotus domino to home-built php sites. It would be an enormous task to update each site with server side scripting to syndicate content. But what if we let the browser do all the hard work?
Say you have a script on the portal, which simply does:
document.write(‘Some dynamic content here’);
All you’d need to include this dynamic content in a page on a different host is:
<script src="http://my.portal.com/dynamic.js"></script>
And the dynamic content will be included at the exact spot the script tag is in the page. There are some problems with this though, most important: the rendering of the page waits untill the content from the portal is retrieved. Another slight problem is that xhtml pages disallow document.write(). So this is not a very good solution. However, with a small bit of extra work, we can avoid both problems, and have some extra possibilities as well:
<html>
…
<body>
… some html content…
<div id="myportalcontent">Portal content is loading…</div>
… some more html content …
<script src="http://my.portal.com/dynamic.js?target=myportalcontent"></script>
</body>
</html>
And the dynamic.js script, which is in fact a server side script, e.g. PHP, that outputs a piece of javascript, now looks like this:
document.getElementById(‘<?php echo $target; ?>’).innerHTML=’Some dynamic content’;
The result is a nice ‘loading’ message somewhere in the page, while the rest of the page is immediately rendered. At the end of the content, the script is included, and when loaded updates the div to show the dynamic content instead of the loading message. There is no need to show a loading message, you can simply leave the div empty, so it will only show the content when something is available. You can also style the div to match the site design, e.g. give it a fixed width and height, set a background image, etc.
But because there is now a div with an id, it is also possible to do another update of the content every so often. All you need is a reliable way to reload the same script, like this:
document.getElementById(‘<?php echo $target; ?>’).innerHTML=’Some dynamic content’;
setTimeout(function() {
var script=document.getElementById(‘script_<?php echo $target; ?>’);
if (script) {
script.parentNode.removeChild(script);
}
script=document.createElement('SCRIPT');
script.id=’script_<?php echo $target; ?>’;
script.src='http://my.portal.com/dynamic.js?target=<?php
echo RawUrlEncode($target); ?>&time=<?php echo time(); ?>';
var head=document.getElementsByTagName('HEAD')[0];
head.appendChild(script);
}, 5000);
In this last script, after updating the content, the script adds a new script tag in the head with the same source. It adds a timestamp, to make sure Internet Explorer doesn’t use a cached version. If a script tag for this target is already in the head, it removes it, otherwise Mozilla doesn't update the content. All this is done after a wait of 5 seconds. So each 5 seconds a new script is loaded from the portal, which updates the content div.
This technique has been tested in Internet Explorer 6, Firefox 1.0.6, Opera 7.54 and Safari 1.3.1.
Auke van Slooten
Muze

