]> git.wh0rd.org - tt-rss.git/blame - lib/dojo/io/iframe.js
build custom layer of Dojo to speed up loading of tt-rss (refs #293)
[tt-rss.git] / lib / dojo / io / iframe.js
CommitLineData
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
8if(!dojo._hasResource["dojo.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9dojo._hasResource["dojo.io.iframe"] = true;
2f01fe57 10dojo.provide("dojo.io.iframe");
a089699c
AD
11
12/*=====
13dojo.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
51dojo.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}