PageRenderTime 1023ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/cia/media-src/js/yui-0.12.2/build/connection/connection-debug.js

http://cia-vc.googlecode.com/
JavaScript | 983 lines | 501 code | 94 blank | 388 comment | 99 complexity | e1968a2924064c996fc47868c55c4628 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (c) 2006, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 0.12.2
  6. */
  7. /**
  8. * The Connection Manager provides a simplified interface to the XMLHttpRequest
  9. * object. It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
  10. * interactive states and server response, returning the results to a pre-defined
  11. * callback you create.
  12. *
  13. * @namespace YAHOO.util
  14. * @module connection
  15. * @requires yahoo
  16. */
  17. /**
  18. * The Connection Manager singleton provides methods for creating and managing
  19. * asynchronous transactions.
  20. *
  21. * @class Connect
  22. */
  23. YAHOO.util.Connect =
  24. {
  25. /**
  26. * @description Array of MSFT ActiveX ids for XMLHttpRequest.
  27. * @property _msxml_progid
  28. * @private
  29. * @static
  30. * @type array
  31. */
  32. _msxml_progid:[
  33. 'MSXML2.XMLHTTP.3.0',
  34. 'MSXML2.XMLHTTP',
  35. 'Microsoft.XMLHTTP'
  36. ],
  37. /**
  38. * @description Object literal of HTTP header(s)
  39. * @property _http_header
  40. * @private
  41. * @static
  42. * @type object
  43. */
  44. _http_header:{},
  45. /**
  46. * @description Determines if HTTP headers are set.
  47. * @property _has_http_headers
  48. * @private
  49. * @static
  50. * @type boolean
  51. */
  52. _has_http_headers:false,
  53. /**
  54. * @description Determines if a default header of
  55. * Content-Type of 'application/x-www-form-urlencoded'
  56. * will be added to any client HTTP headers sent for POST
  57. * transactions.
  58. * @property _use_default_post_header
  59. * @private
  60. * @static
  61. * @type boolean
  62. */
  63. _use_default_post_header:true,
  64. /**
  65. * @description Determines if a default header of
  66. * Content-Type of 'application/x-www-form-urlencoded'
  67. * will be added to any client HTTP headers sent for POST
  68. * transactions.
  69. * @property _default_post_header
  70. * @private
  71. * @static
  72. * @type boolean
  73. */
  74. _default_post_header:'application/x-www-form-urlencoded',
  75. /**
  76. * @description Property modified by setForm() to determine if the data
  77. * should be submitted as an HTML form.
  78. * @property _isFormSubmit
  79. * @private
  80. * @static
  81. * @type boolean
  82. */
  83. _isFormSubmit:false,
  84. /**
  85. * @description Property modified by setForm() to determine if a file(s)
  86. * upload is expected.
  87. * @property _isFileUpload
  88. * @private
  89. * @static
  90. * @type boolean
  91. */
  92. _isFileUpload:false,
  93. /**
  94. * @description Property modified by setForm() to set a reference to the HTML
  95. * form node if the desired action is file upload.
  96. * @property _formNode
  97. * @private
  98. * @static
  99. * @type object
  100. */
  101. _formNode:null,
  102. /**
  103. * @description Property modified by setForm() to set the HTML form data
  104. * for each transaction.
  105. * @property _sFormData
  106. * @private
  107. * @static
  108. * @type string
  109. */
  110. _sFormData:null,
  111. /**
  112. * @description Collection of polling references to the polling mechanism in handleReadyState.
  113. * @property _poll
  114. * @private
  115. * @static
  116. * @type object
  117. */
  118. _poll:{},
  119. /**
  120. * @description Queue of timeout values for each transaction callback with a defined timeout value.
  121. * @property _timeOut
  122. * @private
  123. * @static
  124. * @type object
  125. */
  126. _timeOut:{},
  127. /**
  128. * @description The polling frequency, in milliseconds, for HandleReadyState.
  129. * when attempting to determine a transaction's XHR readyState.
  130. * The default is 50 milliseconds.
  131. * @property _polling_interval
  132. * @private
  133. * @static
  134. * @type int
  135. */
  136. _polling_interval:50,
  137. /**
  138. * @description A transaction counter that increments the transaction id for each transaction.
  139. * @property _transaction_id
  140. * @private
  141. * @static
  142. * @type int
  143. */
  144. _transaction_id:0,
  145. /**
  146. * @description Member to add an ActiveX id to the existing xml_progid array.
  147. * In the event(unlikely) a new ActiveX id is introduced, it can be added
  148. * without internal code modifications.
  149. * @method setProgId
  150. * @public
  151. * @static
  152. * @param {string} id The ActiveX id to be added to initialize the XHR object.
  153. * @return void
  154. */
  155. setProgId:function(id)
  156. {
  157. this._msxml_progid.unshift(id);
  158. YAHOO.log('ActiveX Program Id ' + id + ' added to _msxml_progid.', 'info', 'Connection');
  159. },
  160. /**
  161. * @description Member to enable or disable the default POST header.
  162. * @method setDefaultPostHeader
  163. * @public
  164. * @static
  165. * @param {boolean} b Set and use default header - true or false .
  166. * @return void
  167. */
  168. setDefaultPostHeader:function(b)
  169. {
  170. this._use_default_post_header = b;
  171. YAHOO.log('Use default POST header set to ' + b, 'info', 'Connection');
  172. },
  173. /**
  174. * @description Member to modify the default polling interval.
  175. * @method setPollingInterval
  176. * @public
  177. * @static
  178. * @param {int} i The polling interval in milliseconds.
  179. * @return void
  180. */
  181. setPollingInterval:function(i)
  182. {
  183. if(typeof i == 'number' && isFinite(i)){
  184. this._polling_interval = i;
  185. YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection');
  186. }
  187. },
  188. /**
  189. * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
  190. * the XMLHttpRequest instance and the transaction id.
  191. * @method createXhrObject
  192. * @private
  193. * @static
  194. * @param {int} transactionId Property containing the transaction id for this transaction.
  195. * @return object
  196. */
  197. createXhrObject:function(transactionId)
  198. {
  199. var obj,http;
  200. try
  201. {
  202. // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
  203. http = new XMLHttpRequest();
  204. // Object literal with http and tId properties
  205. obj = { conn:http, tId:transactionId };
  206. YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection');
  207. }
  208. catch(e)
  209. {
  210. for(var i=0; i<this._msxml_progid.length; ++i){
  211. try
  212. {
  213. // Instantiates XMLHttpRequest for IE and assign to http.
  214. http = new ActiveXObject(this._msxml_progid[i]);
  215. // Object literal with conn and tId properties
  216. obj = { conn:http, tId:transactionId };
  217. YAHOO.log('ActiveX XHR object created for transaction ' + transactionId, 'info', 'Connection');
  218. break;
  219. }
  220. catch(e){}
  221. }
  222. }
  223. finally
  224. {
  225. return obj;
  226. }
  227. },
  228. /**
  229. * @description This method is called by asyncRequest to create a
  230. * valid connection object for the transaction. It also passes a
  231. * transaction id and increments the transaction id counter.
  232. * @method getConnectionObject
  233. * @private
  234. * @static
  235. * @return {object}
  236. */
  237. getConnectionObject:function()
  238. {
  239. var o;
  240. var tId = this._transaction_id;
  241. try
  242. {
  243. o = this.createXhrObject(tId);
  244. if(o){
  245. this._transaction_id++;
  246. }
  247. }
  248. catch(e){}
  249. finally
  250. {
  251. return o;
  252. }
  253. },
  254. /**
  255. * @description Method for initiating an asynchronous request via the XHR object.
  256. * @method asyncRequest
  257. * @public
  258. * @static
  259. * @param {string} method HTTP transaction method
  260. * @param {string} uri Fully qualified path of resource
  261. * @param {callback} callback User-defined callback function or object
  262. * @param {string} postData POST body
  263. * @return {object} Returns the connection object
  264. */
  265. asyncRequest:function(method, uri, callback, postData)
  266. {
  267. var o = this.getConnectionObject();
  268. if(!o){
  269. YAHOO.log('Unable to create connection object.', 'error', 'Connection');
  270. return null;
  271. }
  272. else{
  273. if(this._isFormSubmit){
  274. if(this._isFileUpload){
  275. this.uploadFile(o.tId, callback, uri, postData);
  276. this.releaseObject(o);
  277. return;
  278. }
  279. //If the specified HTTP method is GET, setForm() will return an
  280. //encoded string that is concatenated to the uri to
  281. //create a querystring.
  282. if(method == 'GET'){
  283. if(this._sFormData.length != 0){
  284. // If the URI already contains a querystring, append an ampersand
  285. // and then concatenate _sFormData to the URI.
  286. uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
  287. }
  288. else{
  289. uri += "?" + this._sFormData;
  290. }
  291. }
  292. else if(method == 'POST'){
  293. //If POST data exist in addition to the HTML form data,
  294. //it will be concatenated to the form data.
  295. postData = postData?this._sFormData + "&" + postData:this._sFormData;
  296. }
  297. }
  298. o.conn.open(method, uri, true);
  299. if(this._isFormSubmit || (postData && this._use_default_post_header)){
  300. this.initHeader('Content-Type', this._default_post_header);
  301. YAHOO.log('Initialize default header Content-Type to application/x-www-form-urlencoded.', 'info', 'Connection');
  302. if(this._isFormSubmit){
  303. this.resetFormState();
  304. }
  305. }
  306. if(this._has_http_headers){
  307. this.setHeader(o);
  308. }
  309. this.handleReadyState(o, callback);
  310. o.conn.send(postData || null);
  311. return o;
  312. }
  313. },
  314. /**
  315. * @description This method serves as a timer that polls the XHR object's readyState
  316. * property during a transaction, instead of binding a callback to the
  317. * onreadystatechange event. Upon readyState 4, handleTransactionResponse
  318. * will process the response, and the timer will be cleared.
  319. * @method handleReadyState
  320. * @private
  321. * @static
  322. * @param {object} o The connection object
  323. * @param {callback} callback The user-defined callback object
  324. * @return {void}
  325. */
  326. handleReadyState:function(o, callback)
  327. {
  328. var oConn = this;
  329. if(callback && callback.timeout){
  330. this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
  331. }
  332. this._poll[o.tId] = window.setInterval(
  333. function(){
  334. if(o.conn && o.conn.readyState == 4){
  335. window.clearInterval(oConn._poll[o.tId]);
  336. delete oConn._poll[o.tId];
  337. if(callback && callback.timeout){
  338. delete oConn._timeOut[o.tId];
  339. }
  340. oConn.handleTransactionResponse(o, callback);
  341. }
  342. }
  343. ,this._polling_interval);
  344. },
  345. /**
  346. * @description This method attempts to interpret the server response and
  347. * determine whether the transaction was successful, or if an error or
  348. * exception was encountered.
  349. * @method handleTransactionResponse
  350. * @private
  351. * @static
  352. * @param {object} o The connection object
  353. * @param {object} callback The sser-defined callback object
  354. * @param {boolean} isAbort Determines if the transaction was aborted.
  355. * @return {void}
  356. */
  357. handleTransactionResponse:function(o, callback, isAbort)
  358. {
  359. // If no valid callback is provided, then do not process any callback handling.
  360. if(!callback){
  361. this.releaseObject(o);
  362. YAHOO.log('No callback object to process. Transaction complete.', 'warn', 'Connection');
  363. return;
  364. }
  365. var httpStatus, responseObject;
  366. try
  367. {
  368. if(o.conn.status !== undefined && o.conn.status != 0){
  369. httpStatus = o.conn.status;
  370. }
  371. else{
  372. httpStatus = 13030;
  373. }
  374. }
  375. catch(e){
  376. // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
  377. // when the o object's status and statusText properties are
  378. // unavailable, and a query attempt throws an exception.
  379. httpStatus = 13030;
  380. }
  381. if(httpStatus >= 200 && httpStatus < 300){
  382. responseObject = this.createResponseObject(o, callback.argument);
  383. if(callback.success){
  384. if(!callback.scope){
  385. callback.success(responseObject);
  386. YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection');
  387. }
  388. else{
  389. // If a scope property is defined, the callback will be fired from
  390. // the context of the object.
  391. callback.success.apply(callback.scope, [responseObject]);
  392. YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection');
  393. }
  394. }
  395. }
  396. else{
  397. switch(httpStatus){
  398. // The following cases are wininet.dll error codes that may be encountered.
  399. case 12002: // Server timeout
  400. case 12029: // 12029 to 12031 correspond to dropped connections.
  401. case 12030:
  402. case 12031:
  403. case 12152: // Connection closed by server.
  404. case 13030: // See above comments for variable status.
  405. responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
  406. if(callback.failure){
  407. if(!callback.scope){
  408. callback.failure(responseObject);
  409. YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
  410. }
  411. else{
  412. callback.failure.apply(callback.scope, [responseObject]);
  413. YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection');
  414. }
  415. }
  416. break;
  417. default:
  418. responseObject = this.createResponseObject(o, callback.argument);
  419. if(callback.failure){
  420. if(!callback.scope){
  421. callback.failure(responseObject);
  422. YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection');
  423. }
  424. else{
  425. callback.failure.apply(callback.scope, [responseObject]);
  426. YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection');
  427. }
  428. }
  429. }
  430. }
  431. this.releaseObject(o);
  432. responseObject = null;
  433. },
  434. /**
  435. * @description This method evaluates the server response, creates and returns the results via
  436. * its properties. Success and failure cases will differ in the response
  437. * object's property values.
  438. * @method createResponseObject
  439. * @private
  440. * @static
  441. * @param {object} o The connection object
  442. * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
  443. * @return {object}
  444. */
  445. createResponseObject:function(o, callbackArg)
  446. {
  447. var obj = {};
  448. var headerObj = {};
  449. try
  450. {
  451. var headerStr = o.conn.getAllResponseHeaders();
  452. var header = headerStr.split('\n');
  453. for(var i=0; i<header.length; i++){
  454. var delimitPos = header[i].indexOf(':');
  455. if(delimitPos != -1){
  456. headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
  457. }
  458. }
  459. }
  460. catch(e){}
  461. obj.tId = o.tId;
  462. obj.status = o.conn.status;
  463. obj.statusText = o.conn.statusText;
  464. obj.getResponseHeader = headerObj;
  465. obj.getAllResponseHeaders = headerStr;
  466. obj.responseText = o.conn.responseText;
  467. obj.responseXML = o.conn.responseXML;
  468. if(typeof callbackArg !== undefined){
  469. obj.argument = callbackArg;
  470. }
  471. return obj;
  472. },
  473. /**
  474. * @description If a transaction cannot be completed due to dropped or closed connections,
  475. * there may be not be enough information to build a full response object.
  476. * The failure callback will be fired and this specific condition can be identified
  477. * by a status property value of 0.
  478. *
  479. * If an abort was successful, the status property will report a value of -1.
  480. *
  481. * @method createExceptionObject
  482. * @private
  483. * @static
  484. * @param {int} tId The Transaction Id
  485. * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
  486. * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
  487. * @return {object}
  488. */
  489. createExceptionObject:function(tId, callbackArg, isAbort)
  490. {
  491. var COMM_CODE = 0;
  492. var COMM_ERROR = 'communication failure';
  493. var ABORT_CODE = -1;
  494. var ABORT_ERROR = 'transaction aborted';
  495. var obj = {};
  496. obj.tId = tId;
  497. if(isAbort){
  498. obj.status = ABORT_CODE;
  499. obj.statusText = ABORT_ERROR;
  500. }
  501. else{
  502. obj.status = COMM_CODE;
  503. obj.statusText = COMM_ERROR;
  504. }
  505. if(callbackArg){
  506. obj.argument = callbackArg;
  507. }
  508. return obj;
  509. },
  510. /**
  511. * @description Public method that stores the custom HTTP headers for each transaction.
  512. * @method initHeader
  513. * @public
  514. * @static
  515. * @param {string} label The HTTP header label
  516. * @param {string} value The HTTP header value
  517. * @return {void}
  518. */
  519. initHeader:function(label,value)
  520. {
  521. if(this._http_header[label] === undefined){
  522. this._http_header[label] = value;
  523. }
  524. else{
  525. // Concatenate multiple values, comma-delimited,
  526. // for the same header label,
  527. this._http_header[label] = value + "," + this._http_header[label];
  528. }
  529. this._has_http_headers = true;
  530. },
  531. /**
  532. * @description Accessor that sets the HTTP headers for each transaction.
  533. * @method setHeader
  534. * @private
  535. * @static
  536. * @param {object} o The connection object for the transaction.
  537. * @return {void}
  538. */
  539. setHeader:function(o)
  540. {
  541. for(var prop in this._http_header){
  542. if(this._http_header.hasOwnProperty(prop)){
  543. o.conn.setRequestHeader(prop, this._http_header[prop]);
  544. YAHOO.log('HTTP header ' + prop + ' set with value of ' + this._http_header[prop], 'info', 'Connection');
  545. }
  546. }
  547. delete this._http_header;
  548. this._http_header = {};
  549. this._has_http_headers = false;
  550. },
  551. /**
  552. * @description This method assembles the form label and value pairs and
  553. * constructs an encoded string.
  554. * asyncRequest() will automatically initialize the
  555. * transaction with a HTTP header Content-Type of
  556. * application/x-www-form-urlencoded.
  557. * @method setForm
  558. * @public
  559. * @static
  560. * @param {string || object} form id or name attribute, or form object.
  561. * @param {string} optional boolean to indicate SSL environment.
  562. * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
  563. * @return {string} string of the HTML form field name and value pairs..
  564. */
  565. setForm:function(formId, isUpload, secureUri)
  566. {
  567. this.resetFormState();
  568. var oForm;
  569. if(typeof formId == 'string'){
  570. // Determine if the argument is a form id or a form name.
  571. // Note form name usage is deprecated by supported
  572. // here for legacy reasons.
  573. oForm = (document.getElementById(formId) || document.forms[formId]);
  574. }
  575. else if(typeof formId == 'object'){
  576. // Treat argument as an HTML form object.
  577. oForm = formId;
  578. }
  579. else{
  580. YAHOO.log('Unable to create form object ' + formId, 'warn', 'Connection');
  581. return;
  582. }
  583. // If the isUpload argument is true, setForm will call createFrame to initialize
  584. // an iframe as the form target.
  585. //
  586. // The argument secureURI is also required by IE in SSL environments
  587. // where the secureURI string is a fully qualified HTTP path, used to set the source
  588. // of the iframe, to a stub resource in the same domain.
  589. if(isUpload){
  590. // Create iframe in preparation for file upload.
  591. this.createFrame(secureUri?secureUri:null);
  592. // Set form reference and file upload properties to true.
  593. this._isFormSubmit = true;
  594. this._isFileUpload = true;
  595. this._formNode = oForm;
  596. return;
  597. }
  598. var oElement, oName, oValue, oDisabled;
  599. var hasSubmit = false;
  600. // Iterate over the form elements collection to construct the
  601. // label-value pairs.
  602. for (var i=0; i<oForm.elements.length; i++){
  603. oElement = oForm.elements[i];
  604. oDisabled = oForm.elements[i].disabled;
  605. oName = oForm.elements[i].name;
  606. oValue = oForm.elements[i].value;
  607. // Do not submit fields that are disabled or
  608. // do not have a name attribute value.
  609. if(!oDisabled && oName)
  610. {
  611. switch (oElement.type)
  612. {
  613. case 'select-one':
  614. case 'select-multiple':
  615. for(var j=0; j<oElement.options.length; j++){
  616. if(oElement.options[j].selected){
  617. if(window.ActiveXObject){
  618. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
  619. }
  620. else{
  621. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
  622. }
  623. }
  624. }
  625. break;
  626. case 'radio':
  627. case 'checkbox':
  628. if(oElement.checked){
  629. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  630. }
  631. break;
  632. case 'file':
  633. // stub case as XMLHttpRequest will only send the file path as a string.
  634. case undefined:
  635. // stub case for fieldset element which returns undefined.
  636. case 'reset':
  637. // stub case for input type reset button.
  638. case 'button':
  639. // stub case for input type button elements.
  640. break;
  641. case 'submit':
  642. if(hasSubmit == false){
  643. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  644. hasSubmit = true;
  645. }
  646. break;
  647. default:
  648. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  649. break;
  650. }
  651. }
  652. }
  653. this._isFormSubmit = true;
  654. this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
  655. YAHOO.log('Form initialized for transaction. HTML form POST message is: ' + this._sFormData, 'info', 'Connection');
  656. return this._sFormData;
  657. },
  658. /**
  659. * @description Resets HTML form properties when an HTML form or HTML form
  660. * with file upload transaction is sent.
  661. * @method resetFormState
  662. * @private
  663. * @static
  664. * @return {void}
  665. */
  666. resetFormState:function(){
  667. this._isFormSubmit = false;
  668. this._isFileUpload = false;
  669. this._formNode = null;
  670. this._sFormData = "";
  671. },
  672. /**
  673. * @description Creates an iframe to be used for form file uploads. It is remove from the
  674. * document upon completion of the upload transaction.
  675. * @method createFrame
  676. * @private
  677. * @static
  678. * @param {string} optional qualified path of iframe resource for SSL in IE.
  679. * @return {void}
  680. */
  681. createFrame:function(secureUri){
  682. // IE does not allow the setting of id and name attributes as object
  683. // properties via createElement(). A different iframe creation
  684. // pattern is required for IE.
  685. var frameId = 'yuiIO' + this._transaction_id;
  686. if(window.ActiveXObject){
  687. var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
  688. // IE will throw a security exception in an SSL environment if the
  689. // iframe source is undefined.
  690. if(typeof secureUri == 'boolean'){
  691. io.src = 'javascript:false';
  692. }
  693. else if(typeof secureURI == 'string'){
  694. // Deprecated
  695. io.src = secureUri;
  696. }
  697. }
  698. else{
  699. var io = document.createElement('iframe');
  700. io.id = frameId;
  701. io.name = frameId;
  702. }
  703. io.style.position = 'absolute';
  704. io.style.top = '-1000px';
  705. io.style.left = '-1000px';
  706. document.body.appendChild(io);
  707. YAHOO.log('File upload iframe created. Id is:' + frameId, 'info', 'Connection');
  708. },
  709. /**
  710. * @description Parses the POST data and creates hidden form elements
  711. * for each key-value, and appends them to the HTML form object.
  712. * @method appendPostData
  713. * @private
  714. * @static
  715. * @param {string} postData The HTTP POST data
  716. * @return {array} formElements Collection of hidden fields.
  717. */
  718. appendPostData:function(postData)
  719. {
  720. var formElements = [];
  721. var postMessage = postData.split('&');
  722. for(var i=0; i < postMessage.length; i++){
  723. var delimitPos = postMessage[i].indexOf('=');
  724. if(delimitPos != -1){
  725. formElements[i] = document.createElement('input');
  726. formElements[i].type = 'hidden';
  727. formElements[i].name = postMessage[i].substring(0,delimitPos);
  728. formElements[i].value = postMessage[i].substring(delimitPos+1);
  729. this._formNode.appendChild(formElements[i]);
  730. }
  731. }
  732. return formElements;
  733. },
  734. /**
  735. * @description Uploads HTML form, including files/attachments, to the
  736. * iframe created in createFrame.
  737. * @method uploadFile
  738. * @private
  739. * @static
  740. * @param {int} id The transaction id.
  741. * @param {object} callback - User-defined callback object.
  742. * @param {string} uri Fully qualified path of resource.
  743. * @return {void}
  744. */
  745. uploadFile:function(id, callback, uri, postData){
  746. // Each iframe has an id prefix of "yuiIO" followed
  747. // by the unique transaction id.
  748. var frameId = 'yuiIO' + id;
  749. var io = document.getElementById(frameId);
  750. // Initialize the HTML form properties in case they are
  751. // not defined in the HTML form.
  752. this._formNode.action = uri;
  753. this._formNode.method = 'POST';
  754. this._formNode.target = frameId;
  755. if(this._formNode.encoding){
  756. // IE does not respect property enctype for HTML forms.
  757. // Instead use property encoding.
  758. this._formNode.encoding = 'multipart/form-data';
  759. }
  760. else{
  761. this._formNode.enctype = 'multipart/form-data';
  762. }
  763. if(postData){
  764. var oElements = this.appendPostData(postData);
  765. }
  766. this._formNode.submit();
  767. if(oElements && oElements.length > 0){
  768. for(var i=0; i < oElements.length; i++){
  769. this._formNode.removeChild(oElements[i]);
  770. }
  771. }
  772. // Reset HTML form status properties.
  773. this.resetFormState();
  774. // Create the upload callback handler that fires when the iframe
  775. // receives the load event. Subsequently, the event handler is detached
  776. // and the iframe removed from the document.
  777. var uploadCallback = function()
  778. {
  779. var obj = {};
  780. obj.tId = id;
  781. obj.argument = callback.argument;
  782. try
  783. {
  784. obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
  785. obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
  786. }
  787. catch(e){}
  788. if(callback.upload){
  789. if(!callback.scope){
  790. callback.upload(obj);
  791. YAHOO.log('Upload callback.', 'info', 'Connection');
  792. }
  793. else{
  794. callback.upload.apply(callback.scope, [obj]);
  795. YAHOO.log('Upload callback with scope.', 'info', 'Connection');
  796. }
  797. }
  798. if(YAHOO.util.Event){
  799. YAHOO.util.Event.removeListener(io, "load", uploadCallback);
  800. }
  801. else if(window.detachEvent){
  802. io.detachEvent('onload', uploadCallback);
  803. }
  804. else{
  805. io.removeEventListener('load', uploadCallback, false);
  806. }
  807. setTimeout(
  808. function(){
  809. document.body.removeChild(io);
  810. YAHOO.log('File upload iframe destroyed. Id is:' + frameId, 'info', 'Connection');
  811. }, 100);
  812. };
  813. // Bind the onload handler to the iframe to detect the file upload response.
  814. if(YAHOO.util.Event){
  815. YAHOO.util.Event.addListener(io, "load", uploadCallback);
  816. }
  817. else if(window.attachEvent){
  818. io.attachEvent('onload', uploadCallback);
  819. }
  820. else{
  821. io.addEventListener('load', uploadCallback, false);
  822. }
  823. },
  824. /**
  825. * @description Method to terminate a transaction, if it has not reached readyState 4.
  826. * @method abort
  827. * @public
  828. * @static
  829. * @param {object} o The connection object returned by asyncRequest.
  830. * @param {object} callback User-defined callback object.
  831. * @param {string} isTimeout boolean to indicate if abort was a timeout.
  832. * @return {boolean}
  833. */
  834. abort:function(o, callback, isTimeout)
  835. {
  836. if(this.isCallInProgress(o)){
  837. o.conn.abort();
  838. window.clearInterval(this._poll[o.tId]);
  839. delete this._poll[o.tId];
  840. if(isTimeout){
  841. delete this._timeOut[o.tId];
  842. }
  843. this.handleTransactionResponse(o, callback, true);
  844. YAHOO.log('Transaction ' + o.tId + ' aborted.', 'info', 'Connection');
  845. return true;
  846. }
  847. else{
  848. YAHOO.log('Transaction ' + o.tId + ' abort call failed.', 'warn', 'Connection');
  849. return false;
  850. }
  851. },
  852. /**
  853. * Public method to check if the transaction is still being processed.
  854. *
  855. * @method isCallInProgress
  856. * @public
  857. * @static
  858. * @param {object} o The connection object returned by asyncRequest
  859. * @return {boolean}
  860. */
  861. isCallInProgress:function(o)
  862. {
  863. // if the XHR object assigned to the transaction has not been dereferenced,
  864. // then check its readyState status. Otherwise, return false.
  865. if(o.conn){
  866. return o.conn.readyState != 4 && o.conn.readyState != 0;
  867. }
  868. else{
  869. //The XHR object has been destroyed.
  870. return false;
  871. }
  872. },
  873. /**
  874. * @description Dereference the XHR instance and the connection object after the transaction is completed.
  875. * @method releaseObject
  876. * @private
  877. * @static
  878. * @param {object} o The connection object
  879. * @return {void}
  880. */
  881. releaseObject:function(o)
  882. {
  883. //dereference the XHR instance.
  884. o.conn = null;
  885. YAHOO.log('Connection object for transaction ' + o.tId + ' destroyed.', 'info', 'Connection');
  886. //dereference the connection object.
  887. o = null;
  888. }
  889. };