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