windowName.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. define("dojox/io/windowName", ["dojo/_base/kernel", "dojo/_base/window", "dojo/_base/xhr", "dojo/_base/sniff", "dojo/_base/url", "dojo/domReady!"], function(dojo){
  2. dojo.getObject("io.windowName", true, dojox);
  3. // Implements the window.name transport
  4. dojox.io.windowName = {
  5. send: function(/*String*/ method, /*dojo.__IoArgs*/ args){
  6. // summary:
  7. // Provides secure cross-domain request capability.
  8. // Sends a request using an iframe (POST or GET) and reads the response through the
  9. // frame's window.name.
  10. //
  11. // method:
  12. // The method to use to send the request, GET or POST
  13. //
  14. // args:
  15. // See dojo.xhr
  16. //
  17. // args.authElement: DOMNode?
  18. // By providing an authElement, this indicates that windowName should use the
  19. // authorized window.name protocol, relying on
  20. // the loaded XD resource to return to the provided return URL on completion
  21. // of authorization/authentication. The provided authElement will be used to place
  22. // the iframe in, so the user can interact with the server resource for authentication
  23. // and/or authorization to access the resource.
  24. //
  25. // args.onAuthLoad: Function?
  26. // When using authorized access to resources, this function will be called when the
  27. // authorization page has been loaded. (When authorization is actually completed,
  28. // the deferred callback function is called with the result). The primary use for this
  29. // is to make the authElement visible to the user once the resource has loaded
  30. // (this can be preferable to showing the iframe while the resource is loading
  31. // since it may not require authorization, it may simply return the resource).
  32. //
  33. // description:
  34. // In order to provide a windowname transport accessible resources/web services, a server
  35. // should check for the presence of a parameter window.name=true and if a request includes
  36. // such a parameter, it should respond to the request with an HTML
  37. // document that sets it's window.name to the string that is to be
  38. // delivered to the client. For example, if a client makes a window.name request like:
  39. // | http://othersite.com/greeting?windowname=true
  40. // And server wants to respond to the client with "Hello", it should return an html page:
  41. // | <html><script type="text/javascript">
  42. // | window.name="Hello";
  43. // | </script></html>
  44. // One can provide XML or JSON data by simply quoting the data as a string, and parsing the data
  45. // on the client.
  46. // If you use the authorization window.name protocol, the requester should include an
  47. // authElement element in the args, and a request will be created like:
  48. // | http://othersite.com/greeting?windowname=auth
  49. // And the server can respond like this:
  50. // | <html><script type="text/javascript">
  51. // | var loc = window.name;
  52. // | authorizationButton.onclick = function(){
  53. // | window.name="Hello";
  54. // | location = loc;
  55. // | };
  56. // | </script></html>
  57. // When using windowName from a XD Dojo build, make sure to set the
  58. // dojo.dojoBlankHtmlUrl property to a local URL.
  59. args.url += (args.url.match(/\?/) ? '&' : '?') + "windowname=" + (args.authElement ? "auth" : true); // indicate our desire for window.name communication
  60. var authElement = args.authElement;
  61. var cleanup = function(result){
  62. try{
  63. // we have to do this to stop the wait cursor in FF
  64. var innerDoc = dfd.ioArgs.frame.contentWindow.document;
  65. innerDoc.write(" ");
  66. innerDoc.close();
  67. }catch(e){}
  68. (authElement || dojo.body()).removeChild(dfd.ioArgs.outerFrame); // clean up
  69. return result;
  70. }
  71. var dfd = dojo._ioSetArgs(args,cleanup,cleanup,cleanup);
  72. if(args.timeout){
  73. setTimeout(function(){
  74. if(dfd.fired == -1){
  75. dfd.callback(new Error("Timeout"));
  76. }
  77. },
  78. args.timeout
  79. );
  80. }
  81. dojox.io.windowName._send(dfd, method, authElement, args.onAuthLoad);
  82. return dfd;
  83. },
  84. _send: function(dfd, method, authTarget, onAuthLoad){
  85. var ioArgs = dfd.ioArgs;
  86. var frameNum = dojox.io.windowName._frameNum++;
  87. var sameDomainUrl = (dojo.config.dojoBlankHtmlUrl||dojo.config.dojoCallbackUrl||dojo.moduleUrl("dojo", "resources/blank.html")) + "#" + frameNum;
  88. var frameName = new dojo._Url(window.location, sameDomainUrl);
  89. var doc = dojo.doc;
  90. var frameContainer = authTarget || dojo.body();
  91. function styleFrame(frame){
  92. frame.style.width="100%";
  93. frame.style.height="100%";
  94. frame.style.border="0px";
  95. }
  96. if(dojo.isMoz && ![].reduce){
  97. // FF2 allows unsafe sibling frame modification,
  98. // the fix for this is to create nested frames with getters and setters to protect access
  99. var outerFrame = doc.createElement("iframe");
  100. styleFrame(outerFrame);
  101. if(!authTarget){
  102. outerFrame.style.display='none';
  103. }
  104. frameContainer.appendChild(outerFrame);
  105. var firstWindow = outerFrame.contentWindow;
  106. doc = firstWindow.document;
  107. doc.write("<html><body margin='0px'><iframe style='width:100%;height:100%;border:0px' name='protectedFrame'></iframe></body></html>");
  108. doc.close();
  109. var secondWindow = firstWindow[0];
  110. firstWindow.__defineGetter__(0,function(){});
  111. firstWindow.__defineGetter__("protectedFrame",function(){});
  112. doc = secondWindow.document;
  113. doc.write("<html><body margin='0px'></body></html>");
  114. doc.close();
  115. frameContainer = doc.body;
  116. }
  117. var frame;
  118. if(dojo.isIE){
  119. var div = doc.createElement("div");
  120. div.innerHTML = '<iframe name="' + frameName + '" onload="dojox.io.windowName['+frameNum+']()">';
  121. frame = div.firstChild;
  122. }else{
  123. frame = doc.createElement('iframe');
  124. }
  125. ioArgs.frame = frame;
  126. styleFrame(frame);
  127. ioArgs.outerFrame = outerFrame = outerFrame || frame;
  128. if(!authTarget){
  129. outerFrame.style.display='none';
  130. }
  131. var state = 0;
  132. function getData(){
  133. var data = frame.contentWindow.name;
  134. if(typeof data == 'string'){
  135. if(data != frameName){
  136. state = 2; // we are done now
  137. dfd.ioArgs.hash = frame.contentWindow.location.hash;
  138. dfd.callback(data);
  139. }
  140. }
  141. }
  142. dojox.io.windowName[frameNum] = frame.onload = function(){
  143. try{
  144. if(!dojo.isMoz && frame.contentWindow.location =='about:blank'){
  145. // opera and safari will do an onload for about:blank first, we can ignore this first onload
  146. return;
  147. }
  148. }catch(e){
  149. // if we are in the target domain, frame.contentWindow.location will throw an ignorable error
  150. }
  151. if(!state){
  152. // we have loaded the target resource, now time to navigate back to our domain so we can read the frame name
  153. state=1;
  154. if(authTarget){
  155. // call the callback so it can make it visible
  156. if(onAuthLoad){
  157. onAuthLoad();
  158. }
  159. }else{
  160. // we are doing a synchronous capture, go directly to our same domain URL and retrieve the resource
  161. frame.contentWindow.location = sameDomainUrl;
  162. }
  163. }
  164. // back to our domain, we should be able to access the frame name now
  165. try{
  166. if(state<2){
  167. getData();
  168. }
  169. }
  170. catch(e){
  171. }
  172. };
  173. frame.name = frameName;
  174. if(method.match(/GET/i)){
  175. // if it is a GET we can just the iframe our src url
  176. dojo._ioAddQueryToUrl(ioArgs);
  177. frame.src = ioArgs.url;
  178. frameContainer.appendChild(frame);
  179. if(frame.contentWindow){
  180. frame.contentWindow.location.replace(ioArgs.url);
  181. }
  182. }else if(method.match(/POST/i)){
  183. // if it is a POST we will build a form to post it
  184. frameContainer.appendChild(frame);
  185. var form = dojo.doc.createElement("form");
  186. dojo.body().appendChild(form);
  187. var query = dojo.queryToObject(ioArgs.query);
  188. for(var i in query){
  189. var values = query[i];
  190. values = values instanceof Array ? values : [values];
  191. for(var j = 0; j < values.length; j++){
  192. // create hidden inputs for all the parameters
  193. var input = doc.createElement("input");
  194. input.type = 'hidden';
  195. input.name = i;
  196. input.value = values[j];
  197. form.appendChild(input);
  198. }
  199. }
  200. form.method = 'POST';
  201. form.action = ioArgs.url;
  202. form.target = frameName;// connect the form to the iframe
  203. form.submit();
  204. form.parentNode.removeChild(form);
  205. }else{
  206. throw new Error("Method " + method + " not supported with the windowName transport");
  207. }
  208. if(frame.contentWindow){
  209. frame.contentWindow.name = frameName; // IE likes it afterwards
  210. }
  211. },
  212. _frameNum: 0
  213. };
  214. return dojox.io.windowName;
  215. });