1 /** 2 * JET (Javascript Extension Tools) 3 * Copyright (c) 2009, KDV.cn, All rights reserved. 4 * Code licensed under the BSD License: 5 * http://developer.kdv.cn/jet/license.txt 6 * 7 * @fileOverview Jx! 8 * @version 1.0 9 * @author Kinvix(<a href="mailto:Kinvix@gmail.com">Kinvix@gmail.com</a>) 10 * @description 11 * 12 */ 13 14 /** 15 * @description 16 * Package: jet.http 17 * 18 * Need package: 19 * jet.core.js 20 * 21 */ 22 23 /** 24 * 1.[Browser part]: http 包,含有ajax,comet,loadScript,loadCss封装 25 */ 26 Jx().$package(function(J){ 27 var $=J.dom.id, 28 $D=J.dom, 29 $E=J.event, 30 ajax, 31 comet, 32 load, 33 loadCss, 34 loadScript, 35 formSend; 36 37 // 兼容不同浏览器的 Adapter 适配层 38 if(typeof window.XMLHttpRequest === "undefined"){ 39 /** 40 * @ignore 41 */ 42 window.XMLHttpRequest = function(){ 43 return new window.ActiveXObject(navigator.userAgent.indexOf("MSIE 5") >=0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP"); 44 }; 45 } 46 47 /** 48 * http 名字空间 49 * 50 * @namespace 51 * @name http 52 */ 53 J.http = J.http || {}; 54 55 /** 56 * 这是Ajax对象名字空间的一个方法 57 * 58 * @memberOf http 59 * @method ajax 60 * 61 * @param {String} uri 要加载的数据的uri 62 * @param {Object} option 配置对象,如:isAsync,data,arguments,onSuccess,onError,onComplete,onTimeout,timeout,contentType,type 63 * @return {Object} ajax 返回一个ajax对象,可以abort掉 64 */ 65 ajax = function(uri, option){ 66 var httpRequest, 67 httpSuccess, 68 timeout, 69 isTimeout = false, 70 isComplete = false; 71 72 option = { 73 method: (option.method || "GET").toUpperCase(), 74 data: option.data || null, 75 arguments: option.arguments || null, 76 77 onSuccess: option.onSuccess || function(){}, 78 onError: option.onError || function(){}, 79 onComplete: option.onComplete || function(){}, 80 //尚未测试 81 onTimeout: option.onTimeout || function(){}, 82 83 isAsync: option.isAsync || true, 84 timeout: option.timeout || 30000, 85 contentType: option.contentType, 86 type: option.type || "xml" 87 }; 88 if(option.data && typeof option.data === "object"){ 89 option.data = J.string.toQueryString(option.data); 90 } 91 92 uri = uri || ""; 93 timeout = option.timeout; 94 95 httpRequest = new window.XMLHttpRequest(); 96 97 /** 98 * @ignore 99 */ 100 httpSuccess = function(r){ 101 try{ 102 return (!r.status && location.protocol == "file:") 103 || (r.status>=200 && r.status<300) 104 || (r.status==304) 105 || (navigator.userAgent.indexOf("Safari")>-1 && typeof r.status=="undefined"); 106 }catch(e){ 107 //J.out("错误:[" + e.name + "] "+e.message+", " + e.fileName+", 行号:"+e.lineNumber+"; stack:"+typeof e.stack, 2); 108 } 109 return false; 110 } 111 112 /** 113 * @ignore 114 */ 115 httpRequest.onreadystatechange=function (){ 116 if(httpRequest.readyState==4){ 117 if(!isTimeout){ 118 var o={}; 119 o.responseText = httpRequest.responseText; 120 o.responseXML = httpRequest.responseXML; 121 o.data= option.data; 122 o.status= httpRequest.status; 123 o.uri=uri; 124 o.arguments=option.arguments; 125 if(option.type === 'json'){ 126 try{ 127 o.responseJSON = J.json.parse(httpRequest.responseText); 128 }catch(e){ 129 } 130 } 131 if(httpSuccess(httpRequest)){ 132 option.onSuccess(o); 133 }else{ 134 option.onError(o); 135 } 136 option.onComplete(o); 137 } 138 isComplete = true; 139 //删除对象,防止内存溢出 140 httpRequest=null; 141 } 142 }; 143 144 if(option.method === "GET"){ 145 if(option.data){ 146 uri += (uri.indexOf("?")>-1?"&":"?") + option.data; 147 option.data = null; 148 } 149 httpRequest.open("GET", uri, option.isAsync); 150 httpRequest.setRequestHeader("Content-Type",option.contentType || "text/plain;charset=UTF-8"); 151 httpRequest.send(); 152 }else if(option.method === "POST"){ 153 httpRequest.open("POST", uri, option.isAsync); 154 httpRequest.setRequestHeader("Content-Type",option.contentType || "application/x-www-form-urlencoded;charset=UTF-8"); 155 httpRequest.send(option.data); 156 }else{ 157 httpRequest.open(option.method, uri, option.isAsync); 158 httpRequest.send(); 159 } 160 161 window.setTimeout(function(){ 162 var o; 163 if(!isComplete){ 164 isTimeout = true; 165 o={}; 166 o.uri=uri; 167 o.arguments=option.arguments; 168 option.onTimeout(o); 169 option.onComplete(o); 170 } 171 }, timeout); 172 173 return httpRequest; 174 }; 175 176 177 // /** 178 // * comet方法 179 // * 180 // * @memberOf http 181 // * @method comet 182 // * @param {String} uri uri地址 183 // * @param {Object} option 配置对象 184 // * @return {Object} 返回一个comet dom对象 185 // */ 186 // comet = function(uri, option){ 187 188 // uri = uri || ""; 189 // option = { 190 // method : option.method || "GET", 191 // data : option.data || null, 192 // arguments : option.arguments || null, 193 // callback : option.callback || function(){}, 194 // onLoad : option.onLoad || function(){}, 195 196 // contentType: option.contentType ? option.contentType : "utf-8" 197 // }; 198 199 // var connection; 200 // if(J.browser.ie){ 201 // var htmlfile = new ActiveXObject("htmlfile"); 202 // htmlfile.open(); 203 // htmlfile.close(); 204 // var iframediv = htmlfile.createElement("div"); 205 // htmlfile.appendChild(iframediv); 206 // htmlfile.parentWindow._parent = self; 207 // iframediv.innerHTML = '<iframe id="_cometIframe" src="'+uri+'?callback=window.parent._parent.'+option.callback+'"></iframe>'; 208 209 // connection = htmlfile.getElementById("_cometIframe"); 210 211 // } 212 // else{ 213 // connection = $D.node("iframe"); 214 // connection.setAttribute("id", "_cometIframe"); 215 // connection.setAttribute("src", uri+'?callback=window.parent._parent.'+option.callback); 216 // connection.style.position = "absolute"; 217 // connection.style.visibility = "hidden"; 218 // connection.style.left = connection.style.top = "-999px"; 219 // connection.style.width = connection.style.height = "1px"; 220 // document.body.appendChild(connection); 221 // self._parent = self; 222 // }; 223 224 // $E.on(connection,"load", option.onLoad); 225 226 // return connection; 227 228 // }; 229 230 231 232 233 234 235 /** 236 * 这是load方法 237 * 238 * @memberOf http 239 * @method load 240 * 241 * @param {String} type 一个配置对象 242 * @param {Object} option 一个配置对象 243 * @return {Object} ajax 返回一个ajax对象 244 */ 245 load = function(type, uri, option){ 246 var node, 247 linkNode, 248 scriptNode, 249 id, 250 head = document.getElementsByTagName("head") ? document.getElementsByTagName("head")[0] : document.documentElement, 251 timer, 252 isTimeout = false, 253 isComplete = false, 254 option = option || {}, 255 isDefer = option.isDefer || false, 256 query = option.query || null, 257 arguments = option.arguments || null, 258 259 onSuccess = option.onSuccess || function(){}, 260 onError = option.onError || function(){}, 261 onComplete = option.onComplete || function(){}, 262 purge, 263 //尚未测试 264 onTimeout = option.onTimeout || function(){}, 265 266 // timeout = option.timeout ? option.timeout : 10000, 267 timeout = option.timeout, //az 2011-2-21 修改为默认不需要超时 268 charset = option.charset ? option.charset : "utf-8", 269 win = option.win || window, 270 o, 271 272 getId; 273 274 uri = uri || ""; 275 if(query !== null){ 276 uri = uri + "?" + query; 277 } 278 /** 279 * @ignore 280 */ 281 getId = function(){ 282 return load.Id++; 283 }; 284 id = getId(); 285 286 /** 287 * @ignore 288 */ 289 purge = function(id){ 290 var el=$("jet_load_" + id) 291 if(el){ 292 head.removeChild(el); 293 } 294 }; 295 296 /** 297 * Generates a link node 298 * @method _linkNode 299 * @param uri {string} the uri for the css file 300 * @param win {Window} optional window to create the node in 301 * @return {HTMLElement} the generated node 302 * @private 303 */ 304 linkNode = function(uri, win, charset) { 305 var c = charset || "utf-8"; 306 return $D.node("link", { 307 "id": "jet_load_" + id, 308 "type": "text/css", 309 "charset": c, 310 "rel": "stylesheet", 311 "href": uri 312 }, win); 313 }; 314 315 /** 316 * Generates a script node 317 * @method _scriptNode 318 * @param uri {string} the uri for the script file 319 * @param win {Window} optional window to create the node in 320 * @return {HTMLElement} the generated node 321 * @private 322 */ 323 scriptNode = function(uri, win, charset, isDefer) { 324 var c = charset || "utf-8"; 325 var node = $D.node("script", { 326 "id": "jet_load_" + id, 327 "type": "text/javascript", 328 "charset": c, 329 "src": uri 330 }, win); 331 if(isDefer){ 332 node.setAttribute("defer", "defer"); 333 } 334 335 return node; 336 }; 337 338 339 340 if(type === "script"){ 341 node = option.node || scriptNode(uri, win, charset, isDefer); 342 }else if(type === "css"){ 343 node = option.node || linkNode(uri, win, charset); 344 } 345 346 347 if(J.browser.engine.trident && parseInt(J.browser.ie)<9){ 348 /** 349 * @ignore 350 */ 351 node.onreadystatechange = function() { 352 var rs = this.readyState; 353 if (rs === "loaded" || rs === "complete") { 354 /** 355 * @ignore 356 */ 357 node.onreadystatechange = null; 358 359 if(!isTimeout){ 360 isComplete = true; 361 window.clearTimeout(timer); 362 timer = null; 363 o={}; 364 o.id = id; 365 o.uri = uri; 366 o.arguments = arguments; 367 onSuccess(o); 368 onComplete(o); 369 //if(type === "script"){ 370 //purge(id); 371 //} 372 } 373 } 374 }; 375 376 // webkit prior to 3.x is no longer supported 377 }else if(J.browser.engine.webkit){ 378 // Safari 3.x supports the load event for script nodes (DOM2) 379 $E.on(node, "load", function(){ 380 var o; 381 if(!isTimeout){ 382 isComplete = true; 383 window.clearTimeout(timer); 384 timer = null; 385 o={}; 386 o.id = id; 387 o.uri = uri; 388 o.arguments = arguments; 389 onSuccess(o); 390 onComplete(o); 391 if(type === "script"){ 392 purge(id); 393 } 394 } 395 }); 396 397 398 // FireFox and Opera support onload (but not DOM2 in FF) handlers for 399 // script nodes. Opera, but not FF, supports the onload event for link 400 // nodes. 401 }else{ 402 /** 403 * @ignore 404 */ 405 node.onload = function(){ 406 var o; 407 //J.out("else:"+J.browser.engine.name); 408 if(!isTimeout){ 409 isComplete = true; 410 window.clearTimeout(timer); 411 timer = null; 412 o={}; 413 o.id = id; 414 o.uri = uri; 415 o.arguments = option.arguments; 416 onSuccess(o); 417 onComplete(o); 418 419 if(type === "script"){ 420 purge(id); 421 } 422 } 423 }; 424 /** 425 * @ignore 426 */ 427 node.onerror = function(e){ 428 var o; 429 //J.out("else:"+J.browser.engine.name); 430 if(!isTimeout){ 431 isComplete = true; 432 window.clearTimeout(timer); 433 timer = null; 434 o={}; 435 o.id = id; 436 o.uri = uri; 437 o.arguments = arguments; 438 o.error = e; 439 onError(o); 440 onComplete(o); 441 //if(type === "script"){ 442 purge(id); 443 //} 444 } 445 }; 446 } 447 448 449 if(option.node){ 450 if(type === "script"){ 451 node.src = uri; 452 }else if(type === "css"){ 453 node.href = uri; 454 } 455 }else{ 456 head.appendChild(node); 457 } 458 459 460 if(type === "script"){ 461 if(timeout){ 462 timer = window.setTimeout(function(){ 463 var o; 464 if(!isComplete){ 465 isTimeout = true; 466 o = {}; 467 o.uri = uri; 468 o.arguments = arguments; 469 onTimeout(o); 470 onComplete(o); 471 purge(id); 472 } 473 }, timeout); 474 } 475 } 476 /** 477 * @ignore 478 */ 479 var func = function(node){ 480 this._node = node; 481 this._head = head; 482 }; 483 func.prototype={ 484 /** 485 * @ignore 486 */ 487 abort:function(){ 488 this._node.src=""; 489 this._head.removeChild(this._node); 490 delete this._node; 491 } 492 493 }; 494 return new func(node); 495 }; 496 load.Id=0; 497 498 /** 499 * 加载CSS 500 * 501 * @memberOf http 502 * @method loadCss 503 * 504 * @param {String} uri 要加载的css的uri 505 * @param {Object} option 配置对象,如:isDefer,query,arguments,onSuccess,onError,onComplete,onTimeout,timeout,charset 506 * @return {Object} ajax 返回一个ajax对象 507 */ 508 loadCss = function(uri, option){ 509 return load("css", uri, option); 510 }; 511 512 /** 513 * 加载Javascript 514 * 515 * @memberOf http 516 * @method loadScript 517 * 518 * @param {String} uri 要加载的js脚本的uri 519 * @param {Object} option 配置对象,如:isDefer,query,arguments,onSuccess,onError,onComplete,onTimeout,timeout,charset 520 * @return {Element} 返回控制对象,可以abort掉 521 */ 522 loadScript = function(uri, option){ 523 return load("script", uri, option); 524 }; 525 526 527 528 /** 529 * TODO 这里的form send需要改造,建立一个iframe池,来处理并发问题 530 */ 531 /** 532 * @description formSend的iframe池,目前定为长度为2 533 * @type {Object} 534 */ 535 var divEl; 536 var formSendIframePool = { 537 /** 538 * @example 539 * [[divElement,formElement,iframeElement],[divElement,formElement,iframeElement],,,] 540 */ 541 _iframes: [], 542 _tick: 0, 543 /** 544 * 顺序返回一个iframe 545 */ 546 _select: function() { 547 this._tick++; 548 return this._iframes[(this._tick-1)%this._len]; 549 }, 550 /** 551 * @description 初始化 552 * @argument {Number} len the number of iframes in poll 553 */ 554 init: function(len) { 555 if(this._isInit==true) { 556 return; 557 } 558 this._len= len; 559 var bodyEl=document.body; 560 for(var i=0;i<len;i++) { 561 divEl = $D.node("div",{ 562 "class": "RPCService_hDiv" 563 }); 564 $D.hide(divEl); 565 divEl.innerHTML = '<iframe id="RPCService_hIframe_'+i+'" name="RPCService_hIframe_'+i+'" src="'+alloy.CONST.MAIN_URL+'domain.html"></iframe>'; 566 bodyEl.appendChild(divEl); 567 //not have a iframe yet 568 this._iframes[i]=[divEl,null,"RPCService_hIframe_"+i]; 569 } 570 this._isInit= true; 571 }, 572 /** 573 * @description 使用的入口 574 * @argument {Element} iframeEL 575 */ 576 take: function(formEl) { 577 var doms= this._select(); 578 //if iframe exist 579 if(doms[1]) { 580 doms[0].removeChild(doms[1]); 581 } 582 formEl.setAttribute("target",doms[2]); 583 doms[1]= formEl; 584 doms[0].appendChild(formEl); 585 } 586 }; 587 /** 588 * 使用form请求数据 589 * @memberOf http 590 * @param {String} url 591 * @param {Object} option 请求参数 592 */ 593 formSend = function(url, option){ 594 formSendIframePool.init(2); 595 var opt = { 596 method: option.method || "GET", 597 enctype: option.enctype || "", //"multipart/form-data", 598 data: option.data || {}, //表单项 599 //尚未测试 600 onSuccess: option.onSuccess || function(){}, //iframe 载入成功回调,区别与获取数据成功 601 onError: option.onError || function(){}, //iframe 载入失败回调 602 onComplete: option.onComplete || function(){}, 603 604 onTimeout: option.onTimeout || function(){}, 605 timeout: option.timeout ? option.timeout : 10000 606 }; 607 var formEl = $D.node("form",{ 608 "class": "RPCService_form", 609 method: opt.method, 610 action: url+"?t=" + (new Date().getTime()), 611 enctype: opt.enctype 612 }) 613 614 if(Object.prototype.toString.call(opt.data).indexOf("String")>-1) { 615 var inputEl=$D.node("input"); 616 inputEl.type="text"; 617 inputEl.name=opt.data; 618 formEl.appendChild(inputEl); 619 }else { 620 for(var p in opt.data){ 621 var inputEl=$D.node("input"); 622 inputEl.type="text"; 623 inputEl.name=p; 624 inputEl.setAttribute("value",opt.data[p]); 625 formEl.appendChild(inputEl); 626 } 627 } 628 formSendIframePool.take(formEl); 629 formEl.submit(); 630 631 /* 632 iframe事件未处理,当载入成功会自动调用回调函数 633 var iframeEl = $D.id("RPCService_hIframe"); 634 $E.on(iframeEl, "load", opt.onSuccess); 635 oFrm.onload = oFrm.onreadystatechange = function() { 636 if (this.readyState && this.readyState != 'complete') return; 637 else { 638 onComplete(); 639 } 640 */ 641 }; 642 643 644 645 J.http.ajax = ajax; 646 J.http.comet = comet; 647 J.http.load = load; 648 J.http.loadCss = loadCss; 649 J.http.loadScript = loadScript; 650 J.http.formSend = formSend; 651 }); 652 653 654 655