Connection.html 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-data-Connection'>/**
  19. </span> * The Connection class encapsulates a connection to the page's originating domain, allowing requests to be made either
  20. * to a configured URL, or to a URL specified at request time.
  21. *
  22. * Requests made by this class are asynchronous, and will return immediately. No data from the server will be available
  23. * to the statement immediately following the {@link #request} call. To process returned data, use a success callback
  24. * in the request options object, or an {@link #requestcomplete event listener}.
  25. *
  26. * # File Uploads
  27. *
  28. * File uploads are not performed using normal &quot;Ajax&quot; techniques, that is they are not performed using XMLHttpRequests.
  29. * Instead the form is submitted in the standard manner with the DOM &amp;lt;form&amp;gt; element temporarily modified to have its
  30. * target set to refer to a dynamically generated, hidden &amp;lt;iframe&amp;gt; which is inserted into the document but removed
  31. * after the return data has been gathered.
  32. *
  33. * The server response is parsed by the browser to create the document for the IFRAME. If the server is using JSON to
  34. * send the return object, then the Content-Type header must be set to &quot;text/html&quot; in order to tell the browser to
  35. * insert the text unchanged into the document body.
  36. *
  37. * Characters which are significant to an HTML parser must be sent as HTML entities, so encode `&lt;` as `&amp;lt;`, `&amp;` as
  38. * `&amp;amp;` etc.
  39. *
  40. * The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a
  41. * responseText property in order to conform to the requirements of event handlers and callbacks.
  42. *
  43. * Be aware that file upload packets are sent with the content type multipart/form and some server technologies
  44. * (notably JEE) may require some custom processing in order to retrieve parameter names and parameter values from the
  45. * packet content.
  46. *
  47. * Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.
  48. */
  49. Ext.define('Ext.data.Connection', {
  50. mixins: {
  51. observable: 'Ext.util.Observable'
  52. },
  53. statics: {
  54. requestId: 0
  55. },
  56. url: null,
  57. async: true,
  58. method: null,
  59. username: '',
  60. password: '',
  61. <span id='Ext-data-Connection-cfg-disableCaching'> /**
  62. </span> * @cfg {Boolean} disableCaching
  63. * True to add a unique cache-buster param to GET requests.
  64. */
  65. disableCaching: true,
  66. <span id='Ext-data-Connection-cfg-withCredentials'> /**
  67. </span> * @cfg {Boolean} withCredentials
  68. * True to set `withCredentials = true` on the XHR object
  69. */
  70. withCredentials: false,
  71. <span id='Ext-data-Connection-cfg-cors'> /**
  72. </span> * @cfg {Boolean} cors
  73. * True to enable CORS support on the XHR object. Currently the only effect of this option
  74. * is to use the XDomainRequest object instead of XMLHttpRequest if the browser is IE8 or above.
  75. */
  76. cors: false,
  77. <span id='Ext-data-Connection-cfg-disableCachingParam'> /**
  78. </span> * @cfg {String} disableCachingParam
  79. * Change the parameter which is sent went disabling caching through a cache buster.
  80. */
  81. disableCachingParam: '_dc',
  82. <span id='Ext-data-Connection-cfg-timeout'> /**
  83. </span> * @cfg {Number} timeout
  84. * The timeout in milliseconds to be used for requests.
  85. */
  86. timeout : 30000,
  87. <span id='Ext-data-Connection-cfg-extraParams'> /**
  88. </span> * @cfg {Object} extraParams
  89. * Any parameters to be appended to the request.
  90. */
  91. <span id='Ext-data-Connection-cfg-autoAbort'> /**
  92. </span> * @cfg {Boolean} [autoAbort=false]
  93. * Whether this request should abort any pending requests.
  94. */
  95. <span id='Ext-data-Connection-cfg-method'> /**
  96. </span> * @cfg {String} method
  97. * The default HTTP method to be used for requests.
  98. *
  99. * If not set, but {@link #request} params are present, POST will be used;
  100. * otherwise, GET will be used.
  101. */
  102. <span id='Ext-data-Connection-cfg-defaultHeaders'> /**
  103. </span> * @cfg {Object} defaultHeaders
  104. * An object containing request headers which are added to each request made by this object.
  105. */
  106. useDefaultHeader : true,
  107. defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',
  108. useDefaultXhrHeader : true,
  109. defaultXhrHeader : 'XMLHttpRequest',
  110. constructor : function(config) {
  111. config = config || {};
  112. Ext.apply(this, config);
  113. <span id='Ext-data-Connection-event-beforerequest'> /**
  114. </span> * @event beforerequest
  115. * Fires before a network request is made to retrieve a data object.
  116. * @param {Ext.data.Connection} conn This Connection object.
  117. * @param {Object} options The options config object passed to the {@link #request} method.
  118. */
  119. <span id='Ext-data-Connection-event-requestcomplete'> /**
  120. </span> * @event requestcomplete
  121. * Fires if the request was successfully completed.
  122. * @param {Ext.data.Connection} conn This Connection object.
  123. * @param {Object} response The XHR object containing the response data.
  124. * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
  125. * @param {Object} options The options config object passed to the {@link #request} method.
  126. */
  127. <span id='Ext-data-Connection-event-requestexception'> /**
  128. </span> * @event requestexception
  129. * Fires if an error HTTP status was returned from the server.
  130. * See [HTTP Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
  131. * for details of HTTP status codes.
  132. * @param {Ext.data.Connection} conn This Connection object.
  133. * @param {Object} response The XHR object containing the response data.
  134. * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
  135. * @param {Object} options The options config object passed to the {@link #request} method.
  136. */
  137. this.requests = {};
  138. this.mixins.observable.constructor.call(this);
  139. },
  140. <span id='Ext-data-Connection-method-request'> /**
  141. </span> * Sends an HTTP request to a remote server.
  142. *
  143. * **Important:** Ajax server requests are asynchronous, and this call will
  144. * return before the response has been received. Process any returned data
  145. * in a callback function.
  146. *
  147. * Ext.Ajax.request({
  148. * url: 'ajax_demo/sample.json',
  149. * success: function(response, opts) {
  150. * var obj = Ext.decode(response.responseText);
  151. * console.dir(obj);
  152. * },
  153. * failure: function(response, opts) {
  154. * console.log('server-side failure with status code ' + response.status);
  155. * }
  156. * });
  157. *
  158. * To execute a callback function in the correct scope, use the `scope` option.
  159. *
  160. * @param {Object} options An object which may contain the following properties:
  161. *
  162. * (The options object may also contain any other property which might be needed to perform
  163. * postprocessing in a callback because it is passed to callback functions.)
  164. *
  165. * @param {String/Function} options.url The URL to which to send the request, or a function
  166. * to call which returns a URL string. The scope of the function is specified by the `scope` option.
  167. * Defaults to the configured `url`.
  168. *
  169. * @param {Object/String/Function} options.params An object containing properties which are
  170. * used as parameters to the request, a url encoded string or a function to call to get either. The scope
  171. * of the function is specified by the `scope` option.
  172. *
  173. * @param {String} options.method The HTTP method to use
  174. * for the request. Defaults to the configured method, or if no method was configured,
  175. * &quot;GET&quot; if no parameters are being sent, and &quot;POST&quot; if parameters are being sent. Note that
  176. * the method name is case-sensitive and should be all caps.
  177. *
  178. * @param {Function} options.callback The function to be called upon receipt of the HTTP response.
  179. * The callback is called regardless of success or failure and is passed the following parameters:
  180. * @param {Object} options.callback.options The parameter to the request call.
  181. * @param {Boolean} options.callback.success True if the request succeeded.
  182. * @param {Object} options.callback.response The XMLHttpRequest object containing the response data.
  183. * See [www.w3.org/TR/XMLHttpRequest/](http://www.w3.org/TR/XMLHttpRequest/) for details about
  184. * accessing elements of the response.
  185. *
  186. * @param {Function} options.success The function to be called upon success of the request.
  187. * The callback is passed the following parameters:
  188. * @param {Object} options.success.response The XMLHttpRequest object containing the response data.
  189. * @param {Object} options.success.options The parameter to the request call.
  190. *
  191. * @param {Function} options.failure The function to be called upon failure of the request.
  192. * The callback is passed the following parameters:
  193. * @param {Object} options.failure.response The XMLHttpRequest object containing the response data.
  194. * @param {Object} options.failure.options The parameter to the request call.
  195. *
  196. * @param {Object} options.scope The scope in which to execute the callbacks: The &quot;this&quot; object for
  197. * the callback function. If the `url`, or `params` options were specified as functions from which to
  198. * draw values, then this also serves as the scope for those function calls. Defaults to the browser
  199. * window.
  200. *
  201. * @param {Number} options.timeout The timeout in milliseconds to be used for this request.
  202. * Defaults to 30 seconds.
  203. *
  204. * @param {Ext.Element/HTMLElement/String} options.form The `&lt;form&gt;` Element or the id of the `&lt;form&gt;`
  205. * to pull parameters from.
  206. *
  207. * @param {Boolean} options.isUpload **Only meaningful when used with the `form` option.**
  208. *
  209. * True if the form object is a file upload (will be set automatically if the form was configured
  210. * with **`enctype`** `&quot;multipart/form-data&quot;`).
  211. *
  212. * File uploads are not performed using normal &quot;Ajax&quot; techniques, that is they are **not**
  213. * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
  214. * DOM `&lt;form&gt;` element temporarily modified to have its [target][] set to refer to a dynamically
  215. * generated, hidden `&lt;iframe&gt;` which is inserted into the document but removed after the return data
  216. * has been gathered.
  217. *
  218. * The server response is parsed by the browser to create the document for the IFRAME. If the
  219. * server is using JSON to send the return object, then the [Content-Type][] header must be set to
  220. * &quot;text/html&quot; in order to tell the browser to insert the text unchanged into the document body.
  221. *
  222. * The response text is retrieved from the document, and a fake XMLHttpRequest object is created
  223. * containing a `responseText` property in order to conform to the requirements of event handlers
  224. * and callbacks.
  225. *
  226. * Be aware that file upload packets are sent with the content type [multipart/form][] and some server
  227. * technologies (notably JEE) may require some custom processing in order to retrieve parameter names
  228. * and parameter values from the packet content.
  229. *
  230. * [target]: http://www.w3.org/TR/REC-html40/present/frames.html#adef-target
  231. * [Content-Type]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
  232. * [multipart/form]: http://www.faqs.org/rfcs/rfc2388.html
  233. *
  234. * @param {Object} options.headers Request headers to set for the request.
  235. *
  236. * @param {Object} options.xmlData XML document to use for the post. Note: This will be used instead
  237. * of params for the post data. Any params will be appended to the URL.
  238. *
  239. * @param {Object/String} options.jsonData JSON data to use as the post. Note: This will be used
  240. * instead of params for the post data. Any params will be appended to the URL.
  241. *
  242. * @param {Boolean} options.disableCaching True to add a unique cache-buster param to GET requests.
  243. *
  244. * @param {Boolean} options.withCredentials True to add the withCredentials property to the XHR object
  245. *
  246. * @return {Object} The request object. This may be used to cancel the request.
  247. */
  248. request : function(options) {
  249. options = options || {};
  250. var me = this,
  251. scope = options.scope || window,
  252. username = options.username || me.username,
  253. password = options.password || me.password || '',
  254. async,
  255. requestOptions,
  256. request,
  257. headers,
  258. xhr;
  259. if (me.fireEvent('beforerequest', me, options) !== false) {
  260. requestOptions = me.setOptions(options, scope);
  261. if (me.isFormUpload(options)) {
  262. me.upload(options.form, requestOptions.url, requestOptions.data, options);
  263. return null;
  264. }
  265. // if autoabort is set, cancel the current transactions
  266. if (options.autoAbort || me.autoAbort) {
  267. me.abort();
  268. }
  269. // create a connection object
  270. async = options.async !== false ? (options.async || me.async) : false;
  271. xhr = me.openRequest(options, requestOptions, async, username, password);
  272. headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);
  273. // create the transaction object
  274. request = {
  275. id: ++Ext.data.Connection.requestId,
  276. xhr: xhr,
  277. headers: headers,
  278. options: options,
  279. async: async,
  280. timeout: setTimeout(function() {
  281. request.timedout = true;
  282. me.abort(request);
  283. }, options.timeout || me.timeout)
  284. };
  285. me.requests[request.id] = request;
  286. me.latestId = request.id;
  287. // bind our statechange listener
  288. if (async) {
  289. xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
  290. }
  291. // start the request!
  292. xhr.send(requestOptions.data);
  293. if (!async) {
  294. return me.onComplete(request);
  295. }
  296. return request;
  297. } else {
  298. Ext.callback(options.callback, options.scope, [options, undefined, undefined]);
  299. return null;
  300. }
  301. },
  302. <span id='Ext-data-Connection-method-upload'> /**
  303. </span> * Uploads a form using a hidden iframe.
  304. * @param {String/HTMLElement/Ext.Element} form The form to upload
  305. * @param {String} url The url to post to
  306. * @param {String} params Any extra parameters to pass
  307. * @param {Object} options The initial options
  308. */
  309. upload: function(form, url, params, options) {
  310. form = Ext.getDom(form);
  311. options = options || {};
  312. var id = Ext.id(),
  313. frame = document.createElement('iframe'),
  314. hiddens = [],
  315. encoding = 'multipart/form-data',
  316. buf = {
  317. target: form.target,
  318. method: form.method,
  319. encoding: form.encoding,
  320. enctype: form.enctype,
  321. action: form.action
  322. },
  323. addField = function(name, value) {
  324. hiddenItem = document.createElement('input');
  325. Ext.fly(hiddenItem).set({
  326. type: 'hidden',
  327. value: value,
  328. name: name
  329. });
  330. form.appendChild(hiddenItem);
  331. hiddens.push(hiddenItem);
  332. },
  333. hiddenItem, obj, value, name, vLen, v, hLen, h;
  334. /*
  335. * Originally this behaviour was modified for Opera 10 to apply the secure URL after
  336. * the frame had been added to the document. It seems this has since been corrected in
  337. * Opera so the behaviour has been reverted, the URL will be set before being added.
  338. */
  339. Ext.fly(frame).set({
  340. id: id,
  341. name: id,
  342. cls: Ext.baseCSSPrefix + 'hide-display',
  343. src: Ext.SSL_SECURE_URL
  344. });
  345. document.body.appendChild(frame);
  346. // This is required so that IE doesn't pop the response up in a new window.
  347. if (document.frames) {
  348. document.frames[id].name = id;
  349. }
  350. Ext.fly(form).set({
  351. target: id,
  352. method: 'POST',
  353. enctype: encoding,
  354. encoding: encoding,
  355. action: url || buf.action
  356. });
  357. // add dynamic params
  358. if (params) {
  359. obj = Ext.Object.fromQueryString(params) || {};
  360. for (name in obj) {
  361. if (obj.hasOwnProperty(name)) {
  362. value = obj[name];
  363. if (Ext.isArray(value)) {
  364. vLen = value.length;
  365. for (v = 0; v &lt; vLen; v++) {
  366. addField(name, value[v]);
  367. }
  368. } else {
  369. addField(name, value);
  370. }
  371. }
  372. }
  373. }
  374. Ext.fly(frame).on('load', Ext.Function.bind(this.onUploadComplete, this, [frame, options]), null, {single: true});
  375. form.submit();
  376. Ext.fly(form).set(buf);
  377. hLen = hiddens.length;
  378. for (h = 0; h &lt; hLen; h++) {
  379. Ext.removeNode(hiddens[h]);
  380. }
  381. },
  382. <span id='Ext-data-Connection-method-onUploadComplete'> /**
  383. </span> * @private
  384. * Callback handler for the upload function. After we've submitted the form via the iframe this creates a bogus
  385. * response object to simulate an XHR and populates its responseText from the now-loaded iframe's document body
  386. * (or a textarea inside the body). We then clean up by removing the iframe
  387. */
  388. onUploadComplete: function(frame, options) {
  389. var me = this,
  390. // bogus response object
  391. response = {
  392. responseText: '',
  393. responseXML: null
  394. }, doc, contentNode;
  395. try {
  396. doc = frame.contentWindow.document || frame.contentDocument || window.frames[frame.id].document;
  397. if (doc) {
  398. if (doc.body) {
  399. // Response sent as Content-Type: text/json or text/plain. Browser will embed in a &lt;pre&gt; element
  400. // Note: The statement below tests the result of an assignment.
  401. if ((contentNode = doc.body.firstChild) &amp;&amp; /pre/i.test(contentNode.tagName)) {
  402. response.responseText = contentNode.innerText;
  403. }
  404. // Response sent as Content-Type: text/html. We must still support JSON response wrapped in textarea.
  405. // Note: The statement below tests the result of an assignment.
  406. else if (contentNode = doc.getElementsByTagName('textarea')[0]) {
  407. response.responseText = contentNode.value;
  408. }
  409. // Response sent as Content-Type: text/html with no wrapping. Scrape JSON response out of text
  410. else {
  411. response.responseText = doc.body.textContent || doc.body.innerText;
  412. }
  413. }
  414. //in IE the document may still have a body even if returns XML.
  415. response.responseXML = doc.XMLDocument || doc;
  416. }
  417. } catch (e) {
  418. }
  419. me.fireEvent('requestcomplete', me, response, options);
  420. Ext.callback(options.success, options.scope, [response, options]);
  421. Ext.callback(options.callback, options.scope, [options, true, response]);
  422. setTimeout(function() {
  423. Ext.removeNode(frame);
  424. }, 100);
  425. },
  426. <span id='Ext-data-Connection-method-isFormUpload'> /**
  427. </span> * Detects whether the form is intended to be used for an upload.
  428. * @private
  429. */
  430. isFormUpload: function(options) {
  431. var form = this.getForm(options);
  432. if (form) {
  433. return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
  434. }
  435. return false;
  436. },
  437. <span id='Ext-data-Connection-method-getForm'> /**
  438. </span> * Gets the form object from options.
  439. * @private
  440. * @param {Object} options The request options
  441. * @return {HTMLElement} The form, null if not passed
  442. */
  443. getForm: function(options) {
  444. return Ext.getDom(options.form) || null;
  445. },
  446. <span id='Ext-data-Connection-method-setOptions'> /**
  447. </span> * Sets various options such as the url, params for the request
  448. * @param {Object} options The initial options
  449. * @param {Object} scope The scope to execute in
  450. * @return {Object} The params for the request
  451. */
  452. setOptions: function(options, scope) {
  453. var me = this,
  454. params = options.params || {},
  455. extraParams = me.extraParams,
  456. urlParams = options.urlParams,
  457. url = options.url || me.url,
  458. jsonData = options.jsonData,
  459. method,
  460. disableCache,
  461. data;
  462. // allow params to be a method that returns the params object
  463. if (Ext.isFunction(params)) {
  464. params = params.call(scope, options);
  465. }
  466. // allow url to be a method that returns the actual url
  467. if (Ext.isFunction(url)) {
  468. url = url.call(scope, options);
  469. }
  470. url = this.setupUrl(options, url);
  471. //&lt;debug&gt;
  472. if (!url) {
  473. Ext.Error.raise({
  474. options: options,
  475. msg: 'No URL specified'
  476. });
  477. }
  478. //&lt;/debug&gt;
  479. // check for xml or json data, and make sure json data is encoded
  480. data = options.rawData || options.xmlData || jsonData || null;
  481. if (jsonData &amp;&amp; !Ext.isPrimitive(jsonData)) {
  482. data = Ext.encode(data);
  483. }
  484. // make sure params are a url encoded string and include any extraParams if specified
  485. if (Ext.isObject(params)) {
  486. params = Ext.Object.toQueryString(params);
  487. }
  488. if (Ext.isObject(extraParams)) {
  489. extraParams = Ext.Object.toQueryString(extraParams);
  490. }
  491. params = params + ((extraParams) ? ((params) ? '&amp;' : '') + extraParams : '');
  492. urlParams = Ext.isObject(urlParams) ? Ext.Object.toQueryString(urlParams) : urlParams;
  493. params = this.setupParams(options, params);
  494. // decide the proper method for this request
  495. method = (options.method || me.method || ((params || data) ? 'POST' : 'GET')).toUpperCase();
  496. this.setupMethod(options, method);
  497. disableCache = options.disableCaching !== false ? (options.disableCaching || me.disableCaching) : false;
  498. // if the method is get append date to prevent caching
  499. if (method === 'GET' &amp;&amp; disableCache) {
  500. url = Ext.urlAppend(url, (options.disableCachingParam || me.disableCachingParam) + '=' + (new Date().getTime()));
  501. }
  502. // if the method is get or there is json/xml data append the params to the url
  503. if ((method == 'GET' || data) &amp;&amp; params) {
  504. url = Ext.urlAppend(url, params);
  505. params = null;
  506. }
  507. // allow params to be forced into the url
  508. if (urlParams) {
  509. url = Ext.urlAppend(url, urlParams);
  510. }
  511. return {
  512. url: url,
  513. method: method,
  514. data: data || params || null
  515. };
  516. },
  517. <span id='Ext-data-Connection-method-setupUrl'> /**
  518. </span> * Template method for overriding url
  519. * @template
  520. * @private
  521. * @param {Object} options
  522. * @param {String} url
  523. * @return {String} The modified url
  524. */
  525. setupUrl: function(options, url) {
  526. var form = this.getForm(options);
  527. if (form) {
  528. url = url || form.action;
  529. }
  530. return url;
  531. },
  532. <span id='Ext-data-Connection-method-setupParams'> /**
  533. </span> * Template method for overriding params
  534. * @template
  535. * @private
  536. * @param {Object} options
  537. * @param {String} params
  538. * @return {String} The modified params
  539. */
  540. setupParams: function(options, params) {
  541. var form = this.getForm(options),
  542. serializedForm;
  543. if (form &amp;&amp; !this.isFormUpload(options)) {
  544. serializedForm = Ext.Element.serializeForm(form);
  545. params = params ? (params + '&amp;' + serializedForm) : serializedForm;
  546. }
  547. return params;
  548. },
  549. <span id='Ext-data-Connection-method-setupMethod'> /**
  550. </span> * Template method for overriding method
  551. * @template
  552. * @private
  553. * @param {Object} options
  554. * @param {String} method
  555. * @return {String} The modified method
  556. */
  557. setupMethod: function(options, method) {
  558. if (this.isFormUpload(options)) {
  559. return 'POST';
  560. }
  561. return method;
  562. },
  563. <span id='Ext-data-Connection-method-setupHeaders'> /**
  564. </span> * Setup all the headers for the request
  565. * @private
  566. * @param {Object} xhr The xhr object
  567. * @param {Object} options The options for the request
  568. * @param {Object} data The data for the request
  569. * @param {Object} params The params for the request
  570. */
  571. setupHeaders: function(xhr, options, data, params) {
  572. var me = this,
  573. headers = Ext.apply({}, options.headers || {}, me.defaultHeaders || {}),
  574. contentType = me.defaultPostHeader,
  575. jsonData = options.jsonData,
  576. xmlData = options.xmlData,
  577. key,
  578. header;
  579. if (!headers['Content-Type'] &amp;&amp; (data || params)) {
  580. if (data) {
  581. if (options.rawData) {
  582. contentType = 'text/plain';
  583. } else {
  584. if (xmlData &amp;&amp; Ext.isDefined(xmlData)) {
  585. contentType = 'text/xml';
  586. } else if (jsonData &amp;&amp; Ext.isDefined(jsonData)) {
  587. contentType = 'application/json';
  588. }
  589. }
  590. }
  591. headers['Content-Type'] = contentType;
  592. }
  593. if (me.useDefaultXhrHeader &amp;&amp; !headers['X-Requested-With']) {
  594. headers['X-Requested-With'] = me.defaultXhrHeader;
  595. }
  596. // set up all the request headers on the xhr object
  597. try {
  598. for (key in headers) {
  599. if (headers.hasOwnProperty(key)) {
  600. header = headers[key];
  601. xhr.setRequestHeader(key, header);
  602. }
  603. }
  604. } catch(e) {
  605. me.fireEvent('exception', key, header);
  606. }
  607. return headers;
  608. },
  609. <span id='Ext-data-Connection-method-newRequest'> /**
  610. </span> * Creates the appropriate XHR transport for a given request on this browser. On IE
  611. * this may be an `XDomainRequest` rather than an `XMLHttpRequest`.
  612. * @private
  613. */
  614. newRequest: function (options) {
  615. var xhr;
  616. if ((options.cors || this.cors) &amp;&amp; Ext.isIE &amp;&amp; Ext.ieVersion &gt;= 8) {
  617. xhr = new XDomainRequest();
  618. } else {
  619. xhr = this.getXhrInstance();
  620. }
  621. return xhr;
  622. },
  623. <span id='Ext-data-Connection-method-openRequest'> /**
  624. </span> * Creates and opens an appropriate XHR transport for a given request on this browser.
  625. * This logic is contained in an individual method to allow for overrides to process all
  626. * of the parameters and options and return a suitable, open connection.
  627. * @private
  628. */
  629. openRequest: function (options, requestOptions, async, username, password) {
  630. var xhr = this.newRequest(options);
  631. if (username) {
  632. xhr.open(requestOptions.method, requestOptions.url, async, username, password);
  633. } else {
  634. xhr.open(requestOptions.method, requestOptions.url, async);
  635. }
  636. if (options.withCredentials || this.withCredentials) {
  637. xhr.withCredentials = true;
  638. }
  639. return xhr;
  640. },
  641. <span id='Ext-data-Connection-property-getXhrInstance'> /**
  642. </span> * Creates the appropriate XHR transport for this browser.
  643. * @private
  644. */
  645. getXhrInstance: (function() {
  646. var options = [function() {
  647. return new XMLHttpRequest();
  648. }, function() {
  649. return new ActiveXObject('MSXML2.XMLHTTP.3.0');
  650. }, function() {
  651. return new ActiveXObject('MSXML2.XMLHTTP');
  652. }, function() {
  653. return new ActiveXObject('Microsoft.XMLHTTP');
  654. }], i = 0,
  655. len = options.length,
  656. xhr;
  657. for (; i &lt; len; ++i) {
  658. try {
  659. xhr = options[i];
  660. xhr();
  661. break;
  662. } catch(e) {
  663. }
  664. }
  665. return xhr;
  666. }()),
  667. <span id='Ext-data-Connection-method-isLoading'> /**
  668. </span> * Determines whether this object has a request outstanding.
  669. * @param {Object} [request] Defaults to the last transaction
  670. * @return {Boolean} True if there is an outstanding request.
  671. */
  672. isLoading : function(request) {
  673. if (!request) {
  674. request = this.getLatest();
  675. }
  676. if (!(request &amp;&amp; request.xhr)) {
  677. return false;
  678. }
  679. // if there is a connection and readyState is not 0 or 4
  680. var state = request.xhr.readyState;
  681. return !(state === 0 || state == 4);
  682. },
  683. <span id='Ext-data-Connection-method-abort'> /**
  684. </span> * Aborts an active request.
  685. * @param {Object} [request] Defaults to the last request
  686. */
  687. abort : function(request) {
  688. var me = this,
  689. xhr;
  690. if (!request) {
  691. request = me.getLatest();
  692. }
  693. if (request &amp;&amp; me.isLoading(request)) {
  694. /*
  695. * Clear out the onreadystatechange here, this allows us
  696. * greater control, the browser may/may not fire the function
  697. * depending on a series of conditions.
  698. */
  699. xhr = request.xhr;
  700. try {
  701. xhr.onreadystatechange = null;
  702. } catch (e) {
  703. // Setting onreadystatechange to null can cause problems in IE, see
  704. // http://www.quirksmode.org/blog/archives/2005/09/xmlhttp_notes_a_1.html
  705. xhr = Ext.emptyFn;
  706. }
  707. xhr.abort();
  708. me.clearTimeout(request);
  709. if (!request.timedout) {
  710. request.aborted = true;
  711. }
  712. me.onComplete(request);
  713. me.cleanup(request);
  714. }
  715. },
  716. <span id='Ext-data-Connection-method-abortAll'> /**
  717. </span> * Aborts all active requests
  718. */
  719. abortAll: function(){
  720. var requests = this.requests,
  721. id;
  722. for (id in requests) {
  723. if (requests.hasOwnProperty(id)) {
  724. this.abort(requests[id]);
  725. }
  726. }
  727. },
  728. <span id='Ext-data-Connection-method-getLatest'> /**
  729. </span> * Gets the most recent request
  730. * @private
  731. * @return {Object} The request. Null if there is no recent request
  732. */
  733. getLatest: function(){
  734. var id = this.latestId,
  735. request;
  736. if (id) {
  737. request = this.requests[id];
  738. }
  739. return request || null;
  740. },
  741. <span id='Ext-data-Connection-method-onStateChange'> /**
  742. </span> * Fires when the state of the xhr changes
  743. * @private
  744. * @param {Object} request The request
  745. */
  746. onStateChange : function(request) {
  747. if (request.xhr.readyState == 4) {
  748. this.clearTimeout(request);
  749. this.onComplete(request);
  750. this.cleanup(request);
  751. }
  752. },
  753. <span id='Ext-data-Connection-method-clearTimeout'> /**
  754. </span> * Clears the timeout on the request
  755. * @private
  756. * @param {Object} The request
  757. */
  758. clearTimeout: function(request) {
  759. clearTimeout(request.timeout);
  760. delete request.timeout;
  761. },
  762. <span id='Ext-data-Connection-method-cleanup'> /**
  763. </span> * Cleans up any left over information from the request
  764. * @private
  765. * @param {Object} The request
  766. */
  767. cleanup: function(request) {
  768. request.xhr = null;
  769. delete request.xhr;
  770. },
  771. <span id='Ext-data-Connection-method-onComplete'> /**
  772. </span> * To be called when the request has come back from the server
  773. * @private
  774. * @param {Object} request
  775. * @return {Object} The response
  776. */
  777. onComplete : function(request) {
  778. var me = this,
  779. options = request.options,
  780. result,
  781. success,
  782. response;
  783. try {
  784. result = me.parseStatus(request.xhr.status);
  785. } catch (e) {
  786. // in some browsers we can't access the status if the readyState is not 4, so the request has failed
  787. result = {
  788. success : false,
  789. isException : false
  790. };
  791. }
  792. success = result.success;
  793. if (success) {
  794. response = me.createResponse(request);
  795. me.fireEvent('requestcomplete', me, response, options);
  796. Ext.callback(options.success, options.scope, [response, options]);
  797. } else {
  798. if (result.isException || request.aborted || request.timedout) {
  799. response = me.createException(request);
  800. } else {
  801. response = me.createResponse(request);
  802. }
  803. me.fireEvent('requestexception', me, response, options);
  804. Ext.callback(options.failure, options.scope, [response, options]);
  805. }
  806. Ext.callback(options.callback, options.scope, [options, success, response]);
  807. delete me.requests[request.id];
  808. return response;
  809. },
  810. <span id='Ext-data-Connection-method-parseStatus'> /**
  811. </span> * Checks if the response status was successful
  812. * @param {Number} status The status code
  813. * @return {Object} An object containing success/status state
  814. */
  815. parseStatus: function(status) {
  816. // see: https://prototype.lighthouseapp.com/projects/8886/tickets/129-ie-mangles-http-response-status-code-204-to-1223
  817. status = status == 1223 ? 204 : status;
  818. var success = (status &gt;= 200 &amp;&amp; status &lt; 300) || status == 304,
  819. isException = false;
  820. if (!success) {
  821. switch (status) {
  822. case 12002:
  823. case 12029:
  824. case 12030:
  825. case 12031:
  826. case 12152:
  827. case 13030:
  828. isException = true;
  829. break;
  830. }
  831. }
  832. return {
  833. success: success,
  834. isException: isException
  835. };
  836. },
  837. <span id='Ext-data-Connection-method-createResponse'> /**
  838. </span> * Creates the response object
  839. * @private
  840. * @param {Object} request
  841. */
  842. createResponse : function(request) {
  843. var xhr = request.xhr,
  844. headers = {},
  845. lines = xhr.getAllResponseHeaders().replace(/\r\n/g, '\n').split('\n'),
  846. count = lines.length,
  847. line, index, key, value, response;
  848. while (count--) {
  849. line = lines[count];
  850. index = line.indexOf(':');
  851. if (index &gt;= 0) {
  852. key = line.substr(0, index).toLowerCase();
  853. if (line.charAt(index + 1) == ' ') {
  854. ++index;
  855. }
  856. headers[key] = line.substr(index + 1);
  857. }
  858. }
  859. request.xhr = null;
  860. delete request.xhr;
  861. response = {
  862. request: request,
  863. requestId : request.id,
  864. status : xhr.status,
  865. statusText : xhr.statusText,
  866. getResponseHeader : function(header) {
  867. return headers[header.toLowerCase()];
  868. },
  869. getAllResponseHeaders : function() {
  870. return headers;
  871. },
  872. responseText : xhr.responseText,
  873. responseXML : xhr.responseXML
  874. };
  875. // If we don't explicitly tear down the xhr reference, IE6/IE7 will hold this in the closure of the
  876. // functions created with getResponseHeader/getAllResponseHeaders
  877. xhr = null;
  878. return response;
  879. },
  880. <span id='Ext-data-Connection-method-createException'> /**
  881. </span> * Creates the exception object
  882. * @private
  883. * @param {Object} request
  884. */
  885. createException : function(request) {
  886. return {
  887. request : request,
  888. requestId : request.id,
  889. status : request.aborted ? -1 : 0,
  890. statusText : request.aborted ? 'transaction aborted' : 'communication failure',
  891. aborted: request.aborted,
  892. timedout: request.timedout
  893. };
  894. }
  895. });
  896. </pre>
  897. </body>
  898. </html>