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