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