| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| |
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
| <head> |
| <title></title> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta> |
| <!-- Security protection: uncomment the script tag to enable. --> |
| <!-- script type="text/javascript" --> |
| // <!-- |
| /* |
| This file is really focused on just sending one message to the server, and |
| receiving one response. The code does not expect to be re-used for multiple messages. |
| This might be reworked later if performance indicates a need for it. |
| |
| xip fragment identifier/hash values have the form: |
| #id:cmd:realEncodedMessage |
| |
| id: some ID that should be unique among messages. No inherent meaning, |
| just something to make sure the hash value is unique so the message |
| receiver knows a new message is available. |
| |
| cmd: command to the receiver. Valid values are: |
| - init: message used to init the frame. Sent as the first URL when loading |
| the page. Contains some config parameters. |
| - loaded: the remote frame is loaded. Only sent from server to client. |
| - ok: the message that this page sent was received OK. The next message may |
| now be sent. |
| - start: the start message of a block of messages (a complete message may |
| need to be segmented into many messages to get around the limitiations |
| of the size of an URL that a browser accepts. |
| - part: indicates this is a part of a message. |
| - end: the end message of a block of messages. The message can now be acted upon. |
| If the message is small enough that it doesn't need to be segmented, then |
| just one hash value message can be sent with "end" as the command. |
| |
| To reassemble a segmented message, the realEncodedMessage parts just have to be concatenated |
| together. |
| */ |
| |
| //MSIE has the lowest limit for URLs with fragment identifiers, |
| //at around 4K. Choosing a slightly smaller number for good measure. |
| xipUrlLimit = 4000; |
| xipIdCounter = 1; |
| |
| function xipInit(){ |
| xipStateId = ""; |
| xipIsSending = false; |
| xipServerUrl = null; |
| xipStateId = null; |
| xipRequestData = null; |
| xipCurrentHash = ""; |
| xipResponseMessage = ""; |
| xipRequestParts = []; |
| xipPartIndex = 0; |
| xipServerWindow = null; |
| xipUseFrameRecursion = false; |
| } |
| xipInit(); |
| |
| function send(encodedData){ |
| if(xipUseFrameRecursion == "true"){ |
| var clientEndPoint = window.open(xipStateId + "_clientEndPoint"); |
| clientEndPoint.send(encodedData); |
| }else{ |
| if(!xipIsSending){ |
| xipIsSending = true; |
| |
| xipRequestData = encodedData || ""; |
| |
| //Get a handle to the server iframe. |
| xipServerWindow = frames[xipStateId + "_frame"]; |
| if (!xipServerWindow){ |
| xipServerWindow = document.getElementById(xipStateId + "_frame").contentWindow; |
| } |
| |
| sendRequestStart(); |
| } |
| } |
| } |
| |
| //Modify the server URL if it is a local path and |
| //This is done for local/same domain testing. |
| function fixServerUrl(ifpServerUrl){ |
| if(ifpServerUrl.indexOf("..") == 0){ |
| var parts = ifpServerUrl.split("/"); |
| ifpServerUrl = parts[parts.length - 1]; |
| } |
| return ifpServerUrl; |
| } |
| |
| |
| function pollHash(){ |
| //Can't use location.hash because at least Firefox does a decodeURIComponent on it. |
| var urlParts = window.location.href.split("#"); |
| if(urlParts.length == 2){ |
| var newHash = urlParts[1]; |
| if(newHash != xipCurrentHash){ |
| try{ |
| messageReceived(newHash); |
| }catch(e){ |
| //Make sure to not keep processing the error hash value. |
| xipCurrentHash = newHash; |
| throw e; |
| } |
| xipCurrentHash = newHash; |
| } |
| } |
| } |
| |
| function messageReceived(encodedData){ |
| var msg = unpackMessage(encodedData); |
| |
| switch(msg.command){ |
| case "loaded": |
| xipMasterFrame.dojo.io.XhrIframeProxy.clientFrameLoaded(xipStateId); |
| break; |
| case "ok": |
| sendRequestPart(); |
| break; |
| case "start": |
| xipResponseMessage = ""; |
| xipResponseMessage += msg.message; |
| setServerUrl("ok"); |
| break; |
| case "part": |
| xipResponseMessage += msg.message; |
| setServerUrl("ok"); |
| break; |
| case "end": |
| setServerUrl("ok"); |
| xipResponseMessage += msg.message; |
| xipMasterFrame.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage); |
| break; |
| } |
| } |
| |
| function sendRequestStart(){ |
| //Break the message into parts, if necessary. |
| xipRequestParts = []; |
| var reqData = xipRequestData; |
| var urlLength = xipServerUrl.length; |
| var partLength = xipUrlLimit - urlLength; |
| var reqIndex = 0; |
| |
| while((reqData.length - reqIndex) + urlLength > xipUrlLimit){ |
| var part = reqData.substring(reqIndex, reqIndex + partLength); |
| //Safari will do some extra hex escaping unless we keep the original hex |
| //escaping complete. |
| var percentIndex = part.lastIndexOf("%"); |
| if(percentIndex == part.length - 1 || percentIndex == part.length - 2){ |
| part = part.substring(0, percentIndex); |
| } |
| xipRequestParts.push(part); |
| reqIndex += part.length; |
| } |
| xipRequestParts.push(reqData.substring(reqIndex, reqData.length)); |
| |
| xipPartIndex = 0; |
| sendRequestPart(); |
| |
| } |
| |
| function sendRequestPart(){ |
| if(xipPartIndex < xipRequestParts.length){ |
| //Get the message part. |
| var partData = xipRequestParts[xipPartIndex]; |
| |
| //Get the command. |
| var cmd = "part"; |
| if(xipPartIndex + 1 == xipRequestParts.length){ |
| cmd = "end"; |
| }else if (xipPartIndex == 0){ |
| cmd = "start"; |
| } |
| |
| setServerUrl(cmd, partData); |
| xipPartIndex++; |
| } |
| } |
| |
| function setServerUrl(cmd, message){ |
| var serverUrl = makeServerUrl(cmd, message); |
| |
| //Safari won't let us replace across domains. |
| if(navigator.userAgent.indexOf("Safari") == -1){ |
| xipServerWindow.location.replace(serverUrl); |
| }else{ |
| xipServerWindow.location = serverUrl; |
| } |
| } |
| |
| function makeServerUrl(cmd, message){ |
| var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd; |
| if(message){ |
| serverUrl += ":" + message; |
| } |
| return serverUrl; |
| } |
| |
| function unpackMessage(encodedMessage){ |
| var parts = encodedMessage.split(":"); |
| var command = parts[1]; |
| encodedMessage = parts[2] || ""; |
| |
| var config = null; |
| if(command == "init"){ |
| var configParts = encodedMessage.split("&"); |
| config = {}; |
| for(var i = 0; i < configParts.length; i++){ |
| var nameValue = configParts[i].split("="); |
| config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); |
| } |
| } |
| return {command: command, message: encodedMessage, config: config}; |
| } |
| |
| function onClientLoad(){ |
| //Decode the init params |
| var config = unpackMessage(window.location.href.split("#")[1]).config; |
| |
| xipStateId = config.id; |
| |
| //Remove the query param for the IE7 recursive case. |
| xipServerUrl = fixServerUrl(config.server).replace(/(\?|\&)dojo\.fr\=1/, ""); |
| |
| //Make sure we don't have a javascript: url, just for good measure. |
| if(xipServerUrl.split(":")[0].match(/javascript/i)){ |
| throw "Invalid server URL"; |
| } |
| |
| xipUseFrameRecursion = config["fr"]; |
| |
| if(xipUseFrameRecursion == "endpoint"){ |
| xipMasterFrame = parent.parent; |
| }else{ |
| xipMasterFrame = parent; |
| } |
| |
| //Start counter to inspect hash value. |
| setInterval(pollHash, 10); |
| |
| var clientUrl = window.location.href.split("#")[0]; |
| var iframeNode = document.getElementsByTagName("iframe")[0]; |
| iframeNode.id = xipStateId + "_frame"; |
| iframeNode.src = makeServerUrl("init", 'id=' + xipStateId + '&client=' |
| + encodeURIComponent(clientUrl) + '&fr=' + xipUseFrameRecursion); |
| } |
| |
| if(typeof(window.addEventListener) == "undefined"){ |
| window.attachEvent("onload", onClientLoad); |
| }else{ |
| window.addEventListener('load', onClientLoad, false); |
| } |
| |
| // --> |
| </script> |
| </head> |
| <body> |
| <h4>The Dojo Toolkit -- xip_client.html</h4> |
| |
| <p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used |
| internally by dojo.io.XhrIframeProxy.</p> |
| |
| <iframe src="javascript:false"></iframe> |
| </body> |
| </html> |