connection.js 49 KB

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