[483] | 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 | }); |
---|