]>
Commit | Line | Data |
---|---|---|
f0cfe83e AD |
1 | define("dojo/request/iframe", [ |
2 | 'module', | |
3 | 'require', | |
4 | './watch', | |
5 | './util', | |
6 | './handlers', | |
7 | '../_base/lang', | |
8 | '../io-query', | |
9 | '../query', | |
10 | '../has', | |
11 | '../dom', | |
12 | '../dom-construct', | |
13 | '../_base/window'/*=====, | |
14 | '../request', | |
15 | '../_base/declare' =====*/ | |
16 | ], function(module, require, watch, util, handlers, lang, ioQuery, query, has, dom, domConstruct, win/*=====, request, declare =====*/){ | |
17 | var mid = module.id.replace(/[\/\.\-]/g, '_'), | |
18 | onload = mid + '_onload'; | |
19 | ||
20 | if(!win.global[onload]){ | |
21 | win.global[onload] = function(){ | |
22 | var dfd = iframe._currentDfd; | |
23 | if(!dfd){ | |
24 | iframe._fireNextRequest(); | |
25 | return; | |
26 | } | |
27 | ||
28 | var response = dfd.response, | |
29 | options = response.options, | |
30 | formNode = dom.byId(options.form) || dfd._tmpForm; | |
31 | ||
32 | if(formNode){ | |
33 | // remove all the hidden content inputs | |
34 | var toClean = dfd._contentToClean; | |
35 | for(var i=0; i<toClean.length; i++){ | |
36 | var key = toClean[i]; | |
37 | //Need to cycle over all nodes since we may have added | |
38 | //an array value which means that more than one node could | |
39 | //have the same .name value. | |
40 | for(var j=0; j<formNode.childNodes.length; j++){ | |
41 | var childNode = formNode.childNodes[j]; | |
42 | if(childNode.name === key){ | |
43 | domConstruct.destroy(childNode); | |
44 | break; | |
45 | } | |
46 | } | |
47 | } | |
48 | ||
49 | // restore original action + target | |
50 | dfd._originalAction && formNode.setAttribute('action', dfd._originalAction); | |
51 | if(dfd._originalMethod){ | |
52 | formNode.setAttribute('method', dfd._originalMethod); | |
53 | formNode.method = dfd._originalMethod; | |
54 | } | |
55 | if(dfd._originalTarget){ | |
56 | formNode.setAttribute('target', dfd._originalTarget); | |
57 | formNode.target = dfd._originalTarget; | |
58 | } | |
59 | } | |
60 | ||
61 | if(dfd._tmpForm){ | |
62 | domConstruct.destroy(dfd._tmpForm); | |
63 | delete dfd._tmpForm; | |
64 | } | |
65 | ||
66 | dfd._finished = true; | |
67 | }; | |
68 | } | |
69 | ||
70 | function create(name, onloadstr, uri){ | |
71 | if(win.global[name]){ | |
72 | return win.global[name]; | |
73 | } | |
74 | ||
75 | if(win.global.frames[name]){ | |
76 | return win.global.frames[name]; | |
77 | } | |
78 | ||
79 | if(!uri){ | |
80 | if(has('config-useXDomain') && !has('config-dojoBlankHtmlUrl')){ | |
81 | console.warn('dojo/request/iframe: When using cross-domain Dojo builds,' + | |
82 | ' please save dojo/resources/blank.html to your domain and set dojoConfig.dojoBlankHtmlUrl' + | |
83 | ' to the path on your domain to blank.html'); | |
84 | } | |
85 | uri = (has('config-dojoBlankHtmlUrl')||require.toUrl('dojo/resources/blank.html')); | |
86 | } | |
87 | ||
88 | var frame = domConstruct.place( | |
89 | '<iframe id="'+name+'" name="'+name+'" src="'+uri+'" onload="'+onloadstr+ | |
90 | '" style="position: absolute; left: 1px; top: 1px; height: 1px; width: 1px; visibility: hidden">', | |
91 | win.body()); | |
92 | ||
93 | win.global[name] = frame; | |
94 | ||
95 | return frame; | |
96 | } | |
97 | ||
98 | function setSrc(_iframe, src, replace){ | |
99 | var frame = win.global.frames[_iframe.name]; | |
100 | ||
101 | if(frame.contentWindow){ | |
102 | // We have an iframe node instead of the window | |
103 | frame = frame.contentWindow; | |
104 | } | |
105 | ||
106 | try{ | |
107 | if(!replace){ | |
108 | frame.location = src; | |
109 | }else{ | |
110 | frame.location.replace(src); | |
111 | } | |
112 | }catch(e){ | |
113 | console.log('dojo/request/iframe.setSrc: ', e); | |
114 | } | |
115 | } | |
116 | ||
117 | function doc(iframeNode){ | |
118 | if(iframeNode.contentDocument){ | |
119 | return iframeNode.contentDocument; | |
120 | } | |
121 | var name = iframeNode.name; | |
122 | if(name){ | |
123 | var iframes = win.doc.getElementsByTagName('iframe'); | |
124 | if(iframeNode.document && iframes[name].contentWindow && iframes[name].contentWindow.document){ | |
125 | return iframes[name].contentWindow.document; | |
126 | }else if(win.doc.frames[name] && win.doc.frames[name].document){ | |
127 | return win.doc.frames[name].document; | |
128 | } | |
129 | } | |
130 | return null; | |
131 | } | |
132 | ||
133 | function createForm(){ | |
134 | return domConstruct.create('form', { | |
135 | name: mid + '_form', | |
136 | style: { | |
137 | position: 'absolute', | |
138 | top: '-1000px', | |
139 | left: '-1000px' | |
140 | } | |
141 | }, win.body()); | |
142 | } | |
143 | ||
144 | function fireNextRequest(){ | |
145 | // summary: | |
146 | // Internal method used to fire the next request in the queue. | |
147 | var dfd; | |
148 | try{ | |
149 | if(iframe._currentDfd || !iframe._dfdQueue.length){ | |
150 | return; | |
151 | } | |
152 | do{ | |
153 | dfd = iframe._currentDfd = iframe._dfdQueue.shift(); | |
154 | }while(dfd && (dfd.canceled || (dfd.isCanceled && dfd.isCanceled())) && iframe._dfdQueue.length); | |
155 | ||
156 | if(!dfd || dfd.canceled || (dfd.isCanceled && dfd.isCanceled())){ | |
157 | iframe._currentDfd = null; | |
158 | return; | |
159 | } | |
160 | ||
161 | var response = dfd.response, | |
162 | options = response.options, | |
163 | c2c = dfd._contentToClean = [], | |
164 | formNode = dom.byId(options.form), | |
165 | notify = util.notify, | |
166 | data = options.data || null, | |
167 | queryStr; | |
168 | ||
169 | if(!dfd._legacy && options.method === 'POST' && !formNode){ | |
170 | formNode = dfd._tmpForm = createForm(); | |
171 | }else if(options.method === 'GET' && formNode && response.url.indexOf('?') > -1){ | |
172 | queryStr = response.url.slice(response.url.indexOf('?') + 1); | |
173 | data = lang.mixin(ioQuery.queryToObject(queryStr), data); | |
174 | } | |
175 | ||
176 | if(formNode){ | |
177 | if(!dfd._legacy){ | |
178 | var parentNode = formNode; | |
179 | do{ | |
180 | parentNode = parentNode.parentNode; | |
181 | }while(parentNode !== win.doc.documentElement); | |
182 | ||
183 | // Append the form node or some browsers won't work | |
184 | if(!parentNode){ | |
185 | formNode.style.position = 'absolute'; | |
186 | formNode.style.left = '-1000px'; | |
187 | formNode.style.top = '-1000px'; | |
188 | win.body().appendChild(formNode); | |
189 | } | |
190 | ||
191 | if(!formNode.name){ | |
192 | formNode.name = mid + '_form'; | |
193 | } | |
194 | } | |
195 | ||
196 | // if we have things in data, we need to add them to the form | |
197 | // before submission | |
198 | if(data){ | |
199 | var createInput = function(name, value){ | |
200 | domConstruct.create('input', { | |
201 | type: 'hidden', | |
202 | name: name, | |
203 | value: value | |
204 | }, formNode); | |
205 | c2c.push(name); | |
206 | }; | |
207 | for(var x in data){ | |
208 | var val = data[x]; | |
209 | if(lang.isArray(val) && val.length > 1){ | |
210 | for(var i=0; i<val.length; i++){ | |
211 | createInput(x, val[i]); | |
212 | } | |
213 | }else{ | |
214 | if(!formNode[x]){ | |
215 | createInput(x, val); | |
216 | }else{ | |
217 | formNode[x].value = val; | |
218 | } | |
219 | } | |
220 | } | |
221 | } | |
222 | ||
223 | //IE requires going through getAttributeNode instead of just getAttribute in some form cases, | |
224 | //so use it for all. See #2844 | |
225 | var actionNode = formNode.getAttributeNode('action'), | |
226 | methodNode = formNode.getAttributeNode('method'), | |
227 | targetNode = formNode.getAttributeNode('target'); | |
228 | ||
229 | if(response.url){ | |
230 | dfd._originalAction = actionNode ? actionNode.value : null; | |
231 | if(actionNode){ | |
232 | actionNode.value = response.url; | |
233 | }else{ | |
234 | formNode.setAttribute('action', response.url); | |
235 | } | |
236 | } | |
237 | ||
238 | if(!dfd._legacy){ | |
239 | dfd._originalMethod = methodNode ? methodNode.value : null; | |
240 | if(methodNode){ | |
241 | methodNode.value = options.method; | |
242 | }else{ | |
243 | formNode.setAttribute('method', options.method); | |
244 | } | |
245 | }else{ | |
246 | if(!methodNode || !methodNode.value){ | |
247 | if(mthdNode){ | |
248 | mthdNode.value = options.method; | |
249 | }else{ | |
250 | fn.setAttribute("method", options.method); | |
251 | } | |
252 | } | |
253 | } | |
254 | ||
255 | dfd._originalTarget = targetNode ? targetNode.value : null; | |
256 | if(targetNode){ | |
257 | targetNode.value = iframe._iframeName; | |
258 | }else{ | |
259 | formNode.setAttribute('target', iframe._iframeName); | |
260 | } | |
261 | formNode.target = iframe._iframeName; | |
262 | ||
263 | notify && notify.emit('send', response, dfd.promise.cancel); | |
264 | iframe._notifyStart(response); | |
265 | formNode.submit(); | |
266 | }else{ | |
267 | // otherwise we post a GET string by changing URL location for the | |
268 | // iframe | |
269 | ||
270 | var extra = ''; | |
271 | if(response.options.data){ | |
272 | extra = response.options.data; | |
273 | if(typeof extra !== 'string'){ | |
274 | extra = ioQuery.objectToQuery(extra); | |
275 | } | |
276 | } | |
277 | var tmpUrl = response.url + (response.url.indexOf('?') > -1 ? '&' : '?') + extra; | |
278 | notify && notify.emit('send', response, dfd.promise.cancel); | |
279 | iframe._notifyStart(response); | |
280 | iframe.setSrc(iframe._frame, tmpUrl, true); | |
281 | } | |
282 | }catch(e){ | |
283 | dfd.reject(e); | |
284 | } | |
285 | } | |
286 | ||
287 | // dojo/request/watch handlers | |
288 | function isValid(response){ | |
289 | return !this.isFulfilled(); | |
290 | } | |
291 | function isReady(response){ | |
292 | return !!this._finished; | |
293 | } | |
294 | function handleResponse(response, error){ | |
295 | if(!error){ | |
296 | try{ | |
297 | var options = response.options, | |
298 | doc = iframe.doc(iframe._frame), | |
299 | handleAs = options.handleAs; | |
300 | ||
301 | if(handleAs !== 'html'){ | |
302 | if(handleAs === 'xml'){ | |
303 | // IE6-8 have to parse the XML manually. See http://bugs.dojotoolkit.org/ticket/6334 | |
304 | if(doc.documentElement.tagName.toLowerCase() === 'html'){ | |
305 | query('a', doc.documentElement).orphan(); | |
306 | var xmlText = doc.documentElement.innerText; | |
307 | xmlText = xmlText.replace(/>\s+</g, '><'); | |
308 | response.text = lang.trim(xmlText); | |
309 | }else{ | |
310 | response.data = doc; | |
311 | } | |
312 | }else{ | |
313 | // 'json' and 'javascript' and 'text' | |
314 | response.text = doc.getElementsByTagName('textarea')[0].value; // text | |
315 | } | |
316 | handlers(response); | |
317 | }else{ | |
318 | response.data = doc; | |
319 | } | |
320 | }catch(e){ | |
321 | error = e; | |
322 | } | |
323 | } | |
324 | ||
325 | if(error){ | |
326 | this.reject(error); | |
327 | }else if(this._finished){ | |
328 | this.resolve(response); | |
329 | }else{ | |
330 | this.reject(new Error('Invalid dojo/request/iframe request state')); | |
331 | } | |
332 | } | |
333 | function last(response){ | |
334 | this._callNext(); | |
335 | } | |
336 | ||
337 | var defaultOptions = { | |
338 | method: 'POST' | |
339 | }; | |
340 | function iframe(url, options, returnDeferred){ | |
341 | var response = util.parseArgs(url, util.deepCreate(defaultOptions, options), true); | |
342 | url = response.url; | |
343 | options = response.options; | |
344 | ||
345 | if(options.method !== 'GET' && options.method !== 'POST'){ | |
346 | throw new Error(options.method + ' not supported by dojo/request/iframe'); | |
347 | } | |
348 | ||
349 | if(!iframe._frame){ | |
350 | iframe._frame = iframe.create(iframe._iframeName, onload + '();'); | |
351 | } | |
352 | ||
353 | var dfd = util.deferred(response, null, isValid, isReady, handleResponse, last); | |
354 | dfd._callNext = function(){ | |
355 | if(!this._calledNext){ | |
356 | this._calledNext = true; | |
357 | iframe._currentDfd = null; | |
358 | iframe._fireNextRequest(); | |
359 | } | |
360 | }; | |
361 | dfd._legacy = returnDeferred; | |
362 | ||
363 | iframe._dfdQueue.push(dfd); | |
364 | iframe._fireNextRequest(); | |
365 | ||
366 | watch(dfd); | |
367 | ||
368 | return returnDeferred ? dfd : dfd.promise; | |
369 | } | |
370 | ||
371 | /*===== | |
372 | iframe = function(url, options){ | |
373 | // summary: | |
374 | // Sends a request using an iframe element with the given URL and options. | |
375 | // url: String | |
376 | // URL to request | |
377 | // options: dojo/request/iframe.__Options? | |
378 | // Options for the request. | |
379 | // returns: dojo/request.__Promise | |
380 | }; | |
381 | iframe.__BaseOptions = declare(request.__BaseOptions, { | |
382 | // form: DOMNode? | |
383 | // A form node to use to submit data to the server. | |
384 | // data: String|Object? | |
385 | // Data to transfer. When making a GET request, this will | |
386 | // be converted to key=value parameters and appended to the | |
387 | // URL. | |
388 | }); | |
389 | iframe.__MethodOptions = declare(null, { | |
390 | // method: String? | |
391 | // The HTTP method to use to make the request. Must be | |
392 | // uppercase. Only `"GET"` and `"POST"` are accepted. | |
393 | // Default is `"POST"`. | |
394 | }); | |
395 | iframe.__Options = declare([iframe.__BaseOptions, iframe.__MethodOptions]); | |
396 | ||
397 | iframe.get = function(url, options){ | |
398 | // summary: | |
399 | // Send an HTTP GET request using an iframe element with the given URL and options. | |
400 | // url: String | |
401 | // URL to request | |
402 | // options: dojo/request/iframe.__BaseOptions? | |
403 | // Options for the request. | |
404 | // returns: dojo/request.__Promise | |
405 | }; | |
406 | iframe.post = function(url, options){ | |
407 | // summary: | |
408 | // Send an HTTP POST request using an iframe element with the given URL and options. | |
409 | // url: String | |
410 | // URL to request | |
411 | // options: dojo/request/iframe.__BaseOptions? | |
412 | // Options for the request. | |
413 | // returns: dojo/request.__Promise | |
414 | }; | |
415 | =====*/ | |
416 | iframe.create = create; | |
417 | iframe.doc = doc; | |
418 | iframe.setSrc = setSrc; | |
419 | ||
420 | // TODO: Make these truly private in 2.0 | |
421 | iframe._iframeName = mid + '_IoIframe'; | |
422 | iframe._notifyStart = function(){}; | |
423 | iframe._dfdQueue = []; | |
424 | iframe._currentDfd = null; | |
425 | iframe._fireNextRequest = fireNextRequest; | |
426 | ||
427 | util.addCommonMethods(iframe, ['GET', 'POST']); | |
428 | ||
429 | return iframe; | |
430 | }); |