[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('yui2-connectioncore', function(Y) { Y.use('yui2-connection'); }, '3.3.0' ,{"requires": ["yui2-yahoo", "yui2-event"]}); 2 YUI.add('yui2-connection', function(Y) { 3 var YAHOO = Y.YUI2; 4 /* 5 Copyright (c) 2011, Yahoo! Inc. All rights reserved. 6 Code licensed under the BSD License: 7 http://developer.yahoo.com/yui/license.html 8 version: 2.9.0 9 */ 10 /** 11 * The Connection Manager provides a simplified interface to the XMLHttpRequest 12 * object. It handles cross-browser instantiantion of XMLHttpRequest, negotiates the 13 * interactive states and server response, returning the results to a pre-defined 14 * callback you create. 15 * 16 * @namespace YAHOO.util 17 * @module connection 18 * @requires yahoo 19 * @requires event 20 */ 21 22 /** 23 * The Connection Manager singleton provides methods for creating and managing 24 * asynchronous transactions. 25 * 26 * @class YAHOO.util.Connect 27 */ 28 29 YAHOO.util.Connect = 30 { 31 /** 32 * @description Array of MSFT ActiveX ids for XMLHttpRequest. 33 * @property _msxml_progid 34 * @private 35 * @static 36 * @type array 37 */ 38 _msxml_progid:[ 39 'Microsoft.XMLHTTP', 40 'MSXML2.XMLHTTP.3.0', 41 'MSXML2.XMLHTTP' 42 ], 43 44 /** 45 * @description Object literal of HTTP header(s) 46 * @property _http_header 47 * @private 48 * @static 49 * @type object 50 */ 51 _http_headers:{}, 52 53 /** 54 * @description Determines if HTTP headers are set. 55 * @property _has_http_headers 56 * @private 57 * @static 58 * @type boolean 59 */ 60 _has_http_headers:false, 61 62 /** 63 * @description Determines if a default header of 64 * Content-Type of 'application/x-www-form-urlencoded' 65 * will be added to any client HTTP headers sent for POST 66 * transactions. 67 * @property _use_default_post_header 68 * @private 69 * @static 70 * @type boolean 71 */ 72 _use_default_post_header:true, 73 74 /** 75 * @description The default header used for POST transactions. 76 * @property _default_post_header 77 * @private 78 * @static 79 * @type boolean 80 */ 81 _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8', 82 83 /** 84 * @description The default header used for transactions involving the 85 * use of HTML forms. 86 * @property _default_form_header 87 * @private 88 * @static 89 * @type boolean 90 */ 91 _default_form_header:'application/x-www-form-urlencoded', 92 93 /** 94 * @description Determines if a default header of 95 * 'X-Requested-With: XMLHttpRequest' 96 * will be added to each transaction. 97 * @property _use_default_xhr_header 98 * @private 99 * @static 100 * @type boolean 101 */ 102 _use_default_xhr_header:true, 103 104 /** 105 * @description The default header value for the label 106 * "X-Requested-With". This is sent with each 107 * transaction, by default, to identify the 108 * request as being made by YUI Connection Manager. 109 * @property _default_xhr_header 110 * @private 111 * @static 112 * @type boolean 113 */ 114 _default_xhr_header:'XMLHttpRequest', 115 116 /** 117 * @description Determines if custom, default headers 118 * are set for each transaction. 119 * @property _has_default_header 120 * @private 121 * @static 122 * @type boolean 123 */ 124 _has_default_headers:true, 125 126 /** 127 * @description Property modified by setForm() to determine if the data 128 * should be submitted as an HTML form. 129 * @property _isFormSubmit 130 * @private 131 * @static 132 * @type boolean 133 */ 134 _isFormSubmit:false, 135 136 /** 137 * @description Determines if custom, default headers 138 * are set for each transaction. 139 * @property _has_default_header 140 * @private 141 * @static 142 * @type boolean 143 */ 144 _default_headers:{}, 145 146 /** 147 * @description Collection of polling references to the polling mechanism in handleReadyState. 148 * @property _poll 149 * @private 150 * @static 151 * @type object 152 */ 153 _poll:{}, 154 155 /** 156 * @description Queue of timeout values for each transaction callback with a defined timeout value. 157 * @property _timeOut 158 * @private 159 * @static 160 * @type object 161 */ 162 _timeOut:{}, 163 164 /** 165 * @description The polling frequency, in milliseconds, for HandleReadyState. 166 * when attempting to determine a transaction's XHR readyState. 167 * The default is 50 milliseconds. 168 * @property _polling_interval 169 * @private 170 * @static 171 * @type int 172 */ 173 _polling_interval:50, 174 175 /** 176 * @description A transaction counter that increments the transaction id for each transaction. 177 * @property _transaction_id 178 * @private 179 * @static 180 * @type int 181 */ 182 _transaction_id:0, 183 184 /** 185 * @description Custom event that fires at the start of a transaction 186 * @property startEvent 187 * @private 188 * @static 189 * @type CustomEvent 190 */ 191 startEvent: new YAHOO.util.CustomEvent('start'), 192 193 /** 194 * @description Custom event that fires when a transaction response has completed. 195 * @property completeEvent 196 * @private 197 * @static 198 * @type CustomEvent 199 */ 200 completeEvent: new YAHOO.util.CustomEvent('complete'), 201 202 /** 203 * @description Custom event that fires when handleTransactionResponse() determines a 204 * response in the HTTP 2xx range. 205 * @property successEvent 206 * @private 207 * @static 208 * @type CustomEvent 209 */ 210 successEvent: new YAHOO.util.CustomEvent('success'), 211 212 /** 213 * @description Custom event that fires when handleTransactionResponse() determines a 214 * response in the HTTP 4xx/5xx range. 215 * @property failureEvent 216 * @private 217 * @static 218 * @type CustomEvent 219 */ 220 failureEvent: new YAHOO.util.CustomEvent('failure'), 221 222 /** 223 * @description Custom event that fires when a transaction is successfully aborted. 224 * @property abortEvent 225 * @private 226 * @static 227 * @type CustomEvent 228 */ 229 abortEvent: new YAHOO.util.CustomEvent('abort'), 230 231 /** 232 * @description A reference table that maps callback custom events members to its specific 233 * event name. 234 * @property _customEvents 235 * @private 236 * @static 237 * @type object 238 */ 239 _customEvents: 240 { 241 onStart:['startEvent', 'start'], 242 onComplete:['completeEvent', 'complete'], 243 onSuccess:['successEvent', 'success'], 244 onFailure:['failureEvent', 'failure'], 245 onUpload:['uploadEvent', 'upload'], 246 onAbort:['abortEvent', 'abort'] 247 }, 248 249 /** 250 * @description Member to add an ActiveX id to the existing xml_progid array. 251 * In the event(unlikely) a new ActiveX id is introduced, it can be added 252 * without internal code modifications. 253 * @method setProgId 254 * @public 255 * @static 256 * @param {string} id The ActiveX id to be added to initialize the XHR object. 257 * @return void 258 */ 259 setProgId:function(id) 260 { 261 this._msxml_progid.unshift(id); 262 }, 263 264 /** 265 * @description Member to override the default POST header. 266 * @method setDefaultPostHeader 267 * @public 268 * @static 269 * @param {boolean} b Set and use default header - true or false . 270 * @return void 271 */ 272 setDefaultPostHeader:function(b) 273 { 274 if(typeof b == 'string'){ 275 this._default_post_header = b; 276 this._use_default_post_header = true; 277 278 } 279 else if(typeof b == 'boolean'){ 280 this._use_default_post_header = b; 281 } 282 }, 283 284 /** 285 * @description Member to override the default transaction header.. 286 * @method setDefaultXhrHeader 287 * @public 288 * @static 289 * @param {boolean} b Set and use default header - true or false . 290 * @return void 291 */ 292 setDefaultXhrHeader:function(b) 293 { 294 if(typeof b == 'string'){ 295 this._default_xhr_header = b; 296 } 297 else{ 298 this._use_default_xhr_header = b; 299 } 300 }, 301 302 /** 303 * @description Member to modify the default polling interval. 304 * @method setPollingInterval 305 * @public 306 * @static 307 * @param {int} i The polling interval in milliseconds. 308 * @return void 309 */ 310 setPollingInterval:function(i) 311 { 312 if(typeof i == 'number' && isFinite(i)){ 313 this._polling_interval = i; 314 } 315 }, 316 317 /** 318 * @description Instantiates a XMLHttpRequest object and returns an object with two properties: 319 * the XMLHttpRequest instance and the transaction id. 320 * @method createXhrObject 321 * @private 322 * @static 323 * @param {int} transactionId Property containing the transaction id for this transaction. 324 * @return object 325 */ 326 createXhrObject:function(transactionId) 327 { 328 var obj,http,i; 329 try 330 { 331 // Instantiates XMLHttpRequest in non-IE browsers and assigns to http. 332 http = new XMLHttpRequest(); 333 // Object literal with http and tId properties 334 obj = { conn:http, tId:transactionId, xhr: true }; 335 } 336 catch(e) 337 { 338 for(i=0; i<this._msxml_progid.length; ++i){ 339 try 340 { 341 // Instantiates XMLHttpRequest for IE and assign to http 342 http = new ActiveXObject(this._msxml_progid[i]); 343 // Object literal with conn and tId properties 344 obj = { conn:http, tId:transactionId, xhr: true }; 345 break; 346 } 347 catch(e1){} 348 } 349 } 350 finally 351 { 352 return obj; 353 } 354 }, 355 356 /** 357 * @description This method is called by asyncRequest to create a 358 * valid connection object for the transaction. It also passes a 359 * transaction id and increments the transaction id counter. 360 * @method getConnectionObject 361 * @private 362 * @static 363 * @return {object} 364 */ 365 getConnectionObject:function(t) 366 { 367 var o, tId = this._transaction_id; 368 369 try 370 { 371 if(!t){ 372 o = this.createXhrObject(tId); 373 } 374 else{ 375 o = {tId:tId}; 376 if(t==='xdr'){ 377 o.conn = this._transport; 378 o.xdr = true; 379 } 380 else if(t==='upload'){ 381 o.upload = true; 382 } 383 } 384 385 if(o){ 386 this._transaction_id++; 387 } 388 } 389 catch(e){} 390 return o; 391 }, 392 393 /** 394 * @description Method for initiating an asynchronous request via the XHR object. 395 * @method asyncRequest 396 * @public 397 * @static 398 * @param {string} method HTTP transaction method 399 * @param {string} uri Fully qualified path of resource 400 * @param {callback} callback User-defined callback function or object 401 * @param {string} postData POST body 402 * @return {object} Returns the connection object 403 */ 404 asyncRequest:function(method, uri, callback, postData) 405 { 406 var args = callback&&callback.argument?callback.argument:null, 407 YCM = this, 408 o, t; 409 410 if(this._isFileUpload){ 411 t = 'upload'; 412 } 413 else if(callback && callback.xdr){ 414 t = 'xdr'; 415 } 416 417 o = this.getConnectionObject(t); 418 if(!o){ 419 return null; 420 } 421 else{ 422 423 // Intialize any transaction-specific custom events, if provided. 424 if(callback && callback.customevents){ 425 this.initCustomEvents(o, callback); 426 } 427 428 if(this._isFormSubmit){ 429 if(this._isFileUpload){ 430 window.setTimeout(function(){YCM.uploadFile(o, callback, uri, postData);}, 10); 431 return o; 432 } 433 434 // If the specified HTTP method is GET, setForm() will return an 435 // encoded string that is concatenated to the uri to 436 // create a querystring. 437 if(method.toUpperCase() == 'GET'){ 438 if(this._sFormData.length !== 0){ 439 // If the URI already contains a querystring, append an ampersand 440 // and then concatenate _sFormData to the URI. 441 uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData; 442 } 443 } 444 else if(method.toUpperCase() == 'POST'){ 445 // If POST data exist in addition to the HTML form data, 446 // it will be concatenated to the form data. 447 postData = postData?this._sFormData + "&" + postData:this._sFormData; 448 } 449 } 450 451 if(method.toUpperCase() == 'GET' && (callback && callback.cache === false)){ 452 // If callback.cache is defined and set to false, a 453 // timestamp value will be added to the querystring. 454 uri += ((uri.indexOf('?') == -1)?'?':'&') + "rnd=" + new Date().valueOf().toString(); 455 } 456 457 // Each transaction will automatically include a custom header of 458 // "X-Requested-With: XMLHttpRequest" to identify the request as 459 // having originated from Connection Manager. 460 if(this._use_default_xhr_header){ 461 if(!this._default_headers['X-Requested-With']){ 462 this.initHeader('X-Requested-With', this._default_xhr_header, true); 463 } 464 } 465 466 //If the transaction method is POST and the POST header value is set to true 467 //or a custom value, initalize the Content-Type header to this value. 468 if((method.toUpperCase() === 'POST' && this._use_default_post_header) && this._isFormSubmit === false){ 469 this.initHeader('Content-Type', this._default_post_header); 470 } 471 472 if(o.xdr){ 473 this.xdr(o, method, uri, callback, postData); 474 return o; 475 } 476 477 o.conn.open(method, uri, true); 478 //Initialize all default and custom HTTP headers, 479 if(this._has_default_headers || this._has_http_headers){ 480 this.setHeader(o); 481 } 482 483 this.handleReadyState(o, callback); 484 o.conn.send(postData || ''); 485 486 // Reset the HTML form data and state properties as 487 // soon as the data are submitted. 488 if(this._isFormSubmit === true){ 489 this.resetFormState(); 490 } 491 492 // Fire global custom event -- startEvent 493 this.startEvent.fire(o, args); 494 495 if(o.startEvent){ 496 // Fire transaction custom event -- startEvent 497 o.startEvent.fire(o, args); 498 } 499 500 return o; 501 } 502 }, 503 504 /** 505 * @description This method creates and subscribes custom events, 506 * specific to each transaction 507 * @method initCustomEvents 508 * @private 509 * @static 510 * @param {object} o The connection object 511 * @param {callback} callback The user-defined callback object 512 * @return {void} 513 */ 514 initCustomEvents:function(o, callback) 515 { 516 var prop; 517 // Enumerate through callback.customevents members and bind/subscribe 518 // events that match in the _customEvents table. 519 for(prop in callback.customevents){ 520 if(this._customEvents[prop][0]){ 521 // Create the custom event 522 o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null); 523 524 // Subscribe the custom event 525 o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]); 526 } 527 } 528 }, 529 530 /** 531 * @description This method serves as a timer that polls the XHR object's readyState 532 * property during a transaction, instead of binding a callback to the 533 * onreadystatechange event. Upon readyState 4, handleTransactionResponse 534 * will process the response, and the timer will be cleared. 535 * @method handleReadyState 536 * @private 537 * @static 538 * @param {object} o The connection object 539 * @param {callback} callback The user-defined callback object 540 * @return {void} 541 */ 542 543 handleReadyState:function(o, callback) 544 545 { 546 var oConn = this, 547 args = (callback && callback.argument)?callback.argument:null; 548 549 if(callback && callback.timeout){ 550 this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout); 551 } 552 553 this._poll[o.tId] = window.setInterval( 554 function(){ 555 if(o.conn && o.conn.readyState === 4){ 556 557 // Clear the polling interval for the transaction 558 // and remove the reference from _poll. 559 window.clearInterval(oConn._poll[o.tId]); 560 delete oConn._poll[o.tId]; 561 562 if(callback && callback.timeout){ 563 window.clearTimeout(oConn._timeOut[o.tId]); 564 delete oConn._timeOut[o.tId]; 565 } 566 567 // Fire global custom event -- completeEvent 568 oConn.completeEvent.fire(o, args); 569 570 if(o.completeEvent){ 571 // Fire transaction custom event -- completeEvent 572 o.completeEvent.fire(o, args); 573 } 574 575 oConn.handleTransactionResponse(o, callback); 576 } 577 } 578 ,this._polling_interval); 579 }, 580 581 /** 582 * @description This method attempts to interpret the server response and 583 * determine whether the transaction was successful, or if an error or 584 * exception was encountered. 585 * @method handleTransactionResponse 586 * @private 587 * @static 588 * @param {object} o The connection object 589 * @param {object} callback The user-defined callback object 590 * @param {boolean} isAbort Determines if the transaction was terminated via abort(). 591 * @return {void} 592 */ 593 handleTransactionResponse:function(o, callback, isAbort) 594 { 595 var httpStatus, responseObject, 596 args = (callback && callback.argument)?callback.argument:null, 597 xdrS = (o.r && o.r.statusText === 'xdr:success')?true:false, 598 xdrF = (o.r && o.r.statusText === 'xdr:failure')?true:false, 599 xdrA = isAbort; 600 601 try 602 { 603 if((o.conn.status !== undefined && o.conn.status !== 0) || xdrS){ 604 // XDR requests will not have HTTP status defined. The 605 // statusText property will define the response status 606 // set by the Flash transport. 607 httpStatus = o.conn.status; 608 } 609 else if(xdrF && !xdrA){ 610 // Set XDR transaction failure to a status of 0, which 611 // resolves as an HTTP failure, instead of an exception. 612 httpStatus = 0; 613 } 614 else{ 615 httpStatus = 13030; 616 } 617 } 618 catch(e){ 619 620 // 13030 is a custom code to indicate the condition -- in Mozilla/FF -- 621 // when the XHR object's status and statusText properties are 622 // unavailable, and a query attempt throws an exception. 623 httpStatus = 13030; 624 } 625 626 if((httpStatus >= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){ 627 responseObject = o.xdr ? o.r : this.createResponseObject(o, args); 628 if(callback && callback.success){ 629 if(!callback.scope){ 630 callback.success(responseObject); 631 } 632 else{ 633 // If a scope property is defined, the callback will be fired from 634 // the context of the object. 635 callback.success.apply(callback.scope, [responseObject]); 636 } 637 } 638 639 // Fire global custom event -- successEvent 640 this.successEvent.fire(responseObject); 641 642 if(o.successEvent){ 643 // Fire transaction custom event -- successEvent 644 o.successEvent.fire(responseObject); 645 } 646 } 647 else{ 648 switch(httpStatus){ 649 // The following cases are wininet.dll error codes that may be encountered. 650 case 12002: // Server timeout 651 case 12029: // 12029 to 12031 correspond to dropped connections. 652 case 12030: 653 case 12031: 654 case 12152: // Connection closed by server. 655 case 13030: // See above comments for variable status. 656 // XDR transactions will not resolve to this case, since the 657 // response object is already built in the xdr response. 658 responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false)); 659 if(callback && callback.failure){ 660 if(!callback.scope){ 661 callback.failure(responseObject); 662 } 663 else{ 664 callback.failure.apply(callback.scope, [responseObject]); 665 } 666 } 667 668 break; 669 default: 670 responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args); 671 if(callback && callback.failure){ 672 if(!callback.scope){ 673 callback.failure(responseObject); 674 } 675 else{ 676 callback.failure.apply(callback.scope, [responseObject]); 677 } 678 } 679 } 680 681 // Fire global custom event -- failureEvent 682 this.failureEvent.fire(responseObject); 683 684 if(o.failureEvent){ 685 // Fire transaction custom event -- failureEvent 686 o.failureEvent.fire(responseObject); 687 } 688 689 } 690 691 this.releaseObject(o); 692 responseObject = null; 693 }, 694 695 /** 696 * @description This method evaluates the server response, creates and returns the results via 697 * its properties. Success and failure cases will differ in the response 698 * object's property values. 699 * @method createResponseObject 700 * @private 701 * @static 702 * @param {object} o The connection object 703 * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback 704 * @return {object} 705 */ 706 createResponseObject:function(o, callbackArg) 707 { 708 var obj = {}, headerObj = {}, 709 i, headerStr, header, delimitPos; 710 711 try 712 { 713 headerStr = o.conn.getAllResponseHeaders(); 714 header = headerStr.split('\n'); 715 for(i=0; i<header.length; i++){ 716 delimitPos = header[i].indexOf(':'); 717 if(delimitPos != -1){ 718 headerObj[header[i].substring(0,delimitPos)] = YAHOO.lang.trim(header[i].substring(delimitPos+2)); 719 } 720 } 721 } 722 catch(e){} 723 724 obj.tId = o.tId; 725 // Normalize IE's response to HTTP 204 when Win error 1223. 726 obj.status = (o.conn.status == 1223)?204:o.conn.status; 727 // Normalize IE's statusText to "No Content" instead of "Unknown". 728 obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText; 729 obj.getResponseHeader = headerObj; 730 obj.getAllResponseHeaders = headerStr; 731 obj.responseText = o.conn.responseText; 732 obj.responseXML = o.conn.responseXML; 733 734 if(callbackArg){ 735 obj.argument = callbackArg; 736 } 737 738 return obj; 739 }, 740 741 /** 742 * @description If a transaction cannot be completed due to dropped or closed connections, 743 * there may be not be enough information to build a full response object. 744 * The failure callback will be fired and this specific condition can be identified 745 * by a status property value of 0. 746 * 747 * If an abort was successful, the status property will report a value of -1. 748 * 749 * @method createExceptionObject 750 * @private 751 * @static 752 * @param {int} tId The Transaction Id 753 * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback 754 * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort 755 * @return {object} 756 */ 757 createExceptionObject:function(tId, callbackArg, isAbort) 758 { 759 var COMM_CODE = 0, 760 COMM_ERROR = 'communication failure', 761 ABORT_CODE = -1, 762 ABORT_ERROR = 'transaction aborted', 763 obj = {}; 764 765 obj.tId = tId; 766 if(isAbort){ 767 obj.status = ABORT_CODE; 768 obj.statusText = ABORT_ERROR; 769 } 770 else{ 771 obj.status = COMM_CODE; 772 obj.statusText = COMM_ERROR; 773 } 774 775 if(callbackArg){ 776 obj.argument = callbackArg; 777 } 778 779 return obj; 780 }, 781 782 /** 783 * @description Method that initializes the custom HTTP headers for the each transaction. 784 * @method initHeader 785 * @public 786 * @static 787 * @param {string} label The HTTP header label 788 * @param {string} value The HTTP header value 789 * @param {string} isDefault Determines if the specific header is a default header 790 * automatically sent with each transaction. 791 * @return {void} 792 */ 793 initHeader:function(label, value, isDefault) 794 { 795 var headerObj = (isDefault)?this._default_headers:this._http_headers; 796 797 headerObj[label] = value; 798 if(isDefault){ 799 this._has_default_headers = true; 800 } 801 else{ 802 this._has_http_headers = true; 803 } 804 }, 805 806 807 /** 808 * @description Accessor that sets the HTTP headers for each transaction. 809 * @method setHeader 810 * @private 811 * @static 812 * @param {object} o The connection object for the transaction. 813 * @return {void} 814 */ 815 setHeader:function(o) 816 { 817 var prop; 818 if(this._has_default_headers){ 819 for(prop in this._default_headers){ 820 if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){ 821 o.conn.setRequestHeader(prop, this._default_headers[prop]); 822 } 823 } 824 } 825 826 if(this._has_http_headers){ 827 for(prop in this._http_headers){ 828 if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){ 829 o.conn.setRequestHeader(prop, this._http_headers[prop]); 830 } 831 } 832 833 this._http_headers = {}; 834 this._has_http_headers = false; 835 } 836 }, 837 838 /** 839 * @description Resets the default HTTP headers object 840 * @method resetDefaultHeaders 841 * @public 842 * @static 843 * @return {void} 844 */ 845 resetDefaultHeaders:function(){ 846 this._default_headers = {}; 847 this._has_default_headers = false; 848 }, 849 850 /** 851 * @description Method to terminate a transaction, if it has not reached readyState 4. 852 * @method abort 853 * @public 854 * @static 855 * @param {object} o The connection object returned by asyncRequest. 856 * @param {object} callback User-defined callback object. 857 * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout. 858 * @return {boolean} 859 */ 860 abort:function(o, callback, isTimeout) 861 { 862 var abortStatus, 863 args = (callback && callback.argument)?callback.argument:null; 864 o = o || {}; 865 866 if(o.conn){ 867 if(o.xhr){ 868 if(this.isCallInProgress(o)){ 869 // Issue abort request 870 o.conn.abort(); 871 872 window.clearInterval(this._poll[o.tId]); 873 delete this._poll[o.tId]; 874 875 if(isTimeout){ 876 window.clearTimeout(this._timeOut[o.tId]); 877 delete this._timeOut[o.tId]; 878 } 879 880 abortStatus = true; 881 } 882 } 883 else if(o.xdr){ 884 o.conn.abort(o.tId); 885 abortStatus = true; 886 } 887 } 888 else if(o.upload){ 889 var frameId = 'yuiIO' + o.tId; 890 var io = document.getElementById(frameId); 891 892 if(io){ 893 // Remove all listeners on the iframe prior to 894 // its destruction. 895 YAHOO.util.Event.removeListener(io, "load"); 896 // Destroy the iframe facilitating the transaction. 897 document.body.removeChild(io); 898 899 if(isTimeout){ 900 window.clearTimeout(this._timeOut[o.tId]); 901 delete this._timeOut[o.tId]; 902 } 903 904 abortStatus = true; 905 } 906 } 907 else{ 908 abortStatus = false; 909 } 910 911 if(abortStatus === true){ 912 // Fire global custom event -- abortEvent 913 this.abortEvent.fire(o, args); 914 915 if(o.abortEvent){ 916 // Fire transaction custom event -- abortEvent 917 o.abortEvent.fire(o, args); 918 } 919 920 this.handleTransactionResponse(o, callback, true); 921 } 922 923 return abortStatus; 924 }, 925 926 /** 927 * @description Determines if the transaction is still being processed. 928 * @method isCallInProgress 929 * @public 930 * @static 931 * @param {object} o The connection object returned by asyncRequest 932 * @return {boolean} 933 */ 934 isCallInProgress:function(o) 935 { 936 o = o || {}; 937 // if the XHR object assigned to the transaction has not been dereferenced, 938 // then check its readyState status. Otherwise, return false. 939 if(o.xhr && o.conn){ 940 return o.conn.readyState !== 4 && o.conn.readyState !== 0; 941 } 942 else if(o.xdr && o.conn){ 943 return o.conn.isCallInProgress(o.tId); 944 } 945 else if(o.upload === true){ 946 return document.getElementById('yuiIO' + o.tId)?true:false; 947 } 948 else{ 949 return false; 950 } 951 }, 952 953 /** 954 * @description Dereference the XHR instance and the connection object after the transaction is completed. 955 * @method releaseObject 956 * @private 957 * @static 958 * @param {object} o The connection object 959 * @return {void} 960 */ 961 releaseObject:function(o) 962 { 963 if(o && o.conn){ 964 //dereference the XHR instance. 965 o.conn = null; 966 967 968 //dereference the connection object. 969 o = null; 970 } 971 } 972 }; 973 974 /** 975 * @for YAHOO.util.Connect 976 */ 977 (function() { 978 var YCM = YAHOO.util.Connect, _fn = {}; 979 980 /** 981 * @description This method creates and instantiates the Flash transport. 982 * @method _swf 983 * @private 984 * @static 985 * @param {string} URI to connection.swf. 986 * @return {void} 987 */ 988 function _swf(uri) { 989 var o = '<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="' + 990 uri + '" width="0" height="0">' + 991 '<param name="movie" value="' + uri + '">' + 992 '<param name="allowScriptAccess" value="always">' + 993 '</object>', 994 c = document.createElement('div'); 995 996 document.body.appendChild(c); 997 c.innerHTML = o; 998 } 999 1000 /** 1001 * @description This method calls the public method on the 1002 * Flash transport to start the XDR transaction. It is analogous 1003 * to Connection Manager's asyncRequest method. 1004 * @method xdr 1005 * @private 1006 * @static 1007 * @param {object} The transaction object. 1008 * @param {string} HTTP request method. 1009 * @param {string} URI for the transaction. 1010 * @param {object} The transaction's callback object. 1011 * @param {object} The JSON object used as HTTP POST data. 1012 * @return {void} 1013 */ 1014 function _xdr(o, m, u, c, d) { 1015 _fn[parseInt(o.tId)] = { 'o':o, 'c':c }; 1016 if (d) { 1017 c.method = m; 1018 c.data = d; 1019 } 1020 1021 o.conn.send(u, c, o.tId); 1022 } 1023 1024 /** 1025 * @description This method instantiates the Flash transport and 1026 * establishes a static reference to it, used for all XDR requests. 1027 * @method transport 1028 * @public 1029 * @static 1030 * @param {string} URI to connection.swf. 1031 * @return {void} 1032 */ 1033 function _init(uri) { 1034 _swf(uri); 1035 YCM._transport = document.getElementById('YUIConnectionSwf'); 1036 } 1037 1038 function _xdrReady() { 1039 YCM.xdrReadyEvent.fire(); 1040 } 1041 1042 /** 1043 * @description This method fires the global and transaction start 1044 * events. 1045 * @method _xdrStart 1046 * @private 1047 * @static 1048 * @param {object} The transaction object. 1049 * @param {string} The transaction's callback object. 1050 * @return {void} 1051 */ 1052 function _xdrStart(o, cb) { 1053 if (o) { 1054 // Fire global custom event -- startEvent 1055 YCM.startEvent.fire(o, cb.argument); 1056 1057 if(o.startEvent){ 1058 // Fire transaction custom event -- startEvent 1059 o.startEvent.fire(o, cb.argument); 1060 } 1061 } 1062 } 1063 1064 /** 1065 * @description This method is the initial response handler 1066 * for XDR transactions. The Flash transport calls this 1067 * function and sends the response payload. 1068 * @method handleXdrResponse 1069 * @private 1070 * @static 1071 * @param {object} The response object sent from the Flash transport. 1072 * @return {void} 1073 */ 1074 function _handleXdrResponse(r) { 1075 var o = _fn[r.tId].o, 1076 cb = _fn[r.tId].c; 1077 1078 if (r.statusText === 'xdr:start') { 1079 _xdrStart(o, cb); 1080 return; 1081 } 1082 1083 r.responseText = decodeURI(r.responseText); 1084 o.r = r; 1085 if (cb.argument) { 1086 o.r.argument = cb.argument; 1087 } 1088 1089 this.handleTransactionResponse(o, cb, r.statusText === 'xdr:abort' ? true : false); 1090 delete _fn[r.tId]; 1091 } 1092 1093 // Bind the functions to Connection Manager as static fields. 1094 YCM.xdr = _xdr; 1095 YCM.swf = _swf; 1096 YCM.transport = _init; 1097 YCM.xdrReadyEvent = new YAHOO.util.CustomEvent('xdrReady'); 1098 YCM.xdrReady = _xdrReady; 1099 YCM.handleXdrResponse = _handleXdrResponse; 1100 })(); 1101 1102 /** 1103 * @for YAHOO.util.Connect 1104 */ 1105 (function(){ 1106 var YCM = YAHOO.util.Connect, 1107 YE = YAHOO.util.Event, 1108 dM = document.documentMode ? document.documentMode : false; 1109 1110 /** 1111 * @description Property modified by setForm() to determine if a file(s) 1112 * upload is expected. 1113 * @property _isFileUpload 1114 * @private 1115 * @static 1116 * @type boolean 1117 */ 1118 YCM._isFileUpload = false; 1119 1120 /** 1121 * @description Property modified by setForm() to set a reference to the HTML 1122 * form node if the desired action is file upload. 1123 * @property _formNode 1124 * @private 1125 * @static 1126 * @type object 1127 */ 1128 YCM._formNode = null; 1129 1130 /** 1131 * @description Property modified by setForm() to set the HTML form data 1132 * for each transaction. 1133 * @property _sFormData 1134 * @private 1135 * @static 1136 * @type string 1137 */ 1138 YCM._sFormData = null; 1139 1140 /** 1141 * @description Tracks the name-value pair of the "clicked" submit button if multiple submit 1142 * buttons are present in an HTML form; and, if YAHOO.util.Event is available. 1143 * @property _submitElementValue 1144 * @private 1145 * @static 1146 * @type string 1147 */ 1148 YCM._submitElementValue = null; 1149 1150 /** 1151 * @description Custom event that fires when handleTransactionResponse() determines a 1152 * response in the HTTP 4xx/5xx range. 1153 * @property failureEvent 1154 * @private 1155 * @static 1156 * @type CustomEvent 1157 */ 1158 YCM.uploadEvent = new YAHOO.util.CustomEvent('upload'); 1159 1160 /** 1161 * @description Determines whether YAHOO.util.Event is available and returns true or false. 1162 * If true, an event listener is bound at the document level to trap click events that 1163 * resolve to a target type of "Submit". This listener will enable setForm() to determine 1164 * the clicked "Submit" value in a multi-Submit button, HTML form. 1165 * @property _hasSubmitListener 1166 * @private 1167 * @static 1168 */ 1169 YCM._hasSubmitListener = function() { 1170 if(YE){ 1171 YE.addListener( 1172 document, 1173 'click', 1174 function(e){ 1175 var obj = YE.getTarget(e), 1176 name = obj.nodeName.toLowerCase(); 1177 1178 if((name === 'input' || name === 'button') && (obj.type && obj.type.toLowerCase() == 'submit')){ 1179 YCM._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value); 1180 } 1181 }); 1182 return true; 1183 } 1184 return false; 1185 }(); 1186 1187 /** 1188 * @description This method assembles the form label and value pairs and 1189 * constructs an encoded string. 1190 * asyncRequest() will automatically initialize the transaction with a 1191 * a HTTP header Content-Type of application/x-www-form-urlencoded. 1192 * @method setForm 1193 * @public 1194 * @static 1195 * @param {string || object} form id or name attribute, or form object. 1196 * @param {boolean} optional enable file upload. 1197 * @param {boolean} optional enable file upload over SSL in IE only. 1198 * @return {string} string of the HTML form field name and value pairs.. 1199 */ 1200 function _setForm(formId, isUpload, secureUri) 1201 { 1202 var oForm, oElement, oName, oValue, oDisabled, 1203 hasSubmit = false, 1204 data = [], item = 0, 1205 i,len,j,jlen,opt; 1206 1207 this.resetFormState(); 1208 1209 if(typeof formId == 'string'){ 1210 // Determine if the argument is a form id or a form name. 1211 // Note form name usage is deprecated by supported 1212 // here for legacy reasons. 1213 oForm = (document.getElementById(formId) || document.forms[formId]); 1214 } 1215 else if(typeof formId == 'object'){ 1216 // Treat argument as an HTML form object. 1217 oForm = formId; 1218 } 1219 else{ 1220 return; 1221 } 1222 1223 // If the isUpload argument is true, setForm will call createFrame to initialize 1224 // an iframe as the form target. 1225 // 1226 // The argument secureURI is also required by IE in SSL environments 1227 // where the secureURI string is a fully qualified HTTP path, used to set the source 1228 // of the iframe, to a stub resource in the same domain. 1229 if(isUpload){ 1230 1231 // Create iframe in preparation for file upload. 1232 this.createFrame(secureUri?secureUri:null); 1233 1234 // Set form reference and file upload properties to true. 1235 this._isFormSubmit = true; 1236 this._isFileUpload = true; 1237 this._formNode = oForm; 1238 1239 return; 1240 } 1241 1242 // Iterate over the form elements collection to construct the 1243 // label-value pairs. 1244 for (i=0,len=oForm.elements.length; i<len; ++i){ 1245 oElement = oForm.elements[i]; 1246 oDisabled = oElement.disabled; 1247 oName = oElement.name; 1248 1249 // Do not submit fields that are disabled or 1250 // do not have a name attribute value. 1251 if(!oDisabled && oName) 1252 { 1253 oName = encodeURIComponent(oName)+'='; 1254 oValue = encodeURIComponent(oElement.value); 1255 1256 switch(oElement.type) 1257 { 1258 // Safari, Opera, FF all default opt.value from .text if 1259 // value attribute not specified in markup 1260 case 'select-one': 1261 if (oElement.selectedIndex > -1) { 1262 opt = oElement.options[oElement.selectedIndex]; 1263 data[item++] = oName + encodeURIComponent( 1264 (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text); 1265 } 1266 break; 1267 case 'select-multiple': 1268 if (oElement.selectedIndex > -1) { 1269 for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){ 1270 opt = oElement.options[j]; 1271 if (opt.selected) { 1272 data[item++] = oName + encodeURIComponent( 1273 (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text); 1274 } 1275 } 1276 } 1277 break; 1278 case 'radio': 1279 case 'checkbox': 1280 if(oElement.checked){ 1281 data[item++] = oName + oValue; 1282 } 1283 break; 1284 case 'file': 1285 // stub case as XMLHttpRequest will only send the file path as a string. 1286 case undefined: 1287 // stub case for fieldset element which returns undefined. 1288 case 'reset': 1289 // stub case for input type reset button. 1290 case 'button': 1291 // stub case for input type button elements. 1292 break; 1293 case 'submit': 1294 if(hasSubmit === false){ 1295 if(this._hasSubmitListener && this._submitElementValue){ 1296 data[item++] = this._submitElementValue; 1297 } 1298 hasSubmit = true; 1299 } 1300 break; 1301 default: 1302 data[item++] = oName + oValue; 1303 } 1304 } 1305 } 1306 1307 this._isFormSubmit = true; 1308 this._sFormData = data.join('&'); 1309 1310 1311 this.initHeader('Content-Type', this._default_form_header); 1312 1313 return this._sFormData; 1314 } 1315 1316 /** 1317 * @description Resets HTML form properties when an HTML form or HTML form 1318 * with file upload transaction is sent. 1319 * @method resetFormState 1320 * @private 1321 * @static 1322 * @return {void} 1323 */ 1324 function _resetFormState(){ 1325 this._isFormSubmit = false; 1326 this._isFileUpload = false; 1327 this._formNode = null; 1328 this._sFormData = ""; 1329 } 1330 1331 1332 /** 1333 * @description Creates an iframe to be used for form file uploads. It is remove from the 1334 * document upon completion of the upload transaction. 1335 * @method createFrame 1336 * @private 1337 * @static 1338 * @param {string} optional qualified path of iframe resource for SSL in IE. 1339 * @return {void} 1340 */ 1341 function _createFrame(secureUri){ 1342 1343 // IE does not allow the setting of id and name attributes as object 1344 // properties via createElement(). A different iframe creation 1345 // pattern is required for IE. 1346 var frameId = 'yuiIO' + this._transaction_id, 1347 ie9 = (dM === 9) ? true : false, 1348 io; 1349 1350 if(YAHOO.env.ua.ie && !ie9){ 1351 io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />'); 1352 1353 // IE will throw a security exception in an SSL environment if the 1354 // iframe source is undefined. 1355 if(typeof secureUri == 'boolean'){ 1356 io.src = 'javascript:false'; 1357 } 1358 } 1359 else{ 1360 io = document.createElement('iframe'); 1361 io.id = frameId; 1362 io.name = frameId; 1363 } 1364 1365 io.style.position = 'absolute'; 1366 io.style.top = '-1000px'; 1367 io.style.left = '-1000px'; 1368 1369 document.body.appendChild(io); 1370 } 1371 1372 /** 1373 * @description Parses the POST data and creates hidden form elements 1374 * for each key-value, and appends them to the HTML form object. 1375 * @method appendPostData 1376 * @private 1377 * @static 1378 * @param {string} postData The HTTP POST data 1379 * @return {array} formElements Collection of hidden fields. 1380 */ 1381 function _appendPostData(postData){ 1382 var formElements = [], 1383 postMessage = postData.split('&'), 1384 i, delimitPos; 1385 1386 for(i=0; i < postMessage.length; i++){ 1387 delimitPos = postMessage[i].indexOf('='); 1388 if(delimitPos != -1){ 1389 formElements[i] = document.createElement('input'); 1390 formElements[i].type = 'hidden'; 1391 formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos)); 1392 formElements[i].value = decodeURIComponent(postMessage[i].substring(delimitPos+1)); 1393 this._formNode.appendChild(formElements[i]); 1394 } 1395 } 1396 1397 return formElements; 1398 } 1399 1400 /** 1401 * @description Uploads HTML form, inclusive of files/attachments, using the 1402 * iframe created in createFrame to facilitate the transaction. 1403 * @method uploadFile 1404 * @private 1405 * @static 1406 * @param {int} id The transaction id. 1407 * @param {object} callback User-defined callback object. 1408 * @param {string} uri Fully qualified path of resource. 1409 * @param {string} postData POST data to be submitted in addition to HTML form. 1410 * @return {void} 1411 */ 1412 function _uploadFile(o, callback, uri, postData){ 1413 // Each iframe has an id prefix of "yuiIO" followed 1414 // by the unique transaction id. 1415 var frameId = 'yuiIO' + o.tId, 1416 uploadEncoding = 'multipart/form-data', 1417 io = document.getElementById(frameId), 1418 ie8 = (dM >= 8) ? true : false, 1419 oConn = this, 1420 args = (callback && callback.argument)?callback.argument:null, 1421 oElements,i,prop,obj, rawFormAttributes, uploadCallback; 1422 1423 // Track original HTML form attribute values. 1424 rawFormAttributes = { 1425 action:this._formNode.getAttribute('action'), 1426 method:this._formNode.getAttribute('method'), 1427 target:this._formNode.getAttribute('target') 1428 }; 1429 1430 // Initialize the HTML form properties in case they are 1431 // not defined in the HTML form. 1432 this._formNode.setAttribute('action', uri); 1433 this._formNode.setAttribute('method', 'POST'); 1434 this._formNode.setAttribute('target', frameId); 1435 1436 if(YAHOO.env.ua.ie && !ie8){ 1437 // IE does not respect property enctype for HTML forms. 1438 // Instead it uses the property - "encoding". 1439 this._formNode.setAttribute('encoding', uploadEncoding); 1440 } 1441 else{ 1442 this._formNode.setAttribute('enctype', uploadEncoding); 1443 } 1444 1445 if(postData){ 1446 oElements = this.appendPostData(postData); 1447 } 1448 1449 // Start file upload. 1450 this._formNode.submit(); 1451 1452 // Fire global custom event -- startEvent 1453 this.startEvent.fire(o, args); 1454 1455 if(o.startEvent){ 1456 // Fire transaction custom event -- startEvent 1457 o.startEvent.fire(o, args); 1458 } 1459 1460 // Start polling if a callback is present and the timeout 1461 // property has been defined. 1462 if(callback && callback.timeout){ 1463 this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout); 1464 } 1465 1466 // Remove HTML elements created by appendPostData 1467 if(oElements && oElements.length > 0){ 1468 for(i=0; i < oElements.length; i++){ 1469 this._formNode.removeChild(oElements[i]); 1470 } 1471 } 1472 1473 // Restore HTML form attributes to their original 1474 // values prior to file upload. 1475 for(prop in rawFormAttributes){ 1476 if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){ 1477 if(rawFormAttributes[prop]){ 1478 this._formNode.setAttribute(prop, rawFormAttributes[prop]); 1479 } 1480 else{ 1481 this._formNode.removeAttribute(prop); 1482 } 1483 } 1484 } 1485 1486 // Reset HTML form state properties. 1487 this.resetFormState(); 1488 1489 // Create the upload callback handler that fires when the iframe 1490 // receives the load event. Subsequently, the event handler is detached 1491 // and the iframe removed from the document. 1492 uploadCallback = function() { 1493 var body, pre, text; 1494 1495 if(callback && callback.timeout){ 1496 window.clearTimeout(oConn._timeOut[o.tId]); 1497 delete oConn._timeOut[o.tId]; 1498 } 1499 1500 // Fire global custom event -- completeEvent 1501 oConn.completeEvent.fire(o, args); 1502 1503 if(o.completeEvent){ 1504 // Fire transaction custom event -- completeEvent 1505 o.completeEvent.fire(o, args); 1506 } 1507 1508 obj = { 1509 tId : o.tId, 1510 argument : args 1511 }; 1512 1513 try 1514 { 1515 body = io.contentWindow.document.getElementsByTagName('body')[0]; 1516 pre = io.contentWindow.document.getElementsByTagName('pre')[0]; 1517 1518 if (body) { 1519 if (pre) { 1520 text = pre.textContent?pre.textContent:pre.innerText; 1521 } 1522 else { 1523 text = body.textContent?body.textContent:body.innerText; 1524 } 1525 } 1526 obj.responseText = text; 1527 // responseText and responseXML will be populated with the same data from the iframe. 1528 // Since the HTTP headers cannot be read from the iframe 1529 obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document; 1530 } 1531 catch(e){} 1532 1533 if(callback && callback.upload){ 1534 if(!callback.scope){ 1535 callback.upload(obj); 1536 } 1537 else{ 1538 callback.upload.apply(callback.scope, [obj]); 1539 } 1540 } 1541 1542 // Fire global custom event -- uploadEvent 1543 oConn.uploadEvent.fire(obj); 1544 1545 if(o.uploadEvent){ 1546 // Fire transaction custom event -- uploadEvent 1547 o.uploadEvent.fire(obj); 1548 } 1549 1550 YE.removeListener(io, "load", uploadCallback); 1551 1552 setTimeout( 1553 function(){ 1554 document.body.removeChild(io); 1555 oConn.releaseObject(o); 1556 }, 100); 1557 }; 1558 1559 // Bind the onload handler to the iframe to detect the file upload response. 1560 YE.addListener(io, "load", uploadCallback); 1561 } 1562 1563 YCM.setForm = _setForm; 1564 YCM.resetFormState = _resetFormState; 1565 YCM.createFrame = _createFrame; 1566 YCM.appendPostData = _appendPostData; 1567 YCM.uploadFile = _uploadFile; 1568 })(); 1569 1570 YAHOO.register("connection", YAHOO.util.Connect, {version: "2.9.0", build: "2800"}); 1571 1572 }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-event"], "supersedes": ["yui2-connectioncore"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |