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