source: trunk/web/addons/job_monarch/lib/extjs-30/pkgs/direct-debug.js @ 647

Last change on this file since 647 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 38.8 KB
Line 
1/*!
2 * Ext JS Library 3.0.0
3 * Copyright(c) 2006-2009 Ext JS, LLC
4 * licensing@extjs.com
5 * http://www.extjs.com/license
6 */
7/**
8 * @class Ext.data.DirectProxy
9 * @extends Ext.data.DataProxy
10 */
11Ext.data.DirectProxy = function(config){
12    Ext.apply(this, config);
13    if(typeof this.paramOrder == 'string'){
14        this.paramOrder = this.paramOrder.split(/[\s,|]/);
15    }
16    Ext.data.DirectProxy.superclass.constructor.call(this, config);
17};
18
19Ext.extend(Ext.data.DirectProxy, Ext.data.DataProxy, {
20    /**
21     * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. A list of params to be executed
22     * server side.  Specify the params in the order in which they must be executed on the server-side
23     * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
24     * comma, or pipe. For example,
25     * any of the following would be acceptable:<pre><code>
26paramOrder: ['param1','param2','param3']
27paramOrder: 'param1 param2 param3'
28paramOrder: 'param1,param2,param3'
29paramOrder: 'param1|param2|param'
30     </code></pre>
31     */
32    paramOrder: undefined,
33
34    /**
35     * @cfg {Boolean} paramsAsHash
36     * Send parameters as a collection of named arguments (defaults to <tt>true</tt>). Providing a
37     * <tt>{@link #paramOrder}</tt> nullifies this configuration.
38     */
39    paramsAsHash: true,
40
41    /**
42     * @cfg {Function} directFn
43     * Function to call when executing a request.  directFn is a simple alternative to defining the api configuration-parameter
44     * for Store's which will not implement a full CRUD api.
45     */
46    directFn : undefined,
47
48    // protected
49    doRequest : function(action, rs, params, reader, callback, scope, options) {
50        var args = [];
51        var directFn = this.api[action] || this.directFn;
52
53        switch (action) {
54            case Ext.data.Api.actions.create:
55                args.push(params[reader.meta.root]);            // <-- create(Hash)
56                break;
57            case Ext.data.Api.actions.read:
58                if(this.paramOrder){
59                    for(var i = 0, len = this.paramOrder.length; i < len; i++){
60                        args.push(params[this.paramOrder[i]]);
61                    }
62                }else if(this.paramsAsHash){
63                    args.push(params);
64                }
65                break;
66            case Ext.data.Api.actions.update:
67                args.push(params[reader.meta.idProperty]);  // <-- save(Integer/Integer[], Hash/Hash[])
68                args.push(params[reader.meta.root]);
69                break;
70            case Ext.data.Api.actions.destroy:
71                args.push(params[reader.meta.root]);        // <-- destroy(Int/Int[])
72                break;
73        }
74
75        var trans = {
76            params : params || {},
77            callback : callback,
78            scope : scope,
79            arg : options,
80            reader: reader
81        };
82
83        args.push(this.createCallback(action, rs, trans), this);
84        directFn.apply(window, args);
85    },
86
87    // private
88    createCallback : function(action, rs, trans) {
89        return function(result, res) {
90            if (!res.status) {
91                // @deprecated fire loadexception
92                if (action === Ext.data.Api.actions.read) {
93                    this.fireEvent("loadexception", this, trans, res, null);
94                }
95                this.fireEvent('exception', this, 'remote', action, trans, res, null);
96                trans.callback.call(trans.scope, null, trans.arg, false);
97                return;
98            }
99            if (action === Ext.data.Api.actions.read) {
100                this.onRead(action, trans, result, res);
101            } else {
102                this.onWrite(action, trans, result, res, rs);
103            }
104        };
105    },
106    /**
107     * Callback for read actions
108     * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
109     * @param {Object} trans The request transaction object
110     * @param {Object} res The server response
111     * @private
112     */
113    onRead : function(action, trans, result, res) {
114        var records;
115        try {
116            records = trans.reader.readRecords(result);
117        }
118        catch (ex) {
119            // @deprecated: Fire old loadexception for backwards-compat.
120            this.fireEvent("loadexception", this, trans, res, ex);
121
122            this.fireEvent('exception', this, 'response', action, trans, res, ex);
123            trans.callback.call(trans.scope, null, trans.arg, false);
124            return;
125        }
126        this.fireEvent("load", this, res, trans.arg);
127        trans.callback.call(trans.scope, records, trans.arg, true);
128    },
129    /**
130     * Callback for write actions
131     * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
132     * @param {Object} trans The request transaction object
133     * @param {Object} res The server response
134     * @private
135     */
136    onWrite : function(action, trans, result, res, rs) {
137        this.fireEvent("write", this, action, result, res, rs, trans.arg);
138        trans.callback.call(trans.scope, result, res, true);
139    }
140});
141
142/**
143 * @class Ext.data.DirectStore
144 * @extends Ext.data.Store
145 * <p>Small helper class to create an {@link Ext.data.Store} configured with an
146 * {@link Ext.data.DirectProxy} and {@link Ext.data.JsonReader} to make interacting
147 * with an {@link Ext.Direct} Server-side {@link Ext.direct.Provider Provider} easier.
148 * To create a different proxy/reader combination create a basic {@link Ext.data.Store}
149 * configured as needed.</p>
150 *
151 * <p><b>*Note:</b> Although they are not listed, this class inherits all of the config options of:</p>
152 * <div><ul class="mdetail-params">
153 * <li><b>{@link Ext.data.Store Store}</b></li>
154 * <div class="sub-desc"><ul class="mdetail-params">
155 *
156 * </ul></div>
157 * <li><b>{@link Ext.data.JsonReader JsonReader}</b></li>
158 * <div class="sub-desc"><ul class="mdetail-params">
159 * <li><tt><b>{@link Ext.data.JsonReader#root root}</b></tt></li>
160 * <li><tt><b>{@link Ext.data.JsonReader#idProperty idProperty}</b></tt></li>
161 * <li><tt><b>{@link Ext.data.JsonReader#totalProperty totalProperty}</b></tt></li>
162 * </ul></div>
163 *
164 * <li><b>{@link Ext.data.DirectProxy DirectProxy}</b></li>
165 * <div class="sub-desc"><ul class="mdetail-params">
166 * <li><tt><b>{@link Ext.data.DirectProxy#directFn directFn}</b></tt></li>
167 * <li><tt><b>{@link Ext.data.DirectProxy#paramOrder paramOrder}</b></tt></li>
168 * <li><tt><b>{@link Ext.data.DirectProxy#paramsAsHash paramsAsHash}</b></tt></li>
169 * </ul></div>
170 * </ul></div>
171 *
172 * @xtype directstore
173 *
174 * @constructor
175 * @param {Object} config
176 */
177Ext.data.DirectStore = function(c){
178    // each transaction upon a singe record will generatie a distinct Direct transaction since Direct queues them into one Ajax request.
179    c.batchTransactions = false;
180
181    Ext.data.DirectStore.superclass.constructor.call(this, Ext.apply(c, {
182        proxy: (typeof(c.proxy) == 'undefined') ? new Ext.data.DirectProxy(Ext.copyTo({}, c, 'paramOrder,paramsAsHash,directFn,api')) : c.proxy,
183        reader: (typeof(c.reader) == 'undefined' && typeof(c.fields) == 'object') ? new Ext.data.JsonReader(Ext.copyTo({}, c, 'totalProperty,root,idProperty'), c.fields) : c.reader
184    }));
185};
186Ext.extend(Ext.data.DirectStore, Ext.data.Store, {});
187Ext.reg('directstore', Ext.data.DirectStore);
188/**
189 * @class Ext.Direct
190 * @extends Ext.util.Observable
191 * <p><b><u>Overview</u></b></p>
192 *
193 * <p>Ext.Direct aims to streamline communication between the client and server
194 * by providing a single interface that reduces the amount of common code
195 * typically required to validate data and handle returned data packets
196 * (reading data, error conditions, etc).</p>
197 * 
198 * <p>The Ext.direct namespace includes several classes for a closer integration
199 * with the server-side. The Ext.data namespace also includes classes for working
200 * with Ext.data.Stores which are backed by data from an Ext.Direct method.</p>
201 *
202 * <p><b><u>Specification</u></b></p>
203 *
204 * <p>For additional information consult the
205 * <a href="http://extjs.com/products/extjs/direct.php">Ext.Direct Specification</a>.</p>
206 *   
207 * <p><b><u>Providers</u></b></p>
208 *
209 * <p>Ext.Direct uses a provider architecture, where one or more providers are
210 * used to transport data to and from the server. There are several providers
211 * that exist in the core at the moment:</p><div class="mdetail-params"><ul>
212 *
213 * <li>{@link Ext.direct.JsonProvider JsonProvider} for simple JSON operations</li>
214 * <li>{@link Ext.direct.PollingProvider PollingProvider} for repeated requests</li>
215 * <li>{@link Ext.direct.RemotingProvider RemotingProvider} exposes server side
216 * on the client.</li>
217 * </ul></div>
218 *
219 * <p>A provider does not need to be invoked directly, providers are added via
220 * {@link Ext.Direct}.{@link Ext.Direct#add add}.</p>
221 *
222 * <p><b><u>Router</u></b></p>
223 *
224 * <p>Ext.Direct utilizes a "router" on the server to direct requests from the client
225 * to the appropriate server-side method. Because the Ext.Direct API is completely
226 * platform-agnostic, you could completely swap out a Java based server solution
227 * and replace it with one that uses C# without changing the client side JavaScript
228 * at all.</p>
229 *
230 * <p><b><u>Server side events</u></b></p>
231 *
232 * <p>Custom events from the server may be handled by the client by adding
233 * listeners, for example:</p>
234 * <pre><code>
235{"type":"event","name":"message","data":"Successfully polled at: 11:19:30 am"}
236
237// add a handler for a 'message' event sent by the server
238Ext.Direct.on('message', function(e){
239    out.append(String.format('&lt;p>&lt;i>{0}&lt;/i>&lt;/p>', e.data));
240            out.el.scrollTo('t', 100000, true);
241});
242 * </code></pre>
243 * @singleton
244 */
245Ext.Direct = Ext.extend(Ext.util.Observable, {
246    /**
247     * Each event type implements a getData() method. The default event types are:
248     * <div class="mdetail-params"><ul>
249     * <li><b><tt>event</tt></b> : Ext.Direct.Event</li>
250     * <li><b><tt>exception</tt></b> : Ext.Direct.ExceptionEvent</li>
251     * <li><b><tt>rpc</tt></b> : Ext.Direct.RemotingEvent</li>
252     * </ul></div>
253     * @property eventTypes
254     * @type Object
255     */
256
257    /**
258     * Four types of possible exceptions which can occur:
259     * <div class="mdetail-params"><ul>
260     * <li><b><tt>Ext.Direct.exceptions.TRANSPORT</tt></b> : 'xhr'</li>
261     * <li><b><tt>Ext.Direct.exceptions.PARSE</tt></b> : 'parse'</li>
262     * <li><b><tt>Ext.Direct.exceptions.LOGIN</tt></b> : 'login'</li>
263     * <li><b><tt>Ext.Direct.exceptions.SERVER</tt></b> : 'exception'</li>
264     * </ul></div>
265     * @property exceptions
266     * @type Object
267     */
268    exceptions: {
269        TRANSPORT: 'xhr',
270        PARSE: 'parse',
271        LOGIN: 'login',
272        SERVER: 'exception'
273    },
274   
275    // private
276    constructor: function(){
277        this.addEvents(
278            /**
279             * @event event
280             * Fires after an event.
281             * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
282             * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
283             */
284            'event',
285            /**
286             * @event exception
287             * Fires after an event exception.
288             * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
289             */
290            'exception'
291        );
292        this.transactions = {};
293        this.providers = {};
294    },
295
296    /**
297     * Adds an Ext.Direct Provider and creates the proxy or stub methods to execute server-side methods.
298     * If the provider is not already connected, it will auto-connect.
299     * <pre><code>
300var pollProv = new Ext.direct.PollingProvider({
301    url: 'php/poll2.php'
302});
303
304Ext.Direct.addProvider(
305    {
306        "type":"remoting",       // create a {@link Ext.direct.RemotingProvider}
307        "url":"php\/router.php", // url to connect to the Ext.Direct server-side router.
308        "actions":{              // each property within the actions object represents a Class
309            "TestAction":[       // array of methods within each server side Class   
310            {
311                "name":"doEcho", // name of method
312                "len":1
313            },{
314                "name":"multiply",
315                "len":1
316            },{
317                "name":"doForm",
318                "formHandler":true, // handle form on server with Ext.Direct.Transaction
319                "len":1
320            }]
321        },
322        "namespace":"myApplication",// namespace to create the Remoting Provider in
323    },{
324        type: 'polling', // create a {@link Ext.direct.PollingProvider}
325        url:  'php/poll.php'
326    },
327    pollProv // reference to previously created instance
328);
329     * </code></pre>
330     * @param {Object/Array} provider Accepts either an Array of Provider descriptions (an instance
331     * or config object for a Provider) or any number of Provider descriptions as arguments.  Each
332     * Provider description instructs Ext.Direct how to create client-side stub methods.
333     */
334    addProvider : function(provider){       
335        var a = arguments;
336        if(a.length > 1){
337            for(var i = 0, len = a.length; i < len; i++){
338                this.addProvider(a[i]);
339            }
340            return;
341        }
342       
343        // if provider has not already been instantiated
344        if(!provider.events){
345            provider = new Ext.Direct.PROVIDERS[provider.type](provider);
346        }
347        provider.id = provider.id || Ext.id();
348        this.providers[provider.id] = provider;
349
350        provider.on('data', this.onProviderData, this);
351        provider.on('exception', this.onProviderException, this);
352
353
354        if(!provider.isConnected()){
355            provider.connect();
356        }
357
358        return provider;
359    },
360
361    /**
362     * Retrieve a {@link Ext.direct.Provider provider} by the
363     * <b><tt>{@link Ext.direct.Provider#id id}</tt></b> specified when the provider is
364     * {@link #addProvider added}.
365     * @param {String} id Unique identifier assigned to the provider when calling {@link #addProvider}
366     */
367    getProvider : function(id){
368        return this.providers[id];
369    },
370
371    removeProvider : function(id){
372        var provider = id.id ? id : this.providers[id.id];
373        provider.un('data', this.onProviderData, this);
374        provider.un('exception', this.onProviderException, this);
375        delete this.providers[provider.id];
376        return provider;
377    },
378
379    addTransaction: function(t){
380        this.transactions[t.tid] = t;
381        return t;
382    },
383
384    removeTransaction: function(t){
385        delete this.transactions[t.tid || t];
386        return t;
387    },
388
389    getTransaction: function(tid){
390        return this.transactions[tid.tid || tid];
391    },
392
393    onProviderData : function(provider, e){
394        if(Ext.isArray(e)){
395            for(var i = 0, len = e.length; i < len; i++){
396                this.onProviderData(provider, e[i]);
397            }
398            return;
399        }
400        if(e.name && e.name != 'event' && e.name != 'exception'){
401            this.fireEvent(e.name, e);
402        }else if(e.type == 'exception'){
403            this.fireEvent('exception', e);
404        }
405        this.fireEvent('event', e, provider);
406    },
407
408    createEvent : function(response, extraProps){
409        return new Ext.Direct.eventTypes[response.type](Ext.apply(response, extraProps));
410    }
411});
412// overwrite impl. with static instance
413Ext.Direct = new Ext.Direct();
414
415Ext.Direct.TID = 1;
416Ext.Direct.PROVIDERS = {};/**
417 * @class Ext.Direct.Transaction
418 * @extends Object
419 * <p>Supporting Class for Ext.Direct (not intended to be used directly).</p>
420 * @constructor
421 * @param {Object} config
422 */
423Ext.Direct.Transaction = function(config){
424    Ext.apply(this, config);
425    this.tid = ++Ext.Direct.TID;
426    this.retryCount = 0;
427};
428Ext.Direct.Transaction.prototype = {
429    send: function(){
430        this.provider.queueTransaction(this);
431    },
432
433    retry: function(){
434        this.retryCount++;
435        this.send();
436    },
437
438    getProvider: function(){
439        return this.provider;
440    }
441};Ext.Direct.Event = function(config){
442    Ext.apply(this, config);
443}
444Ext.Direct.Event.prototype = {
445    status: true,
446    getData: function(){
447        return this.data;
448    }
449};
450
451Ext.Direct.RemotingEvent = Ext.extend(Ext.Direct.Event, {
452    type: 'rpc',
453    getTransaction: function(){
454        return this.transaction || Ext.Direct.getTransaction(this.tid);
455    }
456});
457
458Ext.Direct.ExceptionEvent = Ext.extend(Ext.Direct.RemotingEvent, {
459    status: false,
460    type: 'exception'
461});
462
463Ext.Direct.eventTypes = {
464    'rpc':  Ext.Direct.RemotingEvent,
465    'event':  Ext.Direct.Event,
466    'exception':  Ext.Direct.ExceptionEvent
467};
468
469/**
470 * @class Ext.direct.Provider
471 * @extends Ext.util.Observable
472 * <p>Ext.direct.Provider is an abstract class meant to be extended.</p>
473 *
474 * <p>For example ExtJs implements the following subclasses:</p>
475 * <pre><code>
476Provider
477|
478+---{@link Ext.direct.JsonProvider JsonProvider}
479    |
480    +---{@link Ext.direct.PollingProvider PollingProvider}   
481    |
482    +---{@link Ext.direct.RemotingProvider RemotingProvider}   
483 * </code></pre>
484 * @abstract
485 */
486Ext.direct.Provider = Ext.extend(Ext.util.Observable, {   
487    /**
488     * @cfg {String} id
489     * The unique id of the provider (defaults to an {@link Ext#id auto-assigned id}).
490     * You should assign an id if you need to be able to access the provider later and you do
491     * not have an object reference available, for example:
492     * <pre><code>
493Ext.Direct.addProvider(
494    {
495        type: 'polling',
496        url:  'php/poll.php',
497        id:   'poll-provider'
498    }
499);
500     
501var p = {@link Ext.Direct Ext.Direct}.{@link Ext.Direct#getProvider getProvider}('poll-provider');
502p.disconnect();
503     * </code></pre>
504     */
505       
506    /**
507     * @cfg {Number} priority
508     * Priority of the request. Lower is higher priority, <tt>0</tt> means "duplex" (always on).
509     * All Providers default to <tt>1</tt> except for PollingProvider which defaults to <tt>3</tt>.
510     */   
511    priority: 1,
512
513    /**
514     * @cfg {String} type
515     * <b>Required</b>, <tt>undefined</tt> by default.  The <tt>type</tt> of provider specified
516     * to {@link Ext.Direct Ext.Direct}.{@link Ext.Direct#addProvider addProvider} to create a
517     * new Provider. Acceptable values by default are:<div class="mdetail-params"><ul>
518     * <li><b><tt>polling</tt></b> : {@link Ext.direct.PollingProvider PollingProvider}</li>
519     * <li><b><tt>remoting</tt></b> : {@link Ext.direct.RemotingProvider RemotingProvider}</li>
520     * </ul></div>
521     */   
522 
523    // private
524    constructor : function(config){
525        Ext.apply(this, config);
526        this.addEvents(
527            /**
528             * @event connect
529             * Fires when the Provider connects to the server-side
530             * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
531             */           
532            'connect',
533            /**
534             * @event disconnect
535             * Fires when the Provider disconnects from the server-side
536             * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
537             */           
538            'disconnect',
539            /**
540             * @event data
541             * Fires when the Provider receives data from the server-side
542             * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
543             * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
544             */           
545            'data',
546            /**
547             * @event exception
548             * Fires when the Provider receives an exception from the server-side
549             */                       
550            'exception'
551        );
552        Ext.direct.Provider.superclass.constructor.call(this, config);
553    },
554
555    /**
556     * Returns whether or not the server-side is currently connected.
557     * Abstract method for subclasses to implement.
558     */
559    isConnected: function(){
560        return false;
561    },
562
563    /**
564     * Abstract methods for subclasses to implement.
565     */
566    connect: Ext.emptyFn,
567   
568    /**
569     * Abstract methods for subclasses to implement.
570     */
571    disconnect: Ext.emptyFn
572});
573/**
574 * @class Ext.direct.JsonProvider
575 * @extends Ext.direct.Provider
576 */
577Ext.direct.JsonProvider = Ext.extend(Ext.direct.Provider, {
578    parseResponse: function(xhr){
579        if(!Ext.isEmpty(xhr.responseText)){
580            if(typeof xhr.responseText == 'object'){
581                return xhr.responseText;
582            }
583            return Ext.decode(xhr.responseText);
584        }
585        return null;
586    },
587
588    getEvents: function(xhr){
589        var data = null;
590        try{
591            data = this.parseResponse(xhr);
592        }catch(e){
593            var event = new Ext.Direct.ExceptionEvent({
594                data: e,
595                xhr: xhr,
596                code: Ext.Direct.exceptions.PARSE,
597                message: 'Error parsing json response: \n\n ' + data
598            })
599            return [event];
600        }
601        var events = [];
602        if(Ext.isArray(data)){
603            for(var i = 0, len = data.length; i < len; i++){
604                events.push(Ext.Direct.createEvent(data[i]));
605            }
606        }else{
607            events.push(Ext.Direct.createEvent(data));
608        }
609        return events;
610    }
611});/**
612 * @class Ext.direct.PollingProvider
613 * @extends Ext.direct.JsonProvider
614 *
615 * <p>Provides for repetitive polling of the server at distinct {@link #interval intervals}.
616 * The initial request for data originates from the client, and then is responded to by the
617 * server.</p>
618 *
619 * <p>All configurations for the PollingProvider should be generated by the server-side
620 * API portion of the Ext.Direct stack.</p>
621 *
622 * <p>An instance of PollingProvider may be created directly via the new keyword or by simply
623 * specifying <tt>type = 'polling'</tt>.  For example:</p>
624 * <pre><code>
625var pollA = new Ext.direct.PollingProvider({
626    type:'polling',
627    url: 'php/pollA.php',
628});
629Ext.Direct.addProvider(pollA);
630pollA.disconnect();
631
632Ext.Direct.addProvider(
633    {
634        type:'polling',
635        url: 'php/pollB.php',
636        id: 'pollB-provider'
637    }
638);
639var pollB = Ext.Direct.getProvider('pollB-provider');
640 * </code></pre>
641 */
642Ext.direct.PollingProvider = Ext.extend(Ext.direct.JsonProvider, {
643    /**
644     * @cfg {Number} priority
645     * Priority of the request (defaults to <tt>3</tt>). See {@link Ext.direct.Provider#priority}.
646     */
647    // override default priority
648    priority: 3,
649   
650    /**
651     * @cfg {Number} interval
652     * How often to poll the server-side in milliseconds (defaults to <tt>3000</tt> - every
653     * 3 seconds).
654     */
655    interval: 3000,
656
657    /**
658     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
659     * on every polling request
660     */
661   
662    /**
663     * @cfg {String/Function} url
664     * The url which the PollingProvider should contact with each request. This can also be
665     * an imported Ext.Direct method which will accept the baseParams as its only argument.
666     */
667
668    // private
669    constructor : function(config){
670        Ext.direct.PollingProvider.superclass.constructor.call(this, config);
671        this.addEvents(
672            /**
673             * @event beforepoll
674             * Fired immediately before a poll takes place, an event handler can return false
675             * in order to cancel the poll.
676             * @param {Ext.direct.PollingProvider}
677             */
678            'beforepoll',           
679            /**
680             * @event poll
681             * This event has not yet been implemented.
682             * @param {Ext.direct.PollingProvider}
683             */
684            'poll'
685        );
686    },
687
688    // inherited
689    isConnected: function(){
690        return !!this.pollTask;
691    },
692
693    /**
694     * Connect to the server-side and begin the polling process. To handle each
695     * response subscribe to the data event.
696     */
697    connect: function(){
698        if(this.url && !this.pollTask){
699            this.pollTask = Ext.TaskMgr.start({
700                run: function(){
701                    if(this.fireEvent('beforepoll', this) !== false){
702                        if(typeof this.url == 'function'){
703                            this.url(this.baseParams);
704                        }else{
705                            Ext.Ajax.request({
706                                url: this.url,
707                                callback: this.onData,
708                                scope: this,
709                                params: this.baseParams
710                            });
711                        }
712                    }
713                },
714                interval: this.interval,
715                scope: this
716            });
717            this.fireEvent('connect', this);
718        }else if(!this.url){
719            throw 'Error initializing PollingProvider, no url configured.';
720        }
721    },
722
723    /**
724     * Disconnect from the server-side and stop the polling process. The disconnect
725     * event will be fired on a successful disconnect.
726     */
727    disconnect: function(){
728        if(this.pollTask){
729            Ext.TaskMgr.stop(this.pollTask);
730            delete this.pollTask;
731            this.fireEvent('disconnect', this);
732        }
733    },
734
735    // private
736    onData: function(opt, success, xhr){
737        if(success){
738            var events = this.getEvents(xhr);
739            for(var i = 0, len = events.length; i < len; i++){
740                var e = events[i];
741                this.fireEvent('data', this, e);
742            }
743        }else{
744            var e = new Ext.Direct.ExceptionEvent({
745                data: e,
746                code: Ext.Direct.exceptions.TRANSPORT,
747                message: 'Unable to connect to the server.',
748                xhr: xhr
749            });
750            this.fireEvent('data', this, e);
751        }
752    }
753});
754
755Ext.Direct.PROVIDERS['polling'] = Ext.direct.PollingProvider;/**
756 * @class Ext.direct.RemotingProvider
757 * @extends Ext.direct.JsonProvider
758 *
759 * <p>The {@link Ext.direct.RemotingProvider RemotingProvider} exposes access to
760 * server side methods on the client (a remote procedure call (RPC) type of
761 * connection where the client can initiate a procedure on the server).</p>
762 *
763 * <p>This allows for code to be organized in a fashion that is maintainable,
764 * while providing a clear path between client and server, something that is
765 * not always apparent when using URLs.</p>
766 *
767 * <p>To accomplish this the server-side needs to describe what classes and methods
768 * are available on the client-side. This configuration will typically be
769 * outputted by the server-side Ext.Direct stack when the API description is built.</p>
770 */
771Ext.direct.RemotingProvider = Ext.extend(Ext.direct.JsonProvider, {       
772    /**
773     * @cfg {Object} actions
774     * Object literal defining the server side actions and methods. For example, if
775     * the Provider is configured with:
776     * <pre><code>
777"actions":{ // each property within the 'actions' object represents a server side Class
778    "TestAction":[ // array of methods within each server side Class to be   
779    {              // stubbed out on client
780        "name":"doEcho",
781        "len":1           
782    },{
783        "name":"multiply",// name of method
784        "len":2           // The number of parameters that will be used to create an
785                          // array of data to send to the server side function.
786                          // Ensure the server sends back a Number, not a String.
787    },{
788        "name":"doForm",
789        "formHandler":true, // direct the client to use specialized form handling method
790        "len":1
791    }]
792}
793     * </code></pre>
794     * <p>Note that a Store is not required, a server method can be called at any time.
795     * In the following example a <b>client side</b> handler is used to call the
796     * server side method "multiply" in the server-side "TestAction" Class:</p>
797     * <pre><code>
798TestAction.multiply(
799    2, 4, // pass two arguments to server, so specify len=2
800    // callback function after the server is called
801    // result: the result returned by the server
802    //      e: Ext.Direct.RemotingEvent object
803    function(result, e){
804        var t = e.getTransaction();
805        var action = t.action; // server side Class called
806        var method = t.method; // server side method called
807        if(e.status){
808            var answer = Ext.encode(result); // 8
809   
810        }else{
811            var msg = e.message; // failure message
812        }
813    }
814);
815     * </code></pre>
816     * In the example above, the server side "multiply" function will be passed two
817     * arguments (2 and 4).  The "multiply" method should return the value 8 which will be
818     * available as the <tt>result</tt> in the example above.
819     */
820   
821    /**
822     * @cfg {String/Object} namespace
823     * Namespace for the Remoting Provider (defaults to the browser global scope of <i>window</i>).
824     * Explicitly specify the namespace Object, or specify a String to have a
825     * {@link Ext#namespace namespace created} implicitly.
826     */
827   
828    /**
829     * @cfg {String} url
830     * <b>Required<b>. The url to connect to the {@link Ext.Direct} server-side router.
831     */
832   
833    /**
834     * @cfg {String} enableUrlEncode
835     * Specify which param will hold the arguments for the method.
836     * Defaults to <tt>'data'</tt>.
837     */
838   
839    /**
840     * @cfg {Number/Boolean} enableBuffer
841     * <p><tt>true</tt> or <tt>false</tt> to enable or disable combining of method
842     * calls. If a number is specified this is the amount of time in milliseconds
843     * to wait before sending a batched request (defaults to <tt>10</tt>).</p>
844     * <br><p>Calls which are received within the specified timeframe will be
845     * concatenated together and sent in a single request, optimizing the
846     * application by reducing the amount of round trips that have to be made
847     * to the server.</p>
848     */
849    enableBuffer: 10,
850   
851    /**
852     * @cfg {Number} maxRetries
853     * Number of times to re-attempt delivery on failure of a call.
854     */
855    maxRetries: 1,
856
857    constructor : function(config){
858        Ext.direct.RemotingProvider.superclass.constructor.call(this, config);
859        this.addEvents(
860            /**
861             * @event beforecall
862             * Fires immediately before the client-side sends off the RPC call.
863             * By returning false from an event handler you can prevent the call from
864             * executing.
865             * @param {Ext.direct.RemotingProvider} provider
866             * @param {Ext.Direct.Transaction} transaction
867             */           
868            'beforecall',
869            /**
870             * @event call
871             * Fires immediately after the request to the server-side is sent. This does
872             * NOT fire after the response has come back from the call.
873             * @param {Ext.direct.RemotingProvider} provider
874             * @param {Ext.Direct.Transaction} transaction
875             */           
876            'call'
877        );
878        this.namespace = (typeof this.namespace === 'string') ? Ext.ns(this.namespace) : this.namespace || window;
879        this.transactions = {};
880        this.callBuffer = [];
881    },
882
883    // private
884    initAPI : function(){
885        var o = this.actions;
886        for(var c in o){
887            var cls = this.namespace[c] || (this.namespace[c] = {});
888            var ms = o[c];
889            for(var i = 0, len = ms.length; i < len; i++){
890                var m = ms[i];
891                cls[m.name] = this.createMethod(c, m);
892            }
893        }
894    },
895
896    // inherited
897    isConnected: function(){
898        return !!this.connected;
899    },
900
901    connect: function(){
902        if(this.url){
903            this.initAPI();
904            this.connected = true;
905            this.fireEvent('connect', this);
906        }else if(!this.url){
907            throw 'Error initializing RemotingProvider, no url configured.';
908        }
909    },
910
911    disconnect: function(){
912        if(this.connected){
913            this.connected = false;
914            this.fireEvent('disconnect', this);
915        }
916    },
917
918    onData: function(opt, success, xhr){
919        if(success){
920            var events = this.getEvents(xhr);
921            for(var i = 0, len = events.length; i < len; i++){
922                var e = events[i];
923                var t = this.getTransaction(e);
924                this.fireEvent('data', this, e);
925                if(t){
926                    this.doCallback(t, e, true);
927                    Ext.Direct.removeTransaction(t);
928                }
929            }
930        }else{
931            var ts = [].concat(opt.ts);
932            for(var i = 0, len = ts.length; i < len; i++){
933                var t = this.getTransaction(ts[i]);
934                if(t && t.retryCount < this.maxRetries){
935                    t.retry();
936                }else{
937                    var e = new Ext.Direct.ExceptionEvent({
938                        data: e,
939                        transaction: t,
940                        code: Ext.Direct.exceptions.TRANSPORT,
941                        message: 'Unable to connect to the server.',
942                        xhr: xhr
943                    });
944                    this.fireEvent('data', this, e);
945                    if(t){
946                        this.doCallback(t, e, false);
947                        Ext.Direct.removeTransaction(t);
948                    }
949                }
950            }
951        }
952    },
953
954    getCallData: function(t){
955        return {
956            action: t.action,
957            method: t.method,
958            data: t.data,
959            type: 'rpc',
960            tid: t.tid
961        };
962    },
963
964    doSend : function(data){
965        var o = {
966            url: this.url,
967            callback: this.onData,
968            scope: this,
969            ts: data
970        };
971
972        // send only needed data
973        var callData;
974        if(Ext.isArray(data)){
975            callData = [];
976            for(var i = 0, len = data.length; i < len; i++){
977                callData.push(this.getCallData(data[i]));
978            }
979        }else{
980            callData = this.getCallData(data);
981        }
982
983        if(this.enableUrlEncode){
984            var params = {};
985            params[typeof this.enableUrlEncode == 'string' ? this.enableUrlEncode : 'data'] = Ext.encode(callData);
986            o.params = params;
987        }else{
988            o.jsonData = callData;
989        }
990        Ext.Ajax.request(o);
991    },
992
993    combineAndSend : function(){
994        var len = this.callBuffer.length;
995        if(len > 0){
996            this.doSend(len == 1 ? this.callBuffer[0] : this.callBuffer);
997            this.callBuffer = [];
998        }
999    },
1000
1001    queueTransaction: function(t){
1002        if(t.form){
1003            this.processForm(t);
1004            return;
1005        }
1006        this.callBuffer.push(t);
1007        if(this.enableBuffer){
1008            if(!this.callTask){
1009                this.callTask = new Ext.util.DelayedTask(this.combineAndSend, this);
1010            }
1011            this.callTask.delay(typeof this.enableBuffer == 'number' ? this.enableBuffer : 10);
1012        }else{
1013            this.combineAndSend();
1014        }
1015    },
1016
1017    doCall : function(c, m, args){
1018        var data = null, hs = args[m.len], scope = args[m.len+1];
1019
1020        if(m.len !== 0){
1021            data = args.slice(0, m.len);
1022        }
1023
1024        var t = new Ext.Direct.Transaction({
1025            provider: this,
1026            args: args,
1027            action: c,
1028            method: m.name,
1029            data: data,
1030            cb: scope && Ext.isFunction(hs) ? hs.createDelegate(scope) : hs
1031        });
1032
1033        if(this.fireEvent('beforecall', this, t) !== false){
1034            Ext.Direct.addTransaction(t);
1035            this.queueTransaction(t);
1036            this.fireEvent('call', this, t);
1037        }
1038    },
1039
1040    doForm : function(c, m, form, callback, scope){
1041        var t = new Ext.Direct.Transaction({
1042            provider: this,
1043            action: c,
1044            method: m.name,
1045            args:[form, callback, scope],
1046            cb: scope && Ext.isFunction(callback) ? callback.createDelegate(scope) : callback,
1047            isForm: true
1048        });
1049
1050        if(this.fireEvent('beforecall', this, t) !== false){
1051            Ext.Direct.addTransaction(t);
1052            var isUpload = String(form.getAttribute("enctype")).toLowerCase() == 'multipart/form-data',
1053                params = {
1054                    extTID: t.tid,
1055                    extAction: c,
1056                    extMethod: m.name,
1057                    extType: 'rpc',
1058                    extUpload: String(isUpload)
1059                };
1060           
1061            // change made from typeof callback check to callback.params
1062            // to support addl param passing in DirectSubmit EAC 6/2
1063            Ext.apply(t, {
1064                form: Ext.getDom(form),
1065                isUpload: isUpload,
1066                params: callback && Ext.isObject(callback.params) ? Ext.apply(params, callback.params) : params
1067            });
1068            this.fireEvent('call', this, t);
1069            this.processForm(t);
1070        }
1071    },
1072   
1073    processForm: function(t){
1074        Ext.Ajax.request({
1075            url: this.url,
1076            params: t.params,
1077            callback: this.onData,
1078            scope: this,
1079            form: t.form,
1080            isUpload: t.isUpload,
1081            ts: t
1082        });
1083    },
1084
1085    createMethod : function(c, m){
1086        var f;
1087        if(!m.formHandler){
1088            f = function(){
1089                this.doCall(c, m, Array.prototype.slice.call(arguments, 0));
1090            }.createDelegate(this);
1091        }else{
1092            f = function(form, callback, scope){
1093                this.doForm(c, m, form, callback, scope);
1094            }.createDelegate(this);
1095        }
1096        f.directCfg = {
1097            action: c,
1098            method: m
1099        };
1100        return f;
1101    },
1102
1103    getTransaction: function(opt){
1104        return opt && opt.tid ? Ext.Direct.getTransaction(opt.tid) : null;
1105    },
1106
1107    doCallback: function(t, e){
1108        var fn = e.status ? 'success' : 'failure';
1109        if(t && t.cb){
1110            var hs = t.cb;
1111            var result = e.result || e.data;
1112            if(Ext.isFunction(hs)){
1113                hs(result, e);
1114            } else{
1115                Ext.callback(hs[fn], hs.scope, [result, e]);
1116                Ext.callback(hs.callback, hs.scope, [result, e]);
1117            }
1118        }
1119    }
1120});
1121Ext.Direct.PROVIDERS['remoting'] = Ext.direct.RemotingProvider;
Note: See TracBrowser for help on using the repository browser.