]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/direct/RemotingProvider.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / direct / RemotingProvider.js
CommitLineData
6527f429
DM
1/**\r
2 * The {@link Ext.direct.RemotingProvider RemotingProvider} exposes access to\r
3 * server side methods on the client (a remote procedure call (RPC) type of\r
4 * connection where the client can initiate a procedure on the server).\r
5 * \r
6 * This allows for code to be organized in a fashion that is maintainable,\r
7 * while providing a clear path between client and server, something that is\r
8 * not always apparent when using URLs.\r
9 * \r
10 * To accomplish this the server-side needs to describe what classes and methods\r
11 * are available on the client-side. This configuration will typically be\r
12 * outputted by the server-side Ext Direct stack when the API description is built.\r
13 */\r
14Ext.define('Ext.direct.RemotingProvider', {\r
15 extend: 'Ext.direct.JsonProvider', \r
16 alias: 'direct.remotingprovider',\r
17 \r
18 requires: [\r
19 'Ext.util.MixedCollection', \r
20 'Ext.util.DelayedTask', \r
21 'Ext.direct.Transaction',\r
22 'Ext.direct.RemotingMethod',\r
23 'Ext.direct.Manager'\r
24 ],\r
25 \r
26 type: 'remoting',\r
27 \r
28 /**\r
29 * @cfg {Object} actions\r
30 *\r
31 * Object literal defining the server side actions and methods. For example, if\r
32 * the Provider is configured with:\r
33 *\r
34 * // each property within the 'actions' object represents a server side Class\r
35 * actions: {\r
36 * // array of methods in each server side Class to be stubbed out on client\r
37 * TestAction: [{\r
38 * name: 'doEcho', // stub method will be TestAction.doEcho\r
39 * len: 1,\r
40 * batched: false // always send requests immediately for this method\r
41 * }, {\r
42 * name: 'multiply', // name of method\r
43 * len: 2 // The number of parameters that will be used to create an\r
44 * // array of data to send to the server side function.\r
45 * }, {\r
46 * name: 'doForm',\r
47 * formHandler: true // tells the client that this method handles form calls\r
48 * }],\r
49 * \r
50 * // These methods will be created in nested namespace TestAction.Foo\r
51 * 'TestAction.Foo': [{\r
52 * name: 'ordered', // stub method will be TestAction.Foo.ordered\r
53 * len: 1\r
54 * }, {\r
55 * name: 'noParams', // this method does not accept any parameters\r
56 * len: 0\r
57 * }, {\r
58 * name: 'named', // stub method will be TestAction.Foo.named\r
59 * params: ['foo', 'bar'] // parameters are passed by name\r
60 * }, {\r
61 * name: 'namedNoStrict',\r
62 * params: [], // this method accepts parameters by name\r
63 * strict: false // but does not check if they are required\r
64 * // and will pass any to the server side\r
65 * }]\r
66 * }\r
67 *\r
68 * Note that starting with 4.2, dotted Action names will generate nested objects.\r
69 * If you wish to reverse to previous behavior, set {@link #cfg-disableNestedActions}\r
70 * to `true`.\r
71 *\r
72 * In the following example a *client side* handler is used to call the\r
73 * server side method "multiply" in the server-side "TestAction" Class:\r
74 *\r
75 * TestAction.multiply(\r
76 * // pass two arguments to server, so specify len=2\r
77 * 2, 4,\r
78 * \r
79 * // callback function after the server is called\r
80 * // result: the result returned by the server\r
81 * // e: Ext.direct.RemotingEvent object\r
82 * // success: true or false\r
83 * // options: options to be applied to method call and passed to callback\r
84 * function (result, e, success, options) {\r
85 * var t, action, method;\r
86 * \r
87 * t = e.getTransaction();\r
88 * action = t.action; // server side Class called\r
89 * method = t.method; // server side method called\r
90 * \r
91 * if (e.status) {\r
92 * var answer = Ext.encode(result); // 8\r
93 * }\r
94 * else {\r
95 * var msg = e.message; // failure message\r
96 * }\r
97 * },\r
98 * \r
99 * // Scope to call the callback in (optional)\r
100 * window,\r
101 * \r
102 * // Options to apply to this method call. This can include\r
103 * // Ajax.request() options; only `timeout` is supported at this time.\r
104 * // When timeout is set for a method call, it will be executed immediately\r
105 * // without buffering.\r
106 * // The same options object is passed to the callback so it's possible\r
107 * // to "forward" some data when needed.\r
108 * {\r
109 * timeout: 60000, // milliseconds\r
110 * foo: 'bar'\r
111 * }\r
112 * );\r
113 *\r
114 * In the example above, the server side "multiply" function will be passed two\r
115 * arguments (2 and 4). The "multiply" method should return the value 8 which will be\r
116 * available as the `result` in the callback example above. \r
117 */\r
118 \r
119 /**\r
120 * @cfg {Boolean} [disableNestedActions=false]\r
121 * In versions prior to 4.2, using dotted Action names was not really meaningful,\r
122 * because it generated flat {@link #cfg-namespace} object with dotted property names.\r
123 * For example, take this API declaration:\r
124 *\r
125 * {\r
126 * actions: {\r
127 * TestAction: [{\r
128 * name: 'foo',\r
129 * len: 1\r
130 * }],\r
131 * 'TestAction.Foo' [{\r
132 * name: 'bar',\r
133 * len: 1\r
134 * }]\r
135 * },\r
136 * namespace: 'MyApp'\r
137 * }\r
138 *\r
139 * Before 4.2, that would generate the following API object:\r
140 *\r
141 * window.MyApp = {\r
142 * TestAction: {\r
143 * foo: function() { ... }\r
144 * },\r
145 * 'TestAction.Foo': {\r
146 * bar: function() { ... }\r
147 * }\r
148 * }\r
149 *\r
150 * In Ext JS 4.2, we introduced new namespace handling behavior. Now the same API object\r
151 * will be like this:\r
152 *\r
153 * window.MyApp = {\r
154 * TestAction: {\r
155 * foo: function() { ... },\r
156 *\r
157 * Foo: {\r
158 * bar: function() { ... }\r
159 * }\r
160 * }\r
161 * }\r
162 *\r
163 * Instead of addressing Action methods array-style `MyApp['TestAction.Foo'].bar()`,\r
164 * now it is possible to use object addressing: `MyApp.TestAction.Foo.bar()`.\r
165 *\r
166 * If you find this behavior undesirable, set this config option to `true`.\r
167 */\r
168 \r
169 /**\r
170 * @cfg {String/Object} namespace\r
171 *\r
172 * Namespace for the Remoting Provider (defaults to `Ext.global`).\r
173 * Explicitly specify the namespace Object, or specify a String to have a\r
174 * {@link Ext#namespace namespace} created implicitly.\r
175 */\r
176 \r
177 /**\r
178 * @cfg {String} url\r
179 *\r
180 * **Required**. The url to connect to the {@link Ext.direct.Manager} server-side router. \r
181 */\r
182 \r
183 /**\r
184 * @cfg {String} [enableUrlEncode=data]\r
185 *\r
186 * Specify which param will hold the arguments for the method.\r
187 */\r
188 \r
189 /**\r
190 * @cfg {Number/Boolean} [enableBuffer=10]\r
191 *\r
192 * `true` or `false` to enable or disable combining of method\r
193 * calls. If a number is specified this is the amount of time in milliseconds\r
194 * to wait before sending a batched request.\r
195 *\r
196 * Calls which are received within the specified timeframe will be\r
197 * concatenated together and sent in a single request, optimizing the\r
198 * application by reducing the amount of round trips that have to be made\r
199 * to the server. To cancel buffering for some particular invocations, pass\r
200 * `timeout` parameter in `options` object for that method call.\r
201 */\r
202 enableBuffer: 10,\r
203 \r
204 /**\r
205 * @cfg {Number} bufferLimit The maximum number of requests to batch together.\r
206 * By default, an unlimited number of requests will be batched. This option will\r
207 * allow to wait only for a certain number of Direct method calls before\r
208 * dispatching a request to the server, even if {@link #enableBuffer} timeout\r
209 * has not yet expired.\r
210 * \r
211 * Note that this option does nothing if {@link #enableBuffer} is set to `false`.\r
212 */\r
213 bufferLimit: Number.MAX_VALUE,\r
214 \r
215 /**\r
216 * @cfg {Number} [maxRetries=1]\r
217 *\r
218 * Number of times to re-attempt delivery on failure of a call.\r
219 */\r
220 maxRetries: 1,\r
221 \r
222 /**\r
223 * @cfg {Number} [timeout]\r
224 *\r
225 * The timeout to use for each request.\r
226 */\r
227 \r
228 /**\r
229 * @event beforecall\r
230 * @preventable\r
231 *\r
232 * Fires immediately before the client-side sends off the RPC call. By returning\r
233 * `false` from an event handler you can prevent the call from being made.\r
234 *\r
235 * @param {Ext.direct.RemotingProvider} provider\r
236 * @param {Ext.direct.Transaction} transaction\r
237 * @param {Object} meta The meta data\r
238 */ \r
239\r
240 /**\r
241 * @event call\r
242 *\r
243 * Fires immediately after the request to the server-side is sent. This does\r
244 * NOT fire after the response has come back from the call.\r
245 *\r
246 * @param {Ext.direct.RemotingProvider} provider\r
247 * @param {Ext.direct.Transaction} transaction\r
248 * @param {Object} meta The meta data\r
249 */ \r
250\r
251 /**\r
252 * @event beforecallback\r
253 * @preventable\r
254 *\r
255 * Fires before callback function is executed. By returning `false` from an event handler\r
256 * you can prevent the callback from executing.\r
257 *\r
258 * @param {Ext.direct.RemotingProvider} provider The provider instance\r
259 * @param {Ext.direct.Event} event Event associated with the callback invocation\r
260 * @param {Ext.direct.Transaction} transaction Transaction for which the callback\r
261 * is about to be fired\r
262 */\r
263\r
264 constructor: function(config) {\r
265 var me = this;\r
266\r
267 me.callParent(arguments);\r
268\r
269 me.namespace = (Ext.isString(me.namespace)) ? Ext.ns(me.namespace) : me.namespace || Ext.global;\r
270 me.transactions = new Ext.util.MixedCollection();\r
271 me.callBuffer = [];\r
272 },\r
273 \r
274 doConnect: function() {\r
275 if (!this.apiCreated) {\r
276 this.initAPI();\r
277 this.apiCreated = true;\r
278 }\r
279 },\r
280 \r
281 /**\r
282 * Get nested namespace by property.\r
283 *\r
284 * @private\r
285 */\r
286 getNamespace: function(root, action) {\r
287 var parts, ns, i, len;\r
288 \r
289 root = root || Ext.global;\r
290 parts = action.toString().split('.');\r
291\r
292 for (i = 0, len = parts.length; i < len; i++) {\r
293 ns = parts[i];\r
294 root = root[ns];\r
295\r
296 if (typeof root === 'undefined') {\r
297 return root;\r
298 }\r
299 }\r
300\r
301 return root;\r
302 },\r
303\r
304 /**\r
305 * Create nested namespaces. Unlike {@link Ext#ns} this method supports\r
306 * nested objects as root of the namespace, not only Ext.global (window).\r
307 *\r
308 * @private\r
309 */\r
310 createNamespaces: function(root, action) {\r
311 var parts, ns, i, len;\r
312 \r
313 root = root || Ext.global;\r
314 parts = action.toString().split('.');\r
315 \r
316 for (i = 0, len = parts.length; i < len; i++) {\r
317 ns = parts[i];\r
318 \r
319 root[ns] = root[ns] || {};\r
320 root = root[ns];\r
321 }\r
322 \r
323 return root;\r
324 },\r
325 \r
326 /**\r
327 * Initialize the API\r
328 *\r
329 * @private\r
330 */\r
331 initAPI: function() {\r
332 var me = this,\r
333 actions = me.actions,\r
334 namespace = me.namespace,\r
335 Manager = Ext.direct.Manager,\r
336 action, cls, methods, i, len, method, handler;\r
337 \r
338 for (action in actions) {\r
339 if (actions.hasOwnProperty(action)) {\r
340 if (me.disableNestedActions) {\r
341 cls = namespace[action];\r
342 \r
343 if (!cls) {\r
344 cls = namespace[action] = {};\r
345 }\r
346 }\r
347 else {\r
348 cls = me.getNamespace(namespace, action);\r
349\r
350 if (!cls) {\r
351 cls = me.createNamespaces(namespace, action);\r
352 }\r
353 }\r
354\r
355 methods = actions[action];\r
356\r
357 for (i = 0, len = methods.length; i < len; ++i) {\r
358 method = new Ext.direct.RemotingMethod(methods[i]);\r
359 cls[method.name] = handler = me.createHandler(action, method);\r
360 \r
361 Manager.registerMethod(handler.$name, handler);\r
362 }\r
363 }\r
364 }\r
365 },\r
366 \r
367 /**\r
368 * Create a handler function for a direct call.\r
369 *\r
370 * @param {String} action The action the call is for\r
371 * @param {Object} method The details of the method\r
372 *\r
373 * @return {Function} A JS function that will kick off the call\r
374 *\r
375 * @private\r
376 */\r
377 createHandler: function(action, method) {\r
378 var me = this,\r
379 slice = Array.prototype.slice,\r
380 handler;\r
381 \r
382 if (!method.formHandler) {\r
383 handler = function() {\r
384 me.configureRequest(action, method, slice.call(arguments, 0));\r
385 };\r
386 }\r
387 else {\r
388 handler = function() {\r
389 me.configureFormRequest(action, method, slice.call(arguments, 0));\r
390 };\r
391 }\r
392 \r
393 handler.name = handler.$name = action + '.' + method.name;\r
394 handler.$directFn = true;\r
395 \r
396 handler.directCfg = handler.$directCfg = {\r
397 action: action,\r
398 method: method\r
399 };\r
400\r
401 return handler;\r
402 },\r
403 \r
404 /**\r
405 * @inheritdoc\r
406 */\r
407 connect: function() {\r
408 var me = this;\r
409\r
410 //<debug>\r
411 if (!me.url) {\r
412 Ext.raise('Error initializing RemotingProvider "' + me.id +\r
413 '", no url configured.');\r
414 }\r
415 //</debug>\r
416 \r
417 me.callParent();\r
418 },\r
419\r
420 /**\r
421 * Run any callbacks related to the transaction.\r
422 *\r
423 * @param {Ext.direct.Transaction} transaction The transaction\r
424 * @param {Ext.direct.Event} event The event\r
425 *\r
426 * @private\r
427 */\r
428 runCallback: function(transaction, event) {\r
429 var success = !!event.status,\r
430 funcName = success ? 'success' : 'failure',\r
431 callback, options, result;\r
432 \r
433 if (transaction && transaction.callback) {\r
434 callback = transaction.callback;\r
435 options = transaction.callbackOptions;\r
436 result = typeof event.result !== 'undefined' ? event.result : event.data;\r
437\r
438 if (Ext.isFunction(callback)) {\r
439 callback(result, event, success, options);\r
440 }\r
441 else {\r
442 Ext.callback(callback[funcName], callback.scope, [result, event, success, options]);\r
443 Ext.callback(callback.callback, callback.scope, [result, event, success, options]);\r
444 }\r
445 }\r
446 },\r
447 \r
448 /**\r
449 * React to the ajax request being completed\r
450 *\r
451 * @private\r
452 */\r
453 onData: function(options, success, response) {\r
454 var me = this,\r
455 i, len, events, event, transaction, transactions;\r
456 \r
457 if (success) {\r
458 events = me.createEvents(response);\r
459\r
460 for (i = 0, len = events.length; i < len; ++i) {\r
461 event = events[i];\r
462 transaction = me.getTransaction(event);\r
463 me.fireEvent('data', me, event);\r
464\r
465 if (transaction && me.fireEvent('beforecallback', me, event, transaction) !== false) {\r
466 me.runCallback(transaction, event, true);\r
467 }\r
468 \r
469 Ext.direct.Manager.removeTransaction(transaction);\r
470 }\r
471 }\r
472 else {\r
473 transactions = [].concat(options.transaction);\r
474 \r
475 for (i = 0, len = transactions.length; i < len; ++i) {\r
476 transaction = me.getTransaction(transactions[i]);\r
477\r
478 if (transaction && transaction.retryCount < me.maxRetries) {\r
479 transaction.retry();\r
480 }\r
481 else {\r
482 event = new Ext.direct.ExceptionEvent({\r
483 data: null,\r
484 transaction: transaction,\r
485 code: Ext.direct.Manager.exceptions.TRANSPORT,\r
486 message: 'Unable to connect to the server.',\r
487 xhr: response\r
488 });\r
489\r
490 me.fireEvent('data', me, event);\r
491\r
492 if (transaction && me.fireEvent('beforecallback', me, event, transaction) !== false) {\r
493 me.runCallback(transaction, event, false);\r
494 }\r
495 \r
496 Ext.direct.Manager.removeTransaction(transaction);\r
497 }\r
498 }\r
499 }\r
500 },\r
501 \r
502 /**\r
503 * Get transaction from XHR options\r
504 *\r
505 * @param {Object} options The options sent to the Ajax request\r
506 *\r
507 * @return {Ext.direct.Transaction} The transaction, null if not found\r
508 *\r
509 * @private\r
510 */\r
511 getTransaction: function(options) {\r
512 return options && options.tid ? Ext.direct.Manager.getTransaction(options.tid) : null;\r
513 },\r
514 \r
515 /**\r
516 * Gets the Ajax call info for a transaction\r
517 *\r
518 * @param {Ext.direct.Transaction} transaction The transaction\r
519 *\r
520 * @return {Object} The call params\r
521 *\r
522 * @private\r
523 */\r
524 getPayload: function(transaction) {\r
525 var result = {\r
526 action: transaction.action,\r
527 method: transaction.method,\r
528 data: transaction.data,\r
529 type: 'rpc',\r
530 tid: transaction.id\r
531 };\r
532 \r
533 if (transaction.metadata) {\r
534 result.metadata = transaction.metadata;\r
535 }\r
536 \r
537 return result;\r
538 },\r
539 \r
540 /**\r
541 * Sends a request to the server\r
542 *\r
543 * @param {Object/Array} transaction The transaction(s) to send\r
544 *\r
545 * @private\r
546 */\r
547 sendRequest: function(transaction) {\r
548 var me = this,\r
549 request, callData, params,\r
550 enableUrlEncode = me.enableUrlEncode,\r
551 payload, i, len;\r
552\r
553 request = {\r
554 url: me.url,\r
555 callback: me.onData,\r
556 scope: me,\r
557 transaction: transaction,\r
558 timeout: me.timeout\r
559 };\r
560\r
561 // Explicitly specified timeout for Ext Direct call overrides defaults\r
562 if (transaction.timeout) {\r
563 request.timeout = transaction.timeout;\r
564 }\r
565\r
566 if (Ext.isArray(transaction)) {\r
567 callData = [];\r
568\r
569 for (i = 0, len = transaction.length; i < len; ++i) {\r
570 payload = me.getPayload(transaction[i]);\r
571 callData.push(payload);\r
572 }\r
573 }\r
574 else {\r
575 callData = me.getPayload(transaction);\r
576 }\r
577\r
578 if (enableUrlEncode) {\r
579 params = {};\r
580 params[Ext.isString(enableUrlEncode) ? enableUrlEncode : 'data'] = Ext.encode(callData);\r
581 request.params = params;\r
582 }\r
583 else {\r
584 request.jsonData = callData;\r
585 }\r
586\r
587 Ext.Ajax.request(request);\r
588 },\r
589 \r
590 /**\r
591 * Add a new transaction to the queue\r
592 *\r
593 * @param {Ext.direct.Transaction} transaction The transaction\r
594 *\r
595 * @private\r
596 */\r
597 queueTransaction: function(transaction) {\r
598 var me = this,\r
599 callBuffer = me.callBuffer,\r
600 enableBuffer = me.enableBuffer;\r
601 \r
602 if (transaction.form) {\r
603 me.sendFormRequest(transaction);\r
604 return;\r
605 }\r
606\r
607 if (enableBuffer === false || transaction.disableBatching ||\r
608 typeof transaction.timeout !== 'undefined') {\r
609 me.sendRequest(transaction);\r
610 return;\r
611 }\r
612 \r
613 callBuffer.push(transaction);\r
614\r
615 if (enableBuffer && callBuffer.length < me.bufferLimit) {\r
616 if (!me.callTask) {\r
617 me.callTask = new Ext.util.DelayedTask(me.combineAndSend, me);\r
618 }\r
619\r
620 me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10);\r
621 }\r
622 else {\r
623 me.combineAndSend();\r
624 }\r
625 },\r
626 \r
627 /**\r
628 * Combine any buffered requests and send them off\r
629 *\r
630 * @private\r
631 */\r
632 combineAndSend : function() {\r
633 var me = this,\r
634 buffer = me.callBuffer,\r
635 len = buffer.length;\r
636 \r
637 if (len > 0) {\r
638 me.sendRequest(len === 1 ? buffer[0] : buffer);\r
639 me.callBuffer = [];\r
640 }\r
641 },\r
642 \r
643 /**\r
644 * Configure a transaction for a Direct request\r
645 *\r
646 * @param {String} action The action being executed\r
647 * @param {Object} method The method being executed\r
648 * @param {Array} args Method invocation arguments\r
649 * @param {Boolean} isForm True for a form submit\r
650 *\r
651 * @return {Object} Transaction object\r
652 *\r
653 * @private\r
654 */\r
655 configureTransaction: function(action, method, args, isForm) {\r
656 var data, cb, scope, options, params;\r
657 \r
658 data = method.getCallData(args);\r
659 \r
660 cb = data.callback;\r
661 scope = data.scope;\r
662 options = data.options;\r
663 \r
664 //<debug>\r
665 if (cb && !Ext.isFunction(cb)) {\r
666 Ext.raise("Callback argument is not a function " +\r
667 "for Ext Direct method " +\r
668 action + "." + method.name);\r
669 }\r
670 //</debug>\r
671 \r
672 // Callback might be unspecified for a notification\r
673 // that does not expect any return value\r
674 cb = cb && scope ? Ext.Function.bind(cb, scope) : cb;\r
675 \r
676 params = Ext.apply({}, {\r
677 provider: this,\r
678 args: args,\r
679 action: action,\r
680 method: method.name,\r
681 form: data.form,\r
682 data: data.data,\r
683 metadata: data.metadata,\r
684 callbackOptions: options,\r
685 callback: cb,\r
686 isForm: isForm,\r
687 disableBatching: method.disableBatching\r
688 });\r
689 \r
690 if (options && options.timeout != null) {\r
691 params.timeout = options.timeout;\r
692 }\r
693 \r
694 return new Ext.direct.Transaction(params);\r
695 },\r
696 \r
697 /**\r
698 * Configure a direct request\r
699 *\r
700 * @param {String} action The action being executed\r
701 * @param {Object} method The method being executed\r
702 *\r
703 * @private\r
704 */\r
705 configureRequest: function(action, method, args) {\r
706 var me = this,\r
707 transaction;\r
708 \r
709 transaction = me.configureTransaction(action, method, args);\r
710\r
711 if (me.fireEvent('beforecall', me, transaction, method) !== false) {\r
712 Ext.direct.Manager.addTransaction(transaction);\r
713 me.queueTransaction(transaction);\r
714 me.fireEvent('call', me, transaction, method);\r
715 }\r
716 },\r
717 \r
718 /**\r
719 * Configure a form submission request\r
720 *\r
721 * @param {String} action The action being executed\r
722 * @param {Object} method The method being executed\r
723 * @param {Array} args Method invocation arguments\r
724 *\r
725 * @private\r
726 */\r
727 configureFormRequest: function(action, method, args) {\r
728 var me = this,\r
729 transaction, form, isUpload, postParams;\r
730 \r
731 transaction = me.configureTransaction(action, method, args, true);\r
732 \r
733 if (me.fireEvent('beforecall', me, transaction, method) !== false) {\r
734 Ext.direct.Manager.addTransaction(transaction);\r
735 \r
736 form = transaction.form;\r
737 \r
738 isUpload = String(form.getAttribute("enctype")).toLowerCase() === 'multipart/form-data';\r
739 \r
740 postParams = {\r
741 extTID: transaction.id,\r
742 extAction: action,\r
743 extMethod: method.name,\r
744 extType: 'rpc',\r
745 extUpload: String(isUpload)\r
746 };\r
747 \r
748 if (transaction.metadata) {\r
749 postParams.extMetadata = Ext.JSON.encode(transaction.metadata);\r
750 }\r
751 \r
752 Ext.apply(transaction, {\r
753 form: form,\r
754 isUpload: isUpload,\r
755 params: postParams\r
756 });\r
757\r
758 me.sendFormRequest(transaction);\r
759 me.fireEvent('call', me, transaction, method);\r
760 }\r
761 },\r
762 \r
763 /**\r
764 * Sends a form request\r
765 *\r
766 * @param {Ext.direct.Transaction} transaction The transaction to send\r
767 *\r
768 * @private\r
769 */\r
770 sendFormRequest: function(transaction) {\r
771 var me = this;\r
772\r
773 Ext.Ajax.request({\r
774 url: me.url,\r
775 params: transaction.params,\r
776 callback: me.onData,\r
777 scope: me,\r
778 form: transaction.form,\r
779 isUpload: transaction.isUpload,\r
780 transaction: transaction\r
781 });\r
782 },\r
783 \r
784 inheritableStatics: {\r
785 /**\r
786 * @private\r
787 * @static\r
788 * @inheritable\r
789 */\r
790 checkConfig: function(config) {\r
791 // RemotingProvider needs service URI,\r
792 // type and array of Actions\r
793 return config && config.type === 'remoting' &&\r
794 config.url && Ext.isArray(config.actions);\r
795 }\r
796 }\r
797});\r