Hermes

February 14th, 2007 by admin

Cross-Domain Dynamic Script Attachment

A challenge for developers wishing to use AJAX to incorporate dynamic content from another domain into their page is that AJAX was limited call back to the same domain that the page originated from. Workarounds have been implemented by having the AJAX call to a server process which then makes the request to the other on behalf of the browser, but this increases the load substantially on the originating server and exposes it to risk if the remote server is unresponsive. iFrames from other domains can not directly interact with the host pages. Even appropriately sizing the iFrame to its content can be a challenge. Other work arounds use plug-ins.

You can include Javascript easily from another site by adding a script tag and it gains full access to the page. This is limited to a single call at page load and hazardous as well since IE will fail to load the entire page if included script resources are not available. The solution is to add the script files dynamically after page load, gaining the advantage of the cross-domain support and integration that included scripts offer without the risk that a failed server would present.

Basic Scenario
On the Page
function fnCheckName(testname) {
var dTimeStamp = new Date();
var sURL = "http://www.foreigndomain.com/checkname.php?name=" + testname + "&callid=" + dTimeStamp.getTime();
var script=document.getElementById("script_CheckName");
if (script) script.parentNode.removeChild(script);
script=document.createElement("SCRIPT");
script.id="script_CheckName";
script.src=sURL;
var head=document.getElementsByTagName("HEAD")[0];
head.appendChild(script);
}
function fnReceiveResponse(rResult) {
//script for handling the result goes here.
}

On the Server
The checkname.php page would simply return a result such as:
fnReceiveResponse("The name was valid.");

As you can see the communication process is very simple and similar to that used by AJAX. However, if the call fails, you will not receive a result. One solution would be to add a setTimeout call to a function to respond to a delayed or failed request.

Adding Support for Call Failures
On the Page
var gCheckNameTimeout;
var gCurrentCallID;
function fnCheckName(testname) {
var dTimeStamp = new Date();
gCurrentCallID = dTimeStamp.getTime();
var sURL = "http://www.foreigndomain.com/checkname.php?name=" + testname + "&callid=" + gCurrentCallID;
var script=document.getElementById("script_CheckName");
if (script) script.parentNode.removeChild(script);
script=document.createElement("SCRIPT");
script.id="script_CheckName";
script.src=sURL;
var head=document.getElementsByTagName("HEAD")[0];
head.appendChild(script);

//set time-out to 5 seconds
gCheckNameTimeout = setTimeout("fnResponseTimeout(gCurrentCallID)",5000);
}

function fnReceiveResponse(CallID, rResult) {
if (CallID == gCurrentCallID) {
clearTimeout(gCheckNameTimeout);
//script for handling the result goes here.
}
}


function fnResponseTimeout(CallID) {
if (CallID == gCurrentCallID) {
gCurrentCallID = 0;
//code to handle failed call goes here
}
}

From the server
In this case the server would need to return the passed callid along with the result:
fnReceiveResponse(12345,"The name was valid.");

Other Usage Scenarios
The flexibilty of Javascript affords quite a few options in passing data to the page. Including updating variables, updating content on the page directly, loading in XML data and much more.

Updating a DIV
var gCheckNameTimeout;
var gCurrentCallID;
function fnUpdateDiv(target,value) {
var dTimeStamp = new Date();
gCurrentCallID = dTimeStamp.getTime();
var sURL = "http://www.foreigndomain.com/checkname.php?target=" + target + "&value=" + value + "&callid=" + gCurrentCallID;
var script=document.getElementById("script_" + target);
if (script) script.parentNode.removeChild(script);
script=document.createElement("SCRIPT");
script.id="script_" + target;
script.src=sURL;
var head=document.getElementsByTagName("HEAD")[0];
head.appendChild(script);
}

The server would the return code such as:
document.getElementById('targetdivname').innerHTML='HTML contents for target DIV';"

Hermes
It is likely this technique has been implemented by many others to address this challenge, but I was only able to find two references online for it: Cross Domain Partial Page Updates with JavaScript by Auke van Slooten and Howto Dynamically Insert Javascript And CSS by Patrick Hunlock. Part of the lack of awareness may be that the technique does not have a coherent brand to describe it. I’m proposing the name of Hermes, the Greek messenger of the gods.

Browser Support
This technique is widely supported in modern browsers and since it involves simple DOM insertion it should work for many older browsers. I’ve tested it on Internet Explorer 7, Firefox 2.0. and Netscape 8.1.2 on Windows XP, Internet Explorer 7 and Firefox 2.0 on Vista, and Netscape 7.2, Safari 2.0 and Firefox 1.0.4 on OS-X with full success. Auke van Slooten noted that the technique has worked successfully in Internet Explorer 6, Firefox 1.0.6, Opera 7.54 and Safari 1.3.1.



For a live demonstration see the Hermes Demo Page

Posted in Uncategorized |

One Response

  1. Andrew Says:

    Can you please provide the source code for the server php ?

    I am trying to implement as you describe but it does not work for me.

    The error console in mozilla says the receive functions from Hermes example are not defined.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.