PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/webapps/thirdparty/exist/web/xqts/scripts/connection.js

http://xformsdb.googlecode.com/
JavaScript | 777 lines | 417 code | 72 blank | 288 comment | 73 complexity | 47aa50615677fdc42c10d9b93f1842e7 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, IPL-1.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.11.1
  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. * @ class
  13. */
  14. YAHOO.util.Connect =
  15. {
  16. /**
  17. * Array of MSFT ActiveX ids for XMLHttpRequest.
  18. * @private
  19. * @type array
  20. */
  21. _msxml_progid:[
  22. 'MSXML2.XMLHTTP.3.0',
  23. 'MSXML2.XMLHTTP',
  24. 'Microsoft.XMLHTTP'
  25. ],
  26. /**
  27. * Object literal of HTTP header(s)
  28. * @private
  29. * @type object
  30. */
  31. _http_header:{},
  32. /**
  33. * Determines if HTTP headers are set.
  34. * @private
  35. * @type boolean
  36. */
  37. _has_http_headers:false,
  38. /**
  39. * Determines if a default header of
  40. * Content-Type of 'application/x-www-form-urlencoded'
  41. * will be added to any client HTTP headers sent for POST
  42. * transactions.
  43. * @private
  44. * @type boolean
  45. */
  46. _default_post_header:true,
  47. /**
  48. * Property modified by setForm() to determine if the data
  49. * should be submitted as an HTML form.
  50. * @private
  51. * @type boolean
  52. */
  53. _isFormSubmit:false,
  54. /**
  55. * Property modified by setForm() to determine if a file(s)
  56. * upload is expected.
  57. * @private
  58. * @type boolean
  59. */
  60. _isFileUpload:false,
  61. /**
  62. * Property modified by setForm() to set a reference to the HTML
  63. * form node if the desired action is file upload.
  64. * @private
  65. * @type object
  66. */
  67. _formNode:null,
  68. /**
  69. * Property modified by setForm() to set the HTML form data
  70. * for each transaction.
  71. * @private
  72. * @type string
  73. */
  74. _sFormData:null,
  75. /**
  76. * Collection of polling references to the polling mechanism in handleReadyState.
  77. * @private
  78. * @type string
  79. */
  80. _poll:[],
  81. /**
  82. * Queue of timeout values for each transaction callback with a defined timeout value.
  83. * @private
  84. * @type string
  85. */
  86. _timeOut:[],
  87. /**
  88. * The polling frequency, in milliseconds, for HandleReadyState.
  89. * when attempting to determine a transaction's XHR readyState.
  90. * The default is 50 milliseconds.
  91. * @private
  92. * @type int
  93. */
  94. _polling_interval:50,
  95. /**
  96. * A transaction counter that increments the transaction id for each transaction.
  97. * @private
  98. * @type int
  99. */
  100. _transaction_id:0,
  101. /**
  102. * Member to add an ActiveX id to the existing xml_progid array.
  103. * In the event(unlikely) a new ActiveX id is introduced, it can be added
  104. * without internal code modifications.
  105. * @public
  106. * @param string id The ActiveX id to be added to initialize the XHR object.
  107. * @return void
  108. */
  109. setProgId:function(id)
  110. {
  111. this._msxml_progid.unshift(id);
  112. },
  113. /**
  114. * Member to enable or disable the default POST header.
  115. * @public
  116. * @param boolean b Set and use default header - true or false .
  117. * @return void
  118. */
  119. setDefaultPostHeader:function(b)
  120. {
  121. this._default_post_header = b;
  122. },
  123. /**
  124. * Member to modify the default polling interval.
  125. * @public
  126. * @param {int} i The polling interval in milliseconds.
  127. * @return void
  128. */
  129. setPollingInterval:function(i)
  130. {
  131. if(typeof i == 'number' && isFinite(i)){
  132. this._polling_interval = i;
  133. }
  134. },
  135. /**
  136. * Instantiates a XMLHttpRequest object and returns an object with two properties:
  137. * the XMLHttpRequest instance and the transaction id.
  138. * @private
  139. * @param {int} transactionId Property containing the transaction id for this transaction.
  140. * @return connection object
  141. */
  142. createXhrObject:function(transactionId)
  143. {
  144. var obj,http;
  145. try
  146. {
  147. // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
  148. http = new XMLHttpRequest();
  149. // Object literal with http and tId properties
  150. obj = { conn:http, tId:transactionId };
  151. }
  152. catch(e)
  153. {
  154. for(var i=0; i<this._msxml_progid.length; ++i){
  155. try
  156. {
  157. // Instantiates XMLHttpRequest for IE and assign to http.
  158. http = new ActiveXObject(this._msxml_progid[i]);
  159. // Object literal with http and tId properties
  160. obj = { conn:http, tId:transactionId };
  161. break;
  162. }
  163. catch(e){}
  164. }
  165. }
  166. finally
  167. {
  168. return obj;
  169. }
  170. },
  171. /**
  172. * This method is called by asyncRequest to create a
  173. * valid connection object for the transaction. It also passes a
  174. * transaction id and increments the transaction id counter.
  175. * @private
  176. * @return object
  177. */
  178. getConnectionObject:function()
  179. {
  180. var o;
  181. var tId = this._transaction_id;
  182. try
  183. {
  184. o = this.createXhrObject(tId);
  185. if(o){
  186. this._transaction_id++;
  187. }
  188. }
  189. catch(e){}
  190. finally
  191. {
  192. return o;
  193. }
  194. },
  195. /**
  196. * Method for initiating an asynchronous request via the XHR object.
  197. * @public
  198. * @param {string} method HTTP transaction method
  199. * @param {string} uri Fully qualified path of resource
  200. * @param callback User-defined callback function or object
  201. * @param {string} postData POST body
  202. * @return {object} Returns the connection object
  203. */
  204. asyncRequest:function(method, uri, callback, postData)
  205. {
  206. var o = this.getConnectionObject();
  207. if(!o){
  208. return null;
  209. }
  210. else{
  211. if(this._isFormSubmit){
  212. if(this._isFileUpload){
  213. this.uploadFile(o.tId, callback, uri);
  214. this.releaseObject(o);
  215. return;
  216. }
  217. //If the specified HTTP method is GET, setForm() will return an
  218. //encoded string that is concatenated to the uri to
  219. //create a querystring.
  220. if(method == 'GET'){
  221. uri += "?" + this._sFormData;
  222. }
  223. else if(method == 'POST'){
  224. postData = this._sFormData;
  225. }
  226. this._sFormData = '';
  227. }
  228. o.conn.open(method, uri, true);
  229. if(this._isFormSubmit || (postData && this._default_post_header)){
  230. this.initHeader('Content-Type','application/x-www-form-urlencoded');
  231. if(this._isFormSubmit){
  232. this._isFormSubmit = false;
  233. }
  234. }
  235. //Verify whether the transaction has any user-defined HTTP headers
  236. //and set them.
  237. if(this._has_http_headers){
  238. this.setHeader(o);
  239. }
  240. this.handleReadyState(o, callback);
  241. postData?o.conn.send(postData):o.conn.send(null);
  242. return o;
  243. }
  244. },
  245. /**
  246. * This method serves as a timer that polls the XHR object's readyState
  247. * property during a transaction, instead of binding a callback to the
  248. * onreadystatechange event. Upon readyState 4, handleTransactionResponse
  249. * will process the response, and the timer will be cleared.
  250. *
  251. * @private
  252. * @param {object} o The connection object
  253. * @param callback User-defined callback object
  254. * @return void
  255. */
  256. handleReadyState:function(o, callback)
  257. {
  258. var timeOut = callback.timeout;
  259. var oConn = this;
  260. try
  261. {
  262. if(timeOut !== undefined){
  263. this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true) }, timeOut);
  264. }
  265. this._poll[o.tId] = window.setInterval(
  266. function(){
  267. if(o.conn && o.conn.readyState == 4){
  268. window.clearInterval(oConn._poll[o.tId]);
  269. oConn._poll.splice(o.tId);
  270. if(timeOut){
  271. oConn._timeOut.splice(o.tId);
  272. }
  273. oConn.handleTransactionResponse(o, callback);
  274. }
  275. }
  276. ,this._polling_interval);
  277. }
  278. catch(e)
  279. {
  280. window.clearInterval(oConn._poll[o.tId]);
  281. oConn._poll.splice(o.tId);
  282. if(timeOut){
  283. oConn._timeOut.splice(o.tId);
  284. }
  285. oConn.handleTransactionResponse(o, callback);
  286. }
  287. },
  288. /**
  289. * This method attempts to interpret the server response and
  290. * determine whether the transaction was successful, or if an error or
  291. * exception was encountered.
  292. *
  293. * @private
  294. * @param {object} o The connection object
  295. * @param {object} callback - User-defined callback object
  296. * @param {boolean} determines if the transaction was aborted.
  297. * @return void
  298. */
  299. handleTransactionResponse:function(o, callback, isAbort)
  300. {
  301. // If no valid callback is provided, then do not process any callback handling.
  302. if(!callback){
  303. this.releaseObject(o);
  304. return;
  305. }
  306. var httpStatus, responseObject;
  307. try
  308. {
  309. if(o.conn.status !== undefined && o.conn.status != 0){
  310. httpStatus = o.conn.status;
  311. }
  312. else{
  313. httpStatus = 13030;
  314. }
  315. }
  316. catch(e){
  317. // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
  318. // when the o object's status and statusText properties are
  319. // unavailable, and a query attempt throws an exception.
  320. httpStatus = 13030;
  321. }
  322. if(httpStatus >= 200 && httpStatus < 300){
  323. responseObject = this.createResponseObject(o, callback.argument);
  324. if(callback.success){
  325. if(!callback.scope){
  326. callback.success(responseObject);
  327. }
  328. else{
  329. // If a scope property is defined, the callback will be fired from
  330. // the context of the object.
  331. callback.success.apply(callback.scope, [responseObject]);
  332. }
  333. }
  334. }
  335. else{
  336. switch(httpStatus){
  337. // The following case labels are wininet.dll error codes that may be encountered.
  338. // Server timeout
  339. case 12002:
  340. // 12029 to 12031 correspond to dropped connections.
  341. case 12029:
  342. case 12030:
  343. case 12031:
  344. // Connection closed by server.
  345. case 12152:
  346. // See above comments for variable status.
  347. case 13030:
  348. responseObject = this.createExceptionObject(o.tId, callback.argument, isAbort);
  349. if(callback.failure){
  350. if(!callback.scope){
  351. callback.failure(responseObject);
  352. }
  353. else{
  354. callback.failure.apply(callback.scope, [responseObject]);
  355. }
  356. }
  357. break;
  358. default:
  359. responseObject = this.createResponseObject(o, callback.argument);
  360. if(callback.failure){
  361. if(!callback.scope){
  362. callback.failure(responseObject);
  363. }
  364. else{
  365. callback.failure.apply(callback.scope, [responseObject]);
  366. }
  367. }
  368. }
  369. }
  370. this.releaseObject(o);
  371. },
  372. /**
  373. * This method evaluates the server response, creates and returns the results via
  374. * its properties. Success and failure cases will differ in the response
  375. * object's property values.
  376. * @private
  377. * @param {object} o The connection object
  378. * @param {} callbackArg User-defined argument or arguments to be passed to the callback
  379. * @return object
  380. */
  381. createResponseObject:function(o, callbackArg)
  382. {
  383. var obj = {};
  384. var headerObj = {};
  385. try
  386. {
  387. var headerStr = o.conn.getAllResponseHeaders();
  388. var header = headerStr.split('\n');
  389. for(var i=0; i < header.length; i++){
  390. var delimitPos = header[i].indexOf(':');
  391. if(delimitPos != -1){
  392. headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos + 2);
  393. }
  394. }
  395. }
  396. catch(e){}
  397. obj.tId = o.tId;
  398. obj.status = o.conn.status;
  399. obj.statusText = o.conn.statusText;
  400. obj.getResponseHeader = headerObj;
  401. obj.getAllResponseHeaders = headerStr;
  402. obj.responseText = o.conn.responseText;
  403. obj.responseXML = o.conn.responseXML;
  404. if(typeof callbackArg !== undefined){
  405. obj.argument = callbackArg;
  406. }
  407. return obj;
  408. },
  409. /**
  410. * If a transaction cannot be completed due to dropped or closed connections,
  411. * there may be not be enough information to build a full response object.
  412. * The failure callback will be fired and this specific condition can be identified
  413. * by a status property value of 0.
  414. *
  415. * If an abort was successful, the status property will report a value of -1.
  416. *
  417. * @private
  418. * @param {int} tId Transaction Id
  419. * @param callbackArg The user-defined arguments
  420. * @param isAbort Determines if the exception is an abort.
  421. * @return object
  422. */
  423. createExceptionObject:function(tId, callbackArg, isAbort)
  424. {
  425. var COMM_CODE = 0;
  426. var COMM_ERROR = 'communication failure';
  427. var ABORT_CODE = -1;
  428. var ABORT_ERROR = 'transaction aborted';
  429. var obj = {};
  430. obj.tId = tId;
  431. if(isAbort){
  432. obj.status = ABORT_CODE;
  433. obj.statusText = ABORT_ERROR;
  434. }
  435. else{
  436. obj.status = COMM_CODE;
  437. obj.statusText = COMM_ERROR;
  438. }
  439. if(callbackArg){
  440. obj.argument = callbackArg;
  441. }
  442. return obj;
  443. },
  444. /**
  445. * Public method that stores the custom HTTP headers for each transaction.
  446. * @public
  447. * @param {string} label The HTTP header label
  448. * @param {string} value The HTTP header value
  449. * @return void
  450. */
  451. initHeader:function(label,value)
  452. {
  453. if(this._http_header[label] === undefined){
  454. this._http_header[label] = value;
  455. }
  456. else{
  457. this._http_header[label] = value + "," + this._http_header[label];
  458. }
  459. this._has_http_headers = true;
  460. },
  461. /**
  462. * Accessor that sets the HTTP headers for each transaction.
  463. * @private
  464. * @param {object} o The connection object for the transaction.
  465. * @return void
  466. */
  467. setHeader:function(o)
  468. {
  469. for(var prop in this._http_header){
  470. if(this._http_header.propertyIsEnumerable){
  471. o.conn.setRequestHeader(prop, this._http_header[prop]);
  472. }
  473. }
  474. delete this._http_header;
  475. this._http_header = {};
  476. this._has_http_headers = false;
  477. },
  478. /**
  479. * This method assembles the form label and value pairs and
  480. * constructs an encoded string.
  481. * asyncRequest() will automatically initialize the
  482. * transaction with a HTTP header Content-Type of
  483. * application/x-www-form-urlencoded.
  484. * @public
  485. * @param {string || object} form id or name attribute, or form object.
  486. * @param {string} optional boolean to indicate SSL environment.
  487. * @param {string} optional qualified path of iframe resource for SSL in IE.
  488. * @return void
  489. */
  490. setForm:function(formId, isUpload, secureUri)
  491. {
  492. this._sFormData = '';
  493. if(typeof formId == 'string'){
  494. // Determine if the argument is a form id or a form name.
  495. // Note form name usage is deprecated by supported
  496. // here for legacy reasons.
  497. var oForm = (document.getElementById(formId) || document.forms[formId]);
  498. }
  499. else if(typeof formId == 'object'){
  500. var oForm = formId;
  501. }
  502. else{
  503. return;
  504. }
  505. // If the isUpload argument is true, setForm will call createFrame to initialize
  506. // an iframe as the form target.
  507. //
  508. // The argument secureURI is also required by IE in SSL environments
  509. // where the secureURI string is a fully qualified HTTP path, used to set the source
  510. // of the iframe, to a stub resource in the same domain.
  511. if(isUpload){
  512. (typeof secureUri == 'string')?this.createFrame(secureUri):this.createFrame();
  513. this._isFormSubmit = true;
  514. this._isFileUpload = true;
  515. this._formNode = oForm;
  516. return;
  517. }
  518. var oElement, oName, oValue, oDisabled;
  519. var hasSubmit = false;
  520. // Iterate over the form elements collection to construct the
  521. // label-value pairs.
  522. for (var i=0; i<oForm.elements.length; i++){
  523. oDisabled = oForm.elements[i].disabled;
  524. // If the name attribute is not populated, the form field's
  525. // value will not be submitted.
  526. oElement = oForm.elements[i];
  527. oName = oForm.elements[i].name;
  528. oValue = oForm.elements[i].value;
  529. // Do not submit fields that are disabled or
  530. // do not have a name attribute value.
  531. if(!oDisabled && oName)
  532. {
  533. switch (oElement.type)
  534. {
  535. case 'select-one':
  536. case 'select-multiple':
  537. for(var j=0; j<oElement.options.length; j++){
  538. if(oElement.options[j].selected){
  539. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].value || oElement.options[j].text) + '&';
  540. }
  541. }
  542. break;
  543. case 'radio':
  544. case 'checkbox':
  545. if(oElement.checked){
  546. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  547. }
  548. break;
  549. case 'file':
  550. // stub case as XMLHttpRequest will only send the file path as a string.
  551. case undefined:
  552. // stub case for fieldset element which returns undefined.
  553. case 'reset':
  554. // stub case for input type reset button.
  555. case 'button':
  556. // stub case for input type button elements.
  557. break;
  558. case 'submit':
  559. if(hasSubmit == false){
  560. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  561. hasSubmit = true;
  562. }
  563. break;
  564. default:
  565. this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
  566. break;
  567. }
  568. }
  569. }
  570. this._isFormSubmit = true;
  571. this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
  572. },
  573. /**
  574. * Creates an iframe to be used for form file uploads. It is remove from the
  575. * document upon completion of the upload transaction.
  576. *
  577. * @private
  578. * @param {string} optional qualified path of iframe resource for SSL in IE.
  579. * @return void
  580. */
  581. createFrame:function(secureUri){
  582. // IE does not allow the setting of id and name attributes as DOM
  583. // properties. A different iframe creation pattern is required for IE.
  584. if(window.ActiveXObject){
  585. var io = document.createElement('<IFRAME name="ioFrame" id="ioFrame">');
  586. if(secureUri){
  587. // IE will throw a security exception in an SSL environment if the
  588. // iframe source isn't set to a valid resource.
  589. io.src = secureUri;
  590. }
  591. }
  592. else{
  593. var io = document.createElement('IFRAME');
  594. io.id = 'ioFrame';
  595. io.name = 'ioFrame';
  596. }
  597. io.style.position = 'absolute';
  598. io.style.top = '-1000px';
  599. io.style.left = '-1000px';
  600. document.body.appendChild(io);
  601. },
  602. /**
  603. * Uploads HTML form, including files/attachments, targeting the
  604. * iframe created in createFrame.
  605. *
  606. * @private
  607. * @param {int} id The transaction id.
  608. * @param {object} callback - User-defined callback object.
  609. * @param {string} uri Fully qualified path of resource.
  610. * @return void
  611. */
  612. uploadFile:function(id, callback, uri){
  613. // Initialize the HTML form properties in case they are
  614. // not defined in the HTML form.
  615. this._formNode.action = uri;
  616. this._formNode.enctype = 'multipart/form-data';
  617. this._formNode.method = 'POST';
  618. this._formNode.target = 'ioFrame';
  619. this._formNode.submit();
  620. // Reset form status properties.
  621. this._formNode = null;
  622. this._isFileUpload = false;
  623. this._isFormSubmit = false;
  624. // Create the upload callback handler that fires when the iframe
  625. // receives the load event. Subsequently, the event handler is detached
  626. // and the iframe removed from the document.
  627. var uploadCallback = function()
  628. {
  629. var oResponse =
  630. {
  631. tId: id,
  632. responseText: document.getElementById("ioFrame").contentWindow.document.body.innerHTML,
  633. argument: callback.argument
  634. }
  635. if(callback.upload){
  636. if(!callback.scope){
  637. callback.upload(oResponse);
  638. }
  639. else{
  640. callback.upload.apply(callback.scope, [oResponse]);
  641. }
  642. }
  643. YAHOO.util.Event.removeListener("ioFrame", "load", uploadCallback);
  644. window.ioFrame.location.replace('#');
  645. setTimeout("document.body.removeChild(document.getElementById('ioFrame'))",100);
  646. };
  647. // Bind the onload handler to the iframe to detect the file upload response.
  648. YAHOO.util.Event.addListener("ioFrame", "load", uploadCallback);
  649. },
  650. /**
  651. * Public method to terminate a transaction, if it has not reached readyState 4.
  652. * @public
  653. * @param {object} o The connection object returned by asyncRequest.
  654. * @param {object} callback User-defined callback object.
  655. * @param {string} isTimeout boolean to indicate if abort was a timeout.
  656. * @return void
  657. */
  658. abort:function(o, callback, isTimeout)
  659. {
  660. if(this.isCallInProgress(o)){
  661. window.clearInterval(this._poll[o.tId]);
  662. this._poll.splice(o.tId);
  663. if(isTimeout){
  664. this._timeOut.splice(o.tId);
  665. }
  666. o.conn.abort();
  667. this.handleTransactionResponse(o, callback, true);
  668. return true;
  669. }
  670. else{
  671. return false;
  672. }
  673. },
  674. /**
  675. * Public method to check if the transaction is still being processed.
  676. * @public
  677. * @param {object} o The connection object returned by asyncRequest
  678. * @return boolean
  679. */
  680. isCallInProgress:function(o)
  681. {
  682. // if the XHR object assigned to the transaction has not been dereferenced,
  683. // then check its readyState status. Otherwise, return false.
  684. if(o.conn){
  685. return o.conn.readyState != 4 && o.conn.readyState != 0;
  686. }
  687. else{
  688. //The XHR object has been destroyed.
  689. return false;
  690. }
  691. },
  692. /**
  693. * Dereference the XHR instance and the connection object after the transaction is completed.
  694. * @private
  695. * @param {object} o The connection object
  696. * @return void
  697. */
  698. releaseObject:function(o)
  699. {
  700. //dereference the XHR instance.
  701. o.conn = null;
  702. //dereference the connection object.
  703. o = null;
  704. }
  705. };