PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/samples/build-ext-using-maven/src/main/javascript/yui/connection.js

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