iframe.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojo.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojo.io.iframe"] = true;
  8. dojo.provide("dojo.io.iframe");
  9. dojo.getObject("io", true, dojo);
  10. /*=====
  11. dojo.declare("dojo.io.iframe.__ioArgs", dojo.__IoArgs, {
  12. constructor: function(){
  13. // summary:
  14. // All the properties described in the dojo.__ioArgs type, apply
  15. // to this type. The following additional properties are allowed
  16. // for dojo.io.iframe.send():
  17. // method: String?
  18. // The HTTP method to use. "GET" or "POST" are the only supported
  19. // values. It will try to read the value from the form node's
  20. // method, then try this argument. If neither one exists, then it
  21. // defaults to POST.
  22. // handleAs: String?
  23. // Specifies what format the result data should be given to the
  24. // load/handle callback. Valid values are: text, html, xml, json,
  25. // javascript. IMPORTANT: For all values EXCEPT html and xml, The
  26. // server response should be an HTML file with a textarea element.
  27. // The response data should be inside the textarea element. Using an
  28. // HTML document the only reliable, cross-browser way this
  29. // transport can know when the response has loaded. For the html
  30. // handleAs value, just return a normal HTML document. NOTE: xml
  31. // is now supported with this transport (as of 1.1+); a known issue
  32. // is if the XML document in question is malformed, Internet Explorer
  33. // will throw an uncatchable error.
  34. // content: Object?
  35. // If "form" is one of the other args properties, then the content
  36. // object properties become hidden form form elements. For
  37. // instance, a content object of {name1 : "value1"} is converted
  38. // to a hidden form element with a name of "name1" and a value of
  39. // "value1". If there is not a "form" property, then the content
  40. // object is converted into a name=value&name=value string, by
  41. // using dojo.objectToQuery().
  42. this.method = method;
  43. this.handleAs = handleAs;
  44. this.content = content;
  45. }
  46. });
  47. =====*/
  48. dojo.io.iframe = {
  49. // summary:
  50. // Sends an Ajax I/O call using and Iframe (for instance, to upload files)
  51. create: function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){
  52. // summary:
  53. // Creates a hidden iframe in the page. Used mostly for IO
  54. // transports. You do not need to call this to start a
  55. // dojo.io.iframe request. Just call send().
  56. // fname: String
  57. // The name of the iframe. Used for the name attribute on the
  58. // iframe.
  59. // onloadstr: String
  60. // A string of JavaScript that will be executed when the content
  61. // in the iframe loads.
  62. // uri: String
  63. // The value of the src attribute on the iframe element. If a
  64. // value is not given, then dojo/resources/blank.html will be
  65. // used.
  66. if(window[fname]){ return window[fname]; }
  67. if(window.frames[fname]){ return window.frames[fname]; }
  68. var cframe = null;
  69. var turi = uri;
  70. if(!turi){
  71. if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
  72. console.warn("dojo.io.iframe.create: When using cross-domain Dojo builds,"
  73. + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
  74. + " to the path on your domain to blank.html");
  75. }
  76. turi = (dojo.config["dojoBlankHtmlUrl"]||dojo.moduleUrl("dojo", "resources/blank.html"));
  77. }
  78. var cframe = dojo.place(
  79. '<iframe id="'+fname+'" name="'+fname+'" src="'+turi+'" onload="'+onloadstr+
  80. '" style="position: absolute; left: 1px; top: 1px; height: 1px; width: 1px; visibility: hidden">',
  81. dojo.body());
  82. window[fname] = cframe;
  83. return cframe;
  84. },
  85. setSrc: function(/*DOMNode*/iframe, /*String*/src, /*Boolean*/replace){
  86. //summary:
  87. // Sets the URL that is loaded in an IFrame. The replace parameter
  88. // indicates whether location.replace() should be used when
  89. // changing the location of the iframe.
  90. try{
  91. if(!replace){
  92. if(dojo.isWebKit){
  93. iframe.location = src;
  94. }else{
  95. frames[iframe.name].location = src;
  96. }
  97. }else{
  98. // Fun with DOM 0 incompatibilities!
  99. var idoc;
  100. if(dojo.isIE || dojo.isWebKit){
  101. idoc = iframe.contentWindow.document;
  102. }else{ // if(d.isMozilla){
  103. idoc = iframe.contentWindow;
  104. }
  105. //For Safari (at least 2.0.3) and Opera, if the iframe
  106. //has just been created but it doesn't have content
  107. //yet, then iframe.document may be null. In that case,
  108. //use iframe.location and return.
  109. if(!idoc){
  110. iframe.location = src;
  111. return;
  112. }else{
  113. idoc.location.replace(src);
  114. }
  115. }
  116. }catch(e){
  117. console.log("dojo.io.iframe.setSrc: ", e);
  118. }
  119. },
  120. doc: function(/*DOMNode*/iframeNode){
  121. //summary: Returns the document object associated with the iframe DOM Node argument.
  122. var doc = iframeNode.contentDocument || // W3
  123. (
  124. (
  125. (iframeNode.name) && (iframeNode.document) &&
  126. (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
  127. (dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
  128. )
  129. ) || // IE
  130. (
  131. (iframeNode.name)&&(dojo.doc.frames[iframeNode.name])&&
  132. (dojo.doc.frames[iframeNode.name].document)
  133. ) || null;
  134. return doc;
  135. },
  136. send: function(/*dojo.io.iframe.__ioArgs*/args){
  137. //summary:
  138. // Function that sends the request to the server.
  139. // This transport can only process one send() request at a time, so if send() is called
  140. //multiple times, it will queue up the calls and only process one at a time.
  141. if(!this["_frame"]){
  142. this._frame = this.create(this._iframeName, dojo._scopeName + ".io.iframe._iframeOnload();");
  143. }
  144. //Set up the deferred.
  145. var dfd = dojo._ioSetArgs(
  146. args,
  147. function(/*Deferred*/dfd){
  148. //summary: canceller function for dojo._ioSetArgs call.
  149. dfd.canceled = true;
  150. dfd.ioArgs._callNext();
  151. },
  152. function(/*Deferred*/dfd){
  153. //summary: okHandler function for dojo._ioSetArgs call.
  154. var value = null;
  155. try{
  156. var ioArgs = dfd.ioArgs;
  157. var dii = dojo.io.iframe;
  158. var ifd = dii.doc(dii._frame);
  159. var handleAs = ioArgs.handleAs;
  160. //Assign correct value based on handleAs value.
  161. value = ifd; //html
  162. if(handleAs != "html"){
  163. if(handleAs == "xml"){
  164. // FF, Saf 3+ and Opera all seem to be fine with ifd being xml. We have to
  165. // do it manually for IE6-8. Refs #6334.
  166. if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
  167. dojo.query("a", dii._frame.contentWindow.document.documentElement).orphan();
  168. var xmlText=(dii._frame.contentWindow.document).documentElement.innerText;
  169. xmlText=xmlText.replace(/>\s+</g, "><");
  170. xmlText=dojo.trim(xmlText);
  171. //Reusing some code in base dojo for handling XML content. Simpler and keeps
  172. //Core from duplicating the effort needed to locate the XML Parser on IE.
  173. var fauxXhr = { responseText: xmlText };
  174. value = dojo._contentHandlers["xml"](fauxXhr); // DOMDocument
  175. }
  176. }else{
  177. value = ifd.getElementsByTagName("textarea")[0].value; //text
  178. if(handleAs == "json"){
  179. value = dojo.fromJson(value); //json
  180. }else if(handleAs == "javascript"){
  181. value = dojo.eval(value); //javascript
  182. }
  183. }
  184. }
  185. }catch(e){
  186. value = e;
  187. }finally{
  188. ioArgs._callNext();
  189. }
  190. return value;
  191. },
  192. function(/*Error*/error, /*Deferred*/dfd){
  193. //summary: errHandler function for dojo._ioSetArgs call.
  194. dfd.ioArgs._hasError = true;
  195. dfd.ioArgs._callNext();
  196. return error;
  197. }
  198. );
  199. //Set up a function that will fire the next iframe request. Make sure it only
  200. //happens once per deferred.
  201. dfd.ioArgs._callNext = function(){
  202. if(!this["_calledNext"]){
  203. this._calledNext = true;
  204. dojo.io.iframe._currentDfd = null;
  205. dojo.io.iframe._fireNextRequest();
  206. }
  207. };
  208. this._dfdQueue.push(dfd);
  209. this._fireNextRequest();
  210. //Add it the IO watch queue, to get things like timeout support.
  211. dojo._ioWatch(
  212. dfd,
  213. function(/*Deferred*/dfd){
  214. //validCheck
  215. return !dfd.ioArgs["_hasError"];
  216. },
  217. function(dfd){
  218. //ioCheck
  219. return (!!dfd.ioArgs["_finished"]);
  220. },
  221. function(dfd){
  222. //resHandle
  223. if(dfd.ioArgs._finished){
  224. dfd.callback(dfd);
  225. }else{
  226. dfd.errback(new Error("Invalid dojo.io.iframe request state"));
  227. }
  228. }
  229. );
  230. return dfd;
  231. },
  232. _currentDfd: null,
  233. _dfdQueue: [],
  234. _iframeName: dojo._scopeName + "IoIframe",
  235. _fireNextRequest: function(){
  236. //summary: Internal method used to fire the next request in the bind queue.
  237. try{
  238. if((this._currentDfd)||(this._dfdQueue.length == 0)){ return; }
  239. //Find next deferred, skip the canceled ones.
  240. do{
  241. var dfd = this._currentDfd = this._dfdQueue.shift();
  242. } while(dfd && dfd.canceled && this._dfdQueue.length);
  243. //If no more dfds, cancel.
  244. if(!dfd || dfd.canceled){
  245. this._currentDfd = null;
  246. return;
  247. }
  248. var ioArgs = dfd.ioArgs;
  249. var args = ioArgs.args;
  250. ioArgs._contentToClean = [];
  251. var fn = dojo.byId(args["form"]);
  252. var content = args["content"] || {};
  253. if(fn){
  254. if(content){
  255. // if we have things in content, we need to add them to the form
  256. // before submission
  257. var pHandler = function(name, value) {
  258. dojo.create("input", {type: "hidden", name: name, value: value}, fn);
  259. ioArgs._contentToClean.push(name);
  260. };
  261. for(var x in content){
  262. var val = content[x];
  263. if(dojo.isArray(val) && val.length > 1){
  264. var i;
  265. for (i = 0; i < val.length; i++) {
  266. pHandler(x,val[i]);
  267. }
  268. }else{
  269. if(!fn[x]){
  270. pHandler(x,val);
  271. }else{
  272. fn[x].value = val;
  273. }
  274. }
  275. }
  276. }
  277. //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
  278. //so use it for all. See #2844
  279. var actnNode = fn.getAttributeNode("action");
  280. var mthdNode = fn.getAttributeNode("method");
  281. var trgtNode = fn.getAttributeNode("target");
  282. if(args["url"]){
  283. ioArgs._originalAction = actnNode ? actnNode.value : null;
  284. if(actnNode){
  285. actnNode.value = args.url;
  286. }else{
  287. fn.setAttribute("action",args.url);
  288. }
  289. }
  290. if(!mthdNode || !mthdNode.value){
  291. if(mthdNode){
  292. mthdNode.value= (args["method"]) ? args["method"] : "post";
  293. }else{
  294. fn.setAttribute("method", (args["method"]) ? args["method"] : "post");
  295. }
  296. }
  297. ioArgs._originalTarget = trgtNode ? trgtNode.value: null;
  298. if(trgtNode){
  299. trgtNode.value = this._iframeName;
  300. }else{
  301. fn.setAttribute("target", this._iframeName);
  302. }
  303. fn.target = this._iframeName;
  304. dojo._ioNotifyStart(dfd);
  305. fn.submit();
  306. }else{
  307. // otherwise we post a GET string by changing URL location for the
  308. // iframe
  309. var tmpUrl = args.url + (args.url.indexOf("?") > -1 ? "&" : "?") + ioArgs.query;
  310. dojo._ioNotifyStart(dfd);
  311. this.setSrc(this._frame, tmpUrl, true);
  312. }
  313. }catch(e){
  314. dfd.errback(e);
  315. }
  316. },
  317. _iframeOnload: function(){
  318. var dfd = this._currentDfd;
  319. if(!dfd){
  320. this._fireNextRequest();
  321. return;
  322. }
  323. var ioArgs = dfd.ioArgs;
  324. var args = ioArgs.args;
  325. var fNode = dojo.byId(args.form);
  326. if(fNode){
  327. // remove all the hidden content inputs
  328. var toClean = ioArgs._contentToClean;
  329. for(var i = 0; i < toClean.length; i++) {
  330. var key = toClean[i];
  331. //Need to cycle over all nodes since we may have added
  332. //an array value which means that more than one node could
  333. //have the same .name value.
  334. for(var j = 0; j < fNode.childNodes.length; j++){
  335. var chNode = fNode.childNodes[j];
  336. if(chNode.name == key){
  337. dojo.destroy(chNode);
  338. break;
  339. }
  340. }
  341. }
  342. // restore original action + target
  343. if(ioArgs["_originalAction"]){
  344. fNode.setAttribute("action", ioArgs._originalAction);
  345. }
  346. if(ioArgs["_originalTarget"]){
  347. fNode.setAttribute("target", ioArgs._originalTarget);
  348. fNode.target = ioArgs._originalTarget;
  349. }
  350. }
  351. ioArgs._finished = true;
  352. }
  353. };
  354. }