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 32 33 /*the target frame responsible for the communication*/ 34 _frame: null, 35 _requestHeader: null, 36 _aborted: false, 37 38 39 CLS_NAME: "myfaces._impl.xhrCore._IFrameRequest", 40 _FRAME_ID: "_mf_comm_frm", 41 42 /** 43 * constructor which shifts the arguments 44 * to the protected properties of this clas 45 * 46 * @param arguments 47 */ 48 constructor_: function(arguments) { 49 //we fetch in the standard arguments 50 51 this._callSuper("constructor", arguments); 52 53 this._initDefaultFinalizableFields(); 54 this._requestHeader = {}; 55 56 this._XHRConst = myfaces._impl.xhrCore.engine.XhrConst; 57 58 this._Lang.applyArgs(this, arguments); 59 this.readyState = this._XHRConst.READY_STATE_UNSENT; 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 110 try { 111 //_t._initAjaxParams(); 112 for (var key in this._requestHeader) { 113 formData.append(key, this._requestHeader[key]); 114 } 115 116 formDataForm.target = this._frame.name; 117 formDataForm.method = this.method; 118 if (this.url) { 119 formDataForm.action = this.url; 120 } 121 this.readyState = this._XHRConst.READY_STATE_LOADING; 122 this.onreadystatechange(myevt); 123 formDataForm.submit(); 124 } finally { 125 formDataForm.action = oldAction; 126 formDataForm.target = oldTarget; 127 formDataForm.method = oldMethod; 128 129 formData._finalize(); 130 } 131 }, 132 133 /*we can implement it, but it will work only on browsers 134 * which have asynchronous iframe loading*/ 135 abort: function() { 136 this._aborted = true; 137 this.onabort({}); 138 }, 139 140 _addProgressAttributes: function(evt, percent, total) { 141 //http://www.w3.org/TR/progress-events/#progressevent 142 evt.lengthComputable = true; 143 evt.loaded = percent; 144 evt.total = total; 145 146 }, 147 148 _callback: function() { 149 150 //aborted no further processing 151 if (this._aborted) return; 152 try { 153 var myevt = {}; 154 155 this._addProgressAttributes(myevt, 100, 100); 156 this.readyState = this._XHRConst.READY_STATE_DONE; 157 this.onreadystatechange(myevt); 158 159 this.responseText = this._getFrameText(); 160 this.responseXML = this._getFrameXml(); 161 this.readyState = this._READY_STATE_DONE; 162 163 //TODO status and statusText 164 165 this.onreadystatechange(myevt); 166 this.onloadend(); 167 168 if (!this._Lang.isXMLParseError(this.responseXML)) { 169 this.status = 201; 170 this.onload(); 171 } else { 172 this.status = 0; 173 //we simulate the request for our xhr call 174 this.onerror(); 175 } 176 177 } finally { 178 this._frame = null; 179 } 180 }, 181 182 /** 183 * returns the frame text in a browser independend manner 184 */ 185 _getFrameDocument: function() { 186 187 //we cover various browsers here, because almost all browsers keep the document in a different 188 //position 189 return this._frame.contentWindow.document || this._frame.contentDocument || this._frame.document; 190 }, 191 192 _getFrameText: function() { 193 var framedoc = this._getFrameDocument(); 194 //also ie keeps the body in framedoc.body the rest in documentElement 195 var body = framedoc.body || framedoc.documentElement; 196 return body.innerHTML; 197 }, 198 199 _clearFrame: function() { 200 201 var framedoc = this._getFrameDocument(); 202 var body = framedoc.documentElement || framedoc.body; 203 //ie8 in 7 mode chokes on the innerHTML method 204 //direct dom removal is less flakey and works 205 //over all browsers, but is slower 206 if (myfaces._impl.core._Runtime.browser.isIE) { 207 this._Dom._removeChildNodes(body, false); 208 } else { 209 body.innerHTML = ""; 210 } 211 }, 212 213 /** 214 * returns the processed xml from the frame 215 */ 216 _getFrameXml: function() { 217 var framedoc = this._getFrameDocument(); 218 //same situation here, the xml is hosted either in xmlDocument or 219 //is located directly under the frame document 220 return framedoc.XMLDocument || framedoc; 221 }, 222 223 _createTransportFrame: function() { 224 225 var _FRM_ID = this._FRAME_ID; 226 var frame = document.getElementById(_FRM_ID); 227 if (frame) return frame; 228 //normally this code should not be called 229 //but just to be sure 230 231 if (this._Dom.isDomCompliant()) { 232 frame = this._Dom.createElement('iframe', { 233 "src": "about:blank", 234 "id": _FRM_ID, 235 "name": _FRM_ID, 236 "type": "content", 237 "collapsed": "true", 238 "style": "display:none" 239 }); 240 241 //probably the ie method would work on all browsers 242 //but this code is the safe bet it works on all standards 243 //compliant browsers in a clean manner 244 245 document.body.appendChild(frame); 246 } else { //Now to the non compliant browsers 247 var node = this._Dom.createElement("div", { 248 "style": "display:none" 249 }); 250 251 //we are dealing with two well known iframe ie bugs here 252 //first the iframe has to be set via innerHTML to be present 253 //secondly the onload handler is immutable on ie, we have to 254 //use a dummy onload handler in this case and call this one 255 //from the onload handler 256 node.innerHTML = "<iframe id='" + _FRM_ID + "' name='" + _FRM_ID + "' style='display:none;' src='about:blank' type='content' onload='this.onload_IE();' ></iframe>"; 257 258 //avoid the ie open tag problem 259 var body = document.body; 260 if (body.firstChild) { 261 body.insertBefore(node, document.body.firstChild); 262 } else { 263 body.appendChild(node); 264 } 265 } 266 267 //helps to for the onload handlers and innerhtml to be in sync again 268 return document.getElementById(_FRM_ID); 269 }, 270 271 _startTimeout: function() { 272 273 if (this.timeout == 0) return; 274 this._timeoutTimer = setTimeout(this._Lang.hitch(this, function() { 275 if (this._xhrObject.readyState != this._XHRConst.READY_STATE_DONE) { 276 277 this._aborted = true; 278 clearTimeout(this._timeoutTimer); 279 //we cannot abort an iframe request 280 this.ontimeout({}); 281 this._timeoutTimer = null; 282 } 283 }), this.timeout); 284 } 285 }); 286