1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to you under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** 18 * @class 19 * @name IFrame 20 * @memberOf myfaces._impl.xhrCore.engine 21 * @extends myfaces._impl.xhrCore.engine.BaseRequest 22 * @description 23 * 24 * wrapper for an iframe transport object with all its differences 25 * it emulates the xhr level2 api 26 */ 27 _MF_CLS(_PFX_XHR + "engine.IFrame", myfaces._impl.xhrCore.engine.BaseRequest, 28 /** @lends myfaces._impl.xhrCore.engine.IFrame.prototype */ 29 { 30 31 _finalized: false, 32 33 /*the target frame responsible for the communication*/ 34 _frame: null, 35 //_requestHeader: null, 36 _aborted: false, 37 38 CLS_NAME: "myfaces._impl.xhrCore._IFrameRequest", 39 _FRAME_ID: "_mf_comm_frm", 40 41 /** 42 * constructor which shifts the arguments 43 * to the protected properties of this clas 44 * 45 * @param args 46 */ 47 constructor_: function (args) { 48 //we fetch in the standard arguments 49 50 this._callSuper("constructor", args); 51 52 this._initDefaultFinalizableFields(); 53 //this._requestHeader = {}; 54 55 this._XHRConst = myfaces._impl.xhrCore.engine.XhrConst; 56 57 this._Lang.applyArgs(this, args); 58 this.readyState = this._XHRConst.READY_STATE_UNSENT; 59 this._startTimeout(); 60 }, 61 62 setRequestHeader: function (key, value) { 63 //this._requestHeader[key] = value; 64 }, 65 66 open: function (method, url, async) { 67 68 this.readyState = this._XHRConst.READY_STATE_OPENED; 69 70 var _RT = myfaces._impl.core._Runtime; 71 var _Lang = this._Lang; 72 73 this._frame = this._createTransportFrame(); 74 75 //we append an onload handler to the frame 76 //to cover the starting and loading events, 77 //timeouts cannot be covered in a cross browser way 78 79 //we point our onload handler to the frame, we do not use addOnLoad 80 //because the frame should not have other onload handlers in place 81 if (!_RT.browser.isIE || this._Dom.isDomCompliant()) { 82 this._frame.onload = _Lang.hitch(this, this._callback); 83 } else { 84 //ie has a bug, onload is not settable outside of innerHTML on iframes 85 this._frame.onload_IE = _Lang.hitch(this, this._callback); 86 } 87 88 this.method = method || this.method; 89 this.url = url || this.url; 90 this.async = ('undefined' != typeof async) ? async : this.async; 91 92 var myevt = {}; 93 this._addProgressAttributes(myevt, 10, 100); 94 this.onprogress(myevt); 95 }, 96 97 send: function (formData) { 98 99 var myevt = {}; 100 this._addProgressAttributes(myevt, 20, 100); 101 this.onloadstart(myevt); 102 this.onprogress(myevt); 103 104 var formDataForm = formData.form, 105 oldTarget = formDataForm.target, 106 oldMethod = formDataForm.method, 107 oldAction = formDataForm.action; 108 109 try { 110 //_t._initAjaxParams(); 111 //for (var key in this._requestHeader) { 112 // formData.append(key, this._requestHeader[key]); 113 //} 114 115 formDataForm.target = this._frame.name; 116 formDataForm.method = this.method; 117 if (this.url) { 118 formDataForm.action = this.url; 119 } 120 this.readyState = this._XHRConst.READY_STATE_LOADING; 121 this.onreadystatechange(myevt); 122 formDataForm.submit(); 123 } finally { 124 formDataForm.action = oldAction; 125 formDataForm.target = oldTarget; 126 formDataForm.method = oldMethod; 127 128 formData._finalize(); 129 //alert("finalizing"); 130 this._finalized = true; 131 } 132 }, 133 134 /*we can implement it, but it will work only on browsers 135 * which have asynchronous iframe loading*/ 136 abort: function () { 137 this._aborted = true; 138 this.onabort({}); 139 }, 140 141 _addProgressAttributes: function (evt, percent, total) { 142 //http://www.w3.org/TR/progress-events/#progressevent 143 evt.lengthComputable = true; 144 evt.loaded = percent; 145 evt.total = total; 146 147 }, 148 149 _callback: function () { 150 //------------------------------------ 151 // we are asynchronous which means we 152 // have to check wether our code 153 // is finalized or not 154 //------------------------------------ 155 if (this._aborted) return; 156 if (this._timeoutTimer) { 157 clearTimeout(this._timeoutTimer); 158 } 159 if (!this._finalized) { 160 setTimeout(this._Lang.hitch(this, this._callback), 10); 161 return; 162 } 163 //aborted no further processing 164 165 try { 166 var myevt = {}; 167 168 this._addProgressAttributes(myevt, 100, 100); 169 //this.readyState = this._XHRConst.READY_STATE_DONE; 170 //this.onreadystatechange(myevt); 171 172 this.responseText = this._getFrameText(); 173 this.responseXML = this._getFrameXml(); 174 this.readyState = this._XHRConst.READY_STATE_DONE; 175 176 //TODO status and statusText 177 178 this.onreadystatechange(myevt); 179 this.onloadend(); 180 181 if (!this._Lang.isXMLParseError(this.responseXML)) { 182 this.status = 201; 183 this.onload(); 184 } else { 185 this.status = 0; 186 //we simulate the request for our xhr call 187 this.onerror(); 188 } 189 190 } finally { 191 this._frame = null; 192 } 193 }, 194 195 /** 196 * returns the frame text in a browser independend manner 197 */ 198 _getFrameDocument: function () { 199 200 //we cover various browsers here, because almost all browsers keep the document in a different 201 //position 202 return this._frame.contentWindow.document || this._frame.contentDocument || this._frame.document; 203 }, 204 205 _getFrameText: function () { 206 var framedoc = this._getFrameDocument(); 207 //also ie keeps the body in framedoc.body the rest in documentElement 208 var body = framedoc.body || framedoc.documentElement; 209 return body.innerHTML; 210 }, 211 212 _clearFrame: function () { 213 214 var framedoc = this._getFrameDocument(); 215 var body = framedoc.documentElement || framedoc.body; 216 //ie8 in 7 mode chokes on the innerHTML method 217 //direct dom removal is less flakey and works 218 //over all browsers, but is slower 219 if (myfaces._impl.core._Runtime.browser.isIE) { 220 this._Dom._removeChildNodes(body, false); 221 } else { 222 body.innerHTML = ""; 223 } 224 }, 225 226 /** 227 * returns the processed xml from the frame 228 */ 229 _getFrameXml: function () { 230 var framedoc = this._getFrameDocument(); 231 //same situation here, the xml is hosted either in xmlDocument or 232 //is located directly under the frame document 233 return framedoc.XMLDocument || framedoc; 234 }, 235 236 _createTransportFrame: function () { 237 238 var _FRM_ID = this._FRAME_ID; 239 var frame = document.getElementById(_FRM_ID); 240 if (frame) return frame; 241 //normally this code should not be called 242 //but just to be sure 243 244 if (this._Dom.isDomCompliant()) { 245 frame = this._Dom.createElement('iframe', { 246 "src": "about:blank", 247 "id": _FRM_ID, 248 "name": _FRM_ID, 249 "type": "content", 250 "collapsed": "true", 251 "style": "display:none" 252 }); 253 254 //probably the ie method would work on all browsers 255 //but this code is the safe bet it works on all standards 256 //compliant browsers in a clean manner 257 258 document.body.appendChild(frame); 259 } else { //Now to the non compliant browsers 260 var node = this._Dom.createElement("div", { 261 "style": "display:none" 262 }); 263 264 //we are dealing with two well known iframe ie bugs here 265 //first the iframe has to be set via innerHTML to be present 266 //secondly the onload handler is immutable on ie, we have to 267 //use a dummy onload handler in this case and call this one 268 //from the onload handler 269 node.innerHTML = "<iframe id='" + _FRM_ID + "' name='" + _FRM_ID + "' style='display:none;' src='about:blank' type='content' onload='this.onload_IE();' ></iframe>"; 270 271 //avoid the ie open tag problem 272 var body = document.body; 273 if (body.firstChild) { 274 body.insertBefore(node, document.body.firstChild); 275 } else { 276 body.appendChild(node); 277 } 278 } 279 280 //helps to for the onload handlers and innerhtml to be in sync again 281 return document.getElementById(_FRM_ID); 282 }, 283 284 _startTimeout: function () { 285 286 if (this.timeout == 0) return; 287 this._timeoutTimer = setTimeout(this._Lang.hitch(this, function () { 288 if (this._xhrObject.readyState != this._XHRConst.READY_STATE_DONE) { 289 290 this._aborted = true; 291 clearTimeout(this._timeoutTimer); 292 //we cannot abort an iframe request 293 this.ontimeout({}); 294 this._timeoutTimer = null; 295 } 296 }), this.timeout); 297 } 298 }); 299